xref: /original-bsd/sys/ufs/lfs/lfs_inode.c (revision e59fb703)
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.51 (Berkeley) 12/30/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.
150 	 */
151 	return (0);
152 }
153 
154 /*
155  * Truncate the inode ip to at most length size.
156  *
157  * NB: triple indirect blocks are untested.
158  */
159 /* ARGSUSED */
160 int
161 lfs_truncate(ovp, length, flags)
162 	struct vnode *ovp;
163 	u_long length;
164 	int flags;
165 {
166 	register struct lfs *fs;
167 	register struct inode *oip;
168 	struct buf *bp;
169 	daddr_t lbn;
170 	int error, offset, size;
171 
172 #ifdef VERBOSE
173 	printf("lfs_truncate\n");
174 #endif
175 	vnode_pager_setsize(ovp, length);
176 	oip = VTOI(ovp);
177 
178 	/* If length is larger than the file, just update the times. */
179 	if (oip->i_size <= length) {
180 		oip->i_flag |= ICHG|IUPD;
181 		ITIMES(oip, &time, &time);
182 		return (0);
183 	}
184 
185 	/*
186 	 * Update the size of the file. If the file is not being truncated to
187 	 * a block boundry, the contents of the partial block following the end
188 	 * of the file must be zero'ed in case it ever become accessable again
189 	 * because of subsequent file growth.
190 	 */
191 	fs = oip->i_lfs;
192 	offset = blkoff(fs, length);
193 	if (offset == 0)
194 		oip->i_size = length;
195 	else {
196 		lbn = lblkno(fs, length);
197 #ifdef QUOTA
198 		if (error = getinoquota(oip))
199 			return (error);
200 #endif
201 		if (error = bread(ovp, lbn, fs->lfs_bsize, NOCRED, &bp))
202 			return (error);
203 		oip->i_size = length;
204 		size = blksize(fs);
205 		(void)vnode_pager_uncache(ovp);
206 		bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset));
207 		allocbuf(bp, size);
208 		LFS_UBWRITE(bp);
209 	}
210 	/*
211 	 * XXX
212 	 * Bzero inode block pointers here, for consistency with ffs.
213 	 * Segment usage information has to be updated when the blocks
214 	 * are free.
215 	 * Block count in the inode has to be fixed when blocks are
216 	 * free.
217 	 */
218 	(void)vinvalbuf(ovp, length > 0);
219 	return (0);
220 }
221