xref: /original-bsd/sys/ufs/lfs/lfs_inode.c (revision 9e0ce84d)
1 /*
2  * Copyright (c) 1986, 1989, 1991 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)lfs_inode.c	7.50 (Berkeley) 12/19/91
8  */
9 
10 #include <sys/param.h>
11 #include <sys/systm.h>
12 #include <sys/mount.h>
13 #include <sys/proc.h>
14 #include <sys/file.h>
15 #include <sys/buf.h>
16 #include <sys/vnode.h>
17 #include <sys/kernel.h>
18 #include <sys/malloc.h>
19 
20 #include <ufs/ufs/quota.h>
21 #include <ufs/ufs/inode.h>
22 #include <ufs/ufs/ufsmount.h>
23 #include <ufs/ufs/ufs_extern.h>
24 
25 #include <ufs/lfs/lfs.h>
26 #include <ufs/lfs/lfs_extern.h>
27 
28 int
29 lfs_init()
30 {
31 #ifdef VERBOSE
32 	printf("lfs_init\n");
33 #endif
34 	return (ufs_init());
35 }
36 
37 /*
38  * Look up an LFS dinode number to find its incore vnode.  If not already
39  * in core, read it in from the specified device.  Return the inode locked.
40  * Detection and handling of mount points must be done by the calling routine.
41  */
42 int
43 lfs_vget(mntp, ino, vpp)
44 	struct mount *mntp;
45 	ino_t ino;
46 	struct vnode **vpp;
47 {
48 	register struct lfs *fs;
49 	register struct inode *ip;
50 	struct buf *bp;
51 	struct vnode *vp;
52 	struct ufsmount *ump;
53 	dev_t dev;
54 	int error;
55 
56 #ifdef VERBOSE
57 	printf("lfs_vget\n");
58 #endif
59 	ump = VFSTOUFS(mntp);
60 	dev = ump->um_dev;
61 	if ((*vpp = ufs_ihashget(dev, ino)) != NULL)
62 		return (0);
63 
64 	/* Allocate new vnode/inode. */
65 	if (error = lfs_vcreate(mntp, ino, &vp)) {
66 		*vpp = NULL;
67 		return (error);
68 	}
69 	/*
70 	 * Put it onto its hash chain and lock it so that other requests for
71 	 * this inode will block if they arrive while we are sleeping waiting
72 	 * for old data structures to be purged or for the contents of the
73 	 * disk portion of this inode to be read.
74 	 */
75 	ip = VTOI(vp);
76 	ufs_ihashins(ip);
77 
78 	/* Read in the disk contents for the inode, copy into the inode. */
79 	ip->i_lfs = fs = ump->um_lfs;
80 	if (error = bread(ump->um_devvp, lfs_itod(fs, ino),
81 	    (int)fs->lfs_bsize, NOCRED, &bp)) {
82 		/*
83 		 * The inode does not contain anything useful, so it
84 		 * would be misleading to leave it on its hash chain.
85 		 * Iput() will return it to the free list.
86 		 */
87 		remque(ip);
88 		ip->i_forw = ip;
89 		ip->i_back = ip;
90 
91 		/* Unlock and discard unneeded inode. */
92 		ufs_iput(ip);
93 		brelse(bp);
94 		*vpp = NULL;
95 		return (error);
96 	}
97 	ip->i_din = *lfs_ifind(fs, ino, bp->b_un.b_dino);
98 	brelse(bp);
99 
100 	/*
101 	 * Initialize the vnode from the inode, check for aliases.  In all
102 	 * cases re-init ip, the underlying vnode/inode may have changed.
103 	 */
104 	if (error = ufs_vinit(mntp, &lfs_specops, LFS_FIFOOPS, &vp)) {
105 		ufs_iput(ip);
106 		*vpp = NULL;
107 		return (error);
108 	}
109 	/*
110 	 * Finish inode initialization now that aliasing has been resolved.
111 	 */
112 	ip->i_devvp = ump->um_devvp;
113 	VREF(ip->i_devvp);
114 	*vpp = vp;
115 	return (0);
116 }
117 
118 int
119 lfs_update(vp, ta, tm, waitfor)
120 	register struct vnode *vp;
121 	struct timeval *ta, *tm;
122         int waitfor;
123 {
124 	struct inode *ip;
125 
126 #ifdef VERBOSE
127 	printf("lfs_update\n");
128 #endif
129 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
130 		return (0);
131 	ip = VTOI(vp);
132 	if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) == 0)
133 		return (0);
134 	if (ip->i_flag&IACC)
135 		ip->i_atime = ta->tv_sec;
136 	if (ip->i_flag&IUPD) {
137 		ip->i_mtime = tm->tv_sec;
138 		INCRQUAD((ip)->i_modrev);
139 	}
140 	if (ip->i_flag&ICHG)
141 		ip->i_ctime = time.tv_sec;
142 	ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD);
143 
144 	/*
145 	 * XXX
146 	 * I'm not real sure what to do here; once we have fsync and partial
147 	 * segments working in the LFS context, this must be fixed to be
148 	 * correct.  The contents of the inode have to be pushed back to
149 	 * stable storage; note that the ifile contains the access time of
150 	 * the inode and must be updated as well.
151 	 */
152 	return (0);
153 }
154 
155 /*
156  * Truncate the inode ip to at most length size.
157  *
158  * NB: triple indirect blocks are untested.
159  */
160 /* ARGSUSED */
161 int
162 lfs_truncate(ovp, length, flags)
163 	struct vnode *ovp;
164 	u_long length;
165 	int flags;
166 {
167 	register struct lfs *fs;
168 	register struct inode *oip;
169 	struct buf *bp;
170 	daddr_t lbn;
171 	int error, offset, size;
172 
173 #ifdef VERBOSE
174 	printf("lfs_truncate\n");
175 #endif
176 	vnode_pager_setsize(ovp, length);
177 	oip = VTOI(ovp);
178 
179 	/* If length is larger than the file, just update the times. */
180 	if (oip->i_size <= length) {
181 		oip->i_flag |= ICHG|IUPD;
182 		ITIMES(oip, &time, &time);
183 		return (0);
184 	}
185 
186 	/*
187 	 * Update the size of the file. If the file is not being truncated to
188 	 * a block boundry, the contents of the partial block following the end
189 	 * of the file must be zero'ed in case it ever become accessable again
190 	 * because of subsequent file growth.
191 	 */
192 	fs = oip->i_lfs;
193 	offset = blkoff(fs, length);
194 	if (offset == 0)
195 		oip->i_size = length;
196 	else {
197 		lbn = lblkno(fs, length);
198 #ifdef QUOTA
199 		if (error = getinoquota(oip))
200 			return (error);
201 #endif
202 		if (error = bread(ovp, lbn, fs->lfs_bsize, NOCRED, &bp))
203 			return (error);
204 		oip->i_size = length;
205 		size = blksize(fs);
206 		(void)vnode_pager_uncache(ovp);
207 		bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset));
208 		allocbuf(bp, size);
209 		lfs_bwrite(bp);
210 	}
211 	/* XXX: BZERO INODE BLOCK POINTERS HERE, FOR CONSISTENCY. */
212 	(void)vinvalbuf(ovp, length > 0);
213 	return (0);
214 }
215