xref: /csrg-svn/sys/ufs/lfs/lfs_inode.c (revision 37736)
123399Smckusick /*
2*37736Smckusick  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3*37736Smckusick  * All rights reserved.
423399Smckusick  *
5*37736Smckusick  * Redistribution and use in source and binary forms are permitted
6*37736Smckusick  * provided that the above copyright notice and this paragraph are
7*37736Smckusick  * duplicated in all such forms and that any documentation,
8*37736Smckusick  * advertising materials, and other materials related to such
9*37736Smckusick  * distribution and use acknowledge that the software was developed
10*37736Smckusick  * by the University of California, Berkeley.  The name of the
11*37736Smckusick  * University may not be used to endorse or promote products derived
12*37736Smckusick  * from this software without specific prior written permission.
13*37736Smckusick  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14*37736Smckusick  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15*37736Smckusick  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16*37736Smckusick  *
17*37736Smckusick  *	@(#)lfs_inode.c	7.6 (Berkeley) 05/09/89
1823399Smckusick  */
1924Sbill 
2017099Sbloom #include "param.h"
2117099Sbloom #include "systm.h"
2217099Sbloom #include "mount.h"
2317099Sbloom #include "user.h"
24*37736Smckusick #include "file.h"
2517099Sbloom #include "buf.h"
2624525Sbloom #include "cmap.h"
27*37736Smckusick #include "vnode.h"
28*37736Smckusick #include "../ufs/inode.h"
29*37736Smckusick #include "../ufs/fs.h"
30*37736Smckusick #include "../ufs/ufsmount.h"
317651Ssam #ifdef QUOTA
32*37736Smckusick #include "../ufs/quota.h"
337504Sroot #endif
3417099Sbloom #include "kernel.h"
3531661Smckusick #include "malloc.h"
3624Sbill 
3716840Smckusick #define	INOHSZ	512
387334Skre #if	((INOHSZ&(INOHSZ-1)) == 0)
397334Skre #define	INOHASH(dev,ino)	(((dev)+(ino))&(INOHSZ-1))
407334Skre #else
4110852Ssam #define	INOHASH(dev,ino)	(((unsigned)((dev)+(ino)))%INOHSZ)
427334Skre #endif
4324Sbill 
44*37736Smckusick #define INSFREE(ip) {\
45*37736Smckusick 	if (ifreeh) { \
46*37736Smckusick 		*ifreet = (ip); \
47*37736Smckusick 		(ip)->i_freeb = ifreet; \
48*37736Smckusick 	} else { \
49*37736Smckusick 		ifreeh = (ip); \
50*37736Smckusick 		(ip)->i_freeb = &ifreeh; \
51*37736Smckusick 	} \
52*37736Smckusick 	(ip)->i_freef = NULL; \
53*37736Smckusick 	ifreet = &(ip)->i_freef; \
54*37736Smckusick }
55*37736Smckusick 
567334Skre union ihead {				/* inode LRU cache, Chris Maltby */
577334Skre 	union  ihead *ih_head[2];
587334Skre 	struct inode *ih_chain[2];
597334Skre } ihead[INOHSZ];
607334Skre 
61*37736Smckusick struct inode *ifreeh, **ifreet, *bdevlisth;
627334Skre 
6324Sbill /*
6424Sbill  * Initialize hash links for inodes
6524Sbill  * and build inode free list.
6624Sbill  */
6724Sbill ihinit()
6824Sbill {
6924Sbill 	register int i;
702737Swnj 	register struct inode *ip = inode;
717334Skre 	register union  ihead *ih = ihead;
7224Sbill 
737334Skre 	for (i = INOHSZ; --i >= 0; ih++) {
747334Skre 		ih->ih_head[0] = ih;
757334Skre 		ih->ih_head[1] = ih;
767334Skre 	}
777334Skre 	ifreeh = ip;
787334Skre 	ifreet = &ip->i_freef;
797334Skre 	ip->i_freeb = &ifreeh;
807334Skre 	ip->i_forw = ip;
817334Skre 	ip->i_back = ip;
82*37736Smckusick 	ITOV(ip)->v_data = (qaddr_t)ip;
837334Skre 	for (i = ninode; --i > 0; ) {
847334Skre 		++ip;
857334Skre 		ip->i_forw = ip;
867334Skre 		ip->i_back = ip;
87*37736Smckusick 		ITOV(ip)->v_data = (qaddr_t)ip;
887334Skre 		*ifreet = ip;
897334Skre 		ip->i_freeb = ifreet;
907334Skre 		ifreet = &ip->i_freef;
917334Skre 	}
927334Skre 	ip->i_freef = NULL;
9324Sbill }
9424Sbill 
9524Sbill /*
96*37736Smckusick  * Look up an vnode/inode by device,inumber.
9724Sbill  * If it is in core (in the inode structure),
9824Sbill  * honor the locking protocol.
9924Sbill  * If it is not in core, read it in from the
10024Sbill  * specified device.
101*37736Smckusick  * Callers must check for mount points!!
10224Sbill  * In all cases, a pointer to a locked
10324Sbill  * inode structure is returned.
10424Sbill  */
105*37736Smckusick iget(xp, ino, ipp)
106*37736Smckusick 	struct inode *xp;
1074818Swnj 	ino_t ino;
108*37736Smckusick 	struct inode **ipp;
10924Sbill {
110*37736Smckusick 	dev_t dev = xp->i_dev;
111*37736Smckusick 	struct mount *mntp = ITOV(xp)->v_mount;
112*37736Smckusick 	register struct fs *fs = VFSTOUFS(mntp)->um_fs;
113*37736Smckusick 	register struct inode *ip, *iq;
114*37736Smckusick 	register struct vnode *vp;
115*37736Smckusick 	struct inode *nip;
116*37736Smckusick 	struct buf *bp;
117*37736Smckusick 	struct dinode tdip, *dp;
118*37736Smckusick 	union  ihead *ih;
119*37736Smckusick 	int error;
12024Sbill 
12124Sbill loop:
1227334Skre 	ih = &ihead[INOHASH(dev, ino)];
1237334Skre 	for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw)
1244818Swnj 		if (ino == ip->i_number && dev == ip->i_dev) {
12516642Ssam 			/*
12616642Ssam 			 * Following is essentially an inline expanded
12716642Ssam 			 * copy of igrab(), expanded inline for speed,
12816642Ssam 			 * and so that the test for a mounted on inode
12916642Ssam 			 * can be deferred until after we are sure that
13016642Ssam 			 * the inode isn't busy.
13116642Ssam 			 */
1328452Sroot 			if ((ip->i_flag&ILOCKED) != 0) {
13324Sbill 				ip->i_flag |= IWANT;
13424Sbill 				sleep((caddr_t)ip, PINOD);
13524Sbill 				goto loop;
13624Sbill 			}
137*37736Smckusick 			vp = ITOV(ip);
138*37736Smckusick 			if (vp->v_count == 0) {		/* ino on free list */
1397334Skre 				if (iq = ip->i_freef)
1407334Skre 					iq->i_freeb = ip->i_freeb;
1417334Skre 				else
1427334Skre 					ifreet = ip->i_freeb;
1437334Skre 				*ip->i_freeb = iq;
1447334Skre 				ip->i_freef = NULL;
1457334Skre 				ip->i_freeb = NULL;
1467334Skre 			}
1478452Sroot 			ip->i_flag |= ILOCKED;
148*37736Smckusick 			vp->v_count++;
149*37736Smckusick 			*ipp = ip;
150*37736Smckusick 			return(0);
15124Sbill 		}
152*37736Smckusick 	if (error = getnewino(dev, ino, &nip)) {
153*37736Smckusick 		*ipp = 0;
154*37736Smckusick 		return (error);
155*37736Smckusick 	}
156*37736Smckusick 	ip = nip;
157*37736Smckusick 	/*
158*37736Smckusick 	 * Read in the disk contents for the inode.
159*37736Smckusick 	 */
160*37736Smckusick 	if (error = bread(VFSTOUFS(mntp)->um_devvp, fsbtodb(fs, itod(fs, ino)),
161*37736Smckusick 	    (int)fs->fs_bsize, &bp)) {
162*37736Smckusick 		/*
163*37736Smckusick 		 * The inode doesn't contain anything useful, so it would
164*37736Smckusick 		 * be misleading to leave it on its hash chain. Iput() will
165*37736Smckusick 		 * take care of putting it back on the free list. We also
166*37736Smckusick 		 * lose its inumber, just in case.
167*37736Smckusick 		 */
168*37736Smckusick 		remque(ip);
169*37736Smckusick 		ip->i_forw = ip;
170*37736Smckusick 		ip->i_back = ip;
171*37736Smckusick 		ip->i_number = 0;
172*37736Smckusick 		INSFREE(ip);
173*37736Smckusick 		ip->i_flag = 0;
174*37736Smckusick 		brelse(bp);
175*37736Smckusick 		*ipp = 0;
176*37736Smckusick 		return(error);
177*37736Smckusick 	}
178*37736Smckusick 	/*
179*37736Smckusick 	 * Check to see if the new inode represents a block device
180*37736Smckusick 	 * for which we already have an inode (either because of
181*37736Smckusick 	 * bdevvp() or because of a different inode representing
182*37736Smckusick 	 * the same block device). If such an alias exists, put the
183*37736Smckusick 	 * just allocated inode back on the free list, and replace
184*37736Smckusick 	 * the contents of the existing inode with the contents of
185*37736Smckusick 	 * the new inode.
186*37736Smckusick 	 */
187*37736Smckusick 	dp = bp->b_un.b_dino;
188*37736Smckusick 	dp += itoo(fs, ino);
189*37736Smckusick 	if ((dp->di_mode & IFMT) != IFBLK) {
190*37736Smckusick 		ip->i_ic = dp->di_ic;
191*37736Smckusick 		brelse(bp);
192*37736Smckusick 	} else {
193*37736Smckusick again:
194*37736Smckusick 		for (iq = bdevlisth; iq; iq = iq->i_devlst) {
195*37736Smckusick 			if (dp->di_rdev != ITOV(iq)->v_rdev)
196*37736Smckusick 				continue;
197*37736Smckusick 			igrab(iq);
198*37736Smckusick 			if (dp->di_rdev != ITOV(iq)->v_rdev) {
199*37736Smckusick 				iput(iq);
200*37736Smckusick 				goto again;
201*37736Smckusick 			}
202*37736Smckusick 			/*
203*37736Smckusick 			 * Discard unneeded inode.
204*37736Smckusick 			 */
205*37736Smckusick 			remque(ip);
206*37736Smckusick 			ip->i_forw = ip;
207*37736Smckusick 			ip->i_back = ip;
208*37736Smckusick 			ip->i_number = 0;
209*37736Smckusick 			INSFREE(ip);
210*37736Smckusick 			ip->i_flag = 0;
211*37736Smckusick 			/*
212*37736Smckusick 			 * Reinitialize aliased inode.
213*37736Smckusick 			 * We must release the buffer that we just read
214*37736Smckusick 			 * before doing the iupdat() to avoid a possible
215*37736Smckusick 			 * deadlock with updating an inode in the same
216*37736Smckusick 			 * disk block.
217*37736Smckusick 			 */
218*37736Smckusick 			ip = iq;
219*37736Smckusick 			vp = ITOV(iq);
220*37736Smckusick 			tdip.di_ic = dp->di_ic;
221*37736Smckusick 			brelse(bp);
222*37736Smckusick 			error = iupdat(ip, &time, &time, 1);
223*37736Smckusick 			ip->i_ic = tdip.di_ic;
224*37736Smckusick 			remque(ip);
225*37736Smckusick 			insque(ip, ih);
226*37736Smckusick 			ip->i_dev = dev;
227*37736Smckusick 			ip->i_number = ino;
228*37736Smckusick 			if (ip->i_devvp) {
229*37736Smckusick 				vrele(ip->i_devvp);
230*37736Smckusick 				ip->i_devvp = 0;
231*37736Smckusick 			}
232*37736Smckusick 			cache_purge(vp);
233*37736Smckusick 			break;
234*37736Smckusick 		}
235*37736Smckusick 		if (iq == 0) {
236*37736Smckusick 			ip->i_ic = dp->di_ic;
237*37736Smckusick 			brelse(bp);
238*37736Smckusick 			ip->i_devlst = bdevlisth;
239*37736Smckusick 			bdevlisth = ip;
240*37736Smckusick 		}
241*37736Smckusick 	}
242*37736Smckusick 	/*
243*37736Smckusick 	 * Finish inode initialization.
244*37736Smckusick 	 */
245*37736Smckusick 	ip->i_fs = fs;
246*37736Smckusick 	ip->i_devvp = VFSTOUFS(mntp)->um_devvp;
247*37736Smckusick 	ip->i_devvp->v_count++;
248*37736Smckusick 	/*
249*37736Smckusick 	 * Initialize the associated vnode
250*37736Smckusick 	 */
251*37736Smckusick 	vp = ITOV(ip);
252*37736Smckusick 	vinit(vp, mntp, IFTOVT(ip->i_mode), &ufs_vnodeops);
253*37736Smckusick 	if (vp->v_type == VCHR || vp->v_type == VBLK) {
254*37736Smckusick 		vp->v_rdev = ip->i_rdev;
255*37736Smckusick 		vp->v_op = &blk_vnodeops;
256*37736Smckusick 	}
257*37736Smckusick 	if (ino == ROOTINO)
258*37736Smckusick 		vp->v_flag |= VROOT;
259*37736Smckusick #ifdef QUOTA
260*37736Smckusick 	if (ip->i_mode != 0)
261*37736Smckusick 		ip->i_dquot = inoquota(ip);
262*37736Smckusick #endif
263*37736Smckusick 	*ipp = ip;
264*37736Smckusick 	return (0);
265*37736Smckusick }
2667334Skre 
267*37736Smckusick /*
268*37736Smckusick  * Allocate a new inode.
269*37736Smckusick  *
270*37736Smckusick  * Put it onto its hash chain and lock it so that other requests for
271*37736Smckusick  * this inode will block if they arrive while we are sleeping waiting
272*37736Smckusick  * for old data structures to be purged or for the contents of the disk
273*37736Smckusick  * portion of this inode to be read.
274*37736Smckusick  */
275*37736Smckusick getnewino(dev, ino, ipp)
276*37736Smckusick 	dev_t dev;
277*37736Smckusick 	ino_t ino;
278*37736Smckusick 	struct inode **ipp;
279*37736Smckusick {
280*37736Smckusick 	union ihead *ih;
281*37736Smckusick 	register struct inode *ip, *iq;
282*37736Smckusick 	register struct vnode *vp;
283*37736Smckusick 
284*37736Smckusick 	/*
285*37736Smckusick 	 * Remove the next inode from the free list.
286*37736Smckusick 	 */
2877334Skre 	if ((ip = ifreeh) == NULL) {
2882933Swnj 		tablefull("inode");
289*37736Smckusick 		*ipp = 0;
290*37736Smckusick 		return(ENFILE);
29124Sbill 	}
292*37736Smckusick 	vp = ITOV(ip);
293*37736Smckusick 	if (vp->v_count)
29416720Skarels 		panic("free inode isn't");
2957334Skre 	if (iq = ip->i_freef)
2967334Skre 		iq->i_freeb = &ifreeh;
2977334Skre 	ifreeh = iq;
2987334Skre 	ip->i_freef = NULL;
2997334Skre 	ip->i_freeb = NULL;
3007334Skre 	/*
3017334Skre 	 * Now to take inode off the hash chain it was on
3027334Skre 	 * (initially, or after an iflush, it is on a "hash chain"
303*37736Smckusick 	 * consisting entirely of itself, and pointed to by no-one)
304*37736Smckusick 	 * and put it on the chain for its new (ino, dev) pair.
3057334Skre 	 */
3067335Skre 	remque(ip);
30724Sbill 	ip->i_dev = dev;
30824Sbill 	ip->i_number = ino;
309*37736Smckusick 	if (dev != NODEV) {
310*37736Smckusick 		ih = &ihead[INOHASH(dev, ino)];
311*37736Smckusick 		insque(ip, ih);
312*37736Smckusick 	}
3138452Sroot 	ip->i_flag = ILOCKED;
3146569Smckusic 	ip->i_lastr = 0;
31524Sbill 	/*
316*37736Smckusick 	 * Purge old data structures associated with the inode.
31724Sbill 	 */
318*37736Smckusick 	cache_purge(vp);
319*37736Smckusick 	if (ip->i_devvp) {
320*37736Smckusick 		vrele(ip->i_devvp);
321*37736Smckusick 		ip->i_devvp = 0;
322*37736Smckusick 	}
3237651Ssam #ifdef QUOTA
324*37736Smckusick 	dqrele(ip->i_dquot);
325*37736Smckusick 	ip->i_dquot = NODQUOT;
3267492Skre #endif
327*37736Smckusick 	if (vp->v_type == VBLK) {
328*37736Smckusick 		if (bdevlisth == ip) {
329*37736Smckusick 			bdevlisth = ip->i_devlst;
330*37736Smckusick 		} else {
331*37736Smckusick 			for (iq = bdevlisth; iq; iq = iq->i_devlst) {
332*37736Smckusick 				if (iq->i_devlst != ip)
333*37736Smckusick 					continue;
334*37736Smckusick 				iq->i_devlst = ip->i_devlst;
335*37736Smckusick 				break;
336*37736Smckusick 			}
337*37736Smckusick 			if (iq == NULL)
338*37736Smckusick 				panic("missing bdev");
339*37736Smckusick 		}
34024Sbill 	}
341*37736Smckusick 	*ipp = ip;
342*37736Smckusick 	return (0);
34324Sbill }
34424Sbill 
34524Sbill /*
34616642Ssam  * Convert a pointer to an inode into a reference to an inode.
34716642Ssam  *
34816642Ssam  * This is basically the internal piece of iget (after the
34916642Ssam  * inode pointer is located) but without the test for mounted
35016642Ssam  * filesystems.  It is caller's responsibility to check that
35116642Ssam  * the inode pointer is valid.
35216642Ssam  */
35316642Ssam igrab(ip)
35416642Ssam 	register struct inode *ip;
35516642Ssam {
356*37736Smckusick 	register struct vnode *vp = ITOV(ip);
357*37736Smckusick 
35816642Ssam 	while ((ip->i_flag&ILOCKED) != 0) {
35916642Ssam 		ip->i_flag |= IWANT;
36016642Ssam 		sleep((caddr_t)ip, PINOD);
36116642Ssam 	}
362*37736Smckusick 	if (vp->v_count == 0) {		/* ino on free list */
36316642Ssam 		register struct inode *iq;
36416642Ssam 
36516642Ssam 		if (iq = ip->i_freef)
36616642Ssam 			iq->i_freeb = ip->i_freeb;
36716642Ssam 		else
36816642Ssam 			ifreet = ip->i_freeb;
36916642Ssam 		*ip->i_freeb = iq;
37016642Ssam 		ip->i_freef = NULL;
37116642Ssam 		ip->i_freeb = NULL;
37216642Ssam 	}
373*37736Smckusick 	vp->v_count++;
37416642Ssam 	ip->i_flag |= ILOCKED;
37516642Ssam }
37616642Ssam 
37716642Ssam /*
378*37736Smckusick  * Create a vnode for a block device.
379*37736Smckusick  * Used for root filesystem, argdev, and swap areas.
380*37736Smckusick  */
381*37736Smckusick bdevvp(dev, vpp)
382*37736Smckusick 	dev_t dev;
383*37736Smckusick 	struct vnode **vpp;
384*37736Smckusick {
385*37736Smckusick 	register struct inode *ip;
386*37736Smckusick 	register struct vnode *vp;
387*37736Smckusick 	struct inode *nip;
388*37736Smckusick 	int error;
389*37736Smckusick 
390*37736Smckusick 	/*
391*37736Smckusick 	 * Check for the existence of an existing vnode.
392*37736Smckusick 	 */
393*37736Smckusick again:
394*37736Smckusick 	for (ip = bdevlisth; ip; ip = ip->i_devlst) {
395*37736Smckusick 		vp = ITOV(ip);
396*37736Smckusick 		if (dev != vp->v_rdev)
397*37736Smckusick 			continue;
398*37736Smckusick 		igrab(ip);
399*37736Smckusick 		if (dev != vp->v_rdev) {
400*37736Smckusick 			iput(ip);
401*37736Smckusick 			goto again;
402*37736Smckusick 		}
403*37736Smckusick 		IUNLOCK(ip);
404*37736Smckusick 		*vpp = vp;
405*37736Smckusick 		return (0);
406*37736Smckusick 	}
407*37736Smckusick 	if (error = getnewino(NODEV, (ino_t)0, &nip)) {
408*37736Smckusick 		*vpp = 0;
409*37736Smckusick 		return (error);
410*37736Smckusick 	}
411*37736Smckusick 	ip = nip;
412*37736Smckusick 	ip->i_fs = 0;
413*37736Smckusick 	ip->i_devlst = bdevlisth;
414*37736Smckusick 	bdevlisth = ip;
415*37736Smckusick 	vp = ITOV(ip);
416*37736Smckusick 	vinit(vp, 0, VBLK, &blk_vnodeops);
417*37736Smckusick 	vp->v_rdev = dev;
418*37736Smckusick 	IUNLOCK(ip);
419*37736Smckusick 	*vpp = vp;
420*37736Smckusick 	return (0);
421*37736Smckusick }
422*37736Smckusick 
423*37736Smckusick /*
42424Sbill  * Decrement reference count of
42524Sbill  * an inode structure.
42624Sbill  * On the last reference,
42724Sbill  * write the inode out and if necessary,
42824Sbill  * truncate and deallocate the file.
42924Sbill  */
43024Sbill iput(ip)
4314818Swnj 	register struct inode *ip;
43224Sbill {
4337118Smckusick 
4348452Sroot 	if ((ip->i_flag & ILOCKED) == 0)
4357118Smckusick 		panic("iput");
43616665Smckusick 	IUNLOCK(ip);
437*37736Smckusick 	vrele(ITOV(ip));
4387118Smckusick }
4397118Smckusick 
440*37736Smckusick 
441*37736Smckusick ufs_inactive(vp)
442*37736Smckusick 	struct vnode *vp;
4437118Smckusick {
444*37736Smckusick 	register struct inode *ip = VTOI(vp);
445*37736Smckusick 	int mode, error;
44624Sbill 
447*37736Smckusick 	if (ITOV(ip)->v_count != 0)
448*37736Smckusick 		panic("ufs_inactive: not inactive");
449*37736Smckusick 	ip->i_flag |= ILOCKED;
450*37736Smckusick 	if (ip->i_nlink <= 0 && (ITOV(ip)->v_mount->m_flag&M_RDONLY) == 0) {
451*37736Smckusick 		error = itrunc(ip, (u_long)0);
452*37736Smckusick 		mode = ip->i_mode;
453*37736Smckusick 		ip->i_mode = 0;
454*37736Smckusick 		ip->i_rdev = 0;
455*37736Smckusick 		ip->i_flag |= IUPD|ICHG;
456*37736Smckusick 		ifree(ip, ip->i_number, mode);
4577651Ssam #ifdef QUOTA
458*37736Smckusick 		(void) chkiq(ip->i_dev, ip, ip->i_uid, 0);
459*37736Smckusick 		dqrele(ip->i_dquot);
460*37736Smckusick 		ip->i_dquot = NODQUOT;
4617492Skre #endif
462*37736Smckusick 	}
463*37736Smckusick 	IUPDAT(ip, &time, &time, 0);
464*37736Smckusick 	IUNLOCK(ip);
465*37736Smckusick 	ip->i_flag = 0;
466*37736Smckusick 	/*
467*37736Smckusick 	 * Put the inode on the end of the free list.
468*37736Smckusick 	 * Possibly in some cases it would be better to
469*37736Smckusick 	 * put the inode at the head of the free list,
470*37736Smckusick 	 * (eg: where i_mode == 0 || i_number == 0).
471*37736Smckusick 	 */
472*37736Smckusick 	INSFREE(ip);
473*37736Smckusick 	return (error);
47424Sbill }
47524Sbill 
47624Sbill /*
47724Sbill  * Check accessed and update flags on
47824Sbill  * an inode structure.
47924Sbill  * If any is on, update the inode
48024Sbill  * with the current time.
4811203Sbill  * If waitfor is given, then must insure
4821203Sbill  * i/o order so wait for write to complete.
48324Sbill  */
4841203Sbill iupdat(ip, ta, tm, waitfor)
4854818Swnj 	register struct inode *ip;
4868630Sroot 	struct timeval *ta, *tm;
4874818Swnj 	int waitfor;
48824Sbill {
489*37736Smckusick 	struct buf *bp;
490*37736Smckusick 	struct vnode *vp = ITOV(ip);
49124Sbill 	struct dinode *dp;
49230749Skarels 	register struct fs *fs;
493*37736Smckusick 	int error;
49424Sbill 
49530749Skarels 	fs = ip->i_fs;
496*37736Smckusick 	if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) == 0)
497*37736Smckusick 		return (0);
498*37736Smckusick 	if (vp->v_mount->m_flag & M_RDONLY)
499*37736Smckusick 		return (0);
500*37736Smckusick 	error = bread(ip->i_devvp, fsbtodb(fs, itod(fs, ip->i_number)),
501*37736Smckusick 		(int)fs->fs_bsize, &bp);
502*37736Smckusick 	if (error) {
503*37736Smckusick 		brelse(bp);
504*37736Smckusick 		return (error);
50524Sbill 	}
506*37736Smckusick 	if (ip->i_flag&IACC)
507*37736Smckusick 		ip->i_atime = ta->tv_sec;
508*37736Smckusick 	if (ip->i_flag&IUPD)
509*37736Smckusick 		ip->i_mtime = tm->tv_sec;
510*37736Smckusick 	if (ip->i_flag&ICHG)
511*37736Smckusick 		ip->i_ctime = time.tv_sec;
512*37736Smckusick 	ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD);
513*37736Smckusick 	dp = bp->b_un.b_dino + itoo(fs, ip->i_number);
514*37736Smckusick 	dp->di_ic = ip->i_ic;
515*37736Smckusick 	if (waitfor) {
516*37736Smckusick 		return (bwrite(bp));
517*37736Smckusick 	} else {
518*37736Smckusick 		bdwrite(bp);
519*37736Smckusick 		return (0);
520*37736Smckusick 	}
52124Sbill }
52224Sbill 
52310736Ssam #define	SINGLE	0	/* index of single indirect block */
52410736Ssam #define	DOUBLE	1	/* index of double indirect block */
52510736Ssam #define	TRIPLE	2	/* index of triple indirect block */
52624Sbill /*
5277702Ssam  * Truncate the inode ip to at most
5287702Ssam  * length size.  Free affected disk
5297702Ssam  * blocks -- the blocks of the file
5307702Ssam  * are removed in reverse order.
53110736Ssam  *
53210736Ssam  * NB: triple indirect blocks are untested.
53324Sbill  */
53410736Ssam itrunc(oip, length)
53517942Smckusick 	register struct inode *oip;
5369165Ssam 	u_long length;
53724Sbill {
5389165Ssam 	register daddr_t lastblock;
53926272Skarels 	daddr_t bn, lbn, lastiblock[NIADDR];
5406569Smckusic 	register struct fs *fs;
54110736Ssam 	register struct inode *ip;
54217942Smckusick 	struct buf *bp;
543*37736Smckusick 	int offset, osize, size, level;
544*37736Smckusick 	long count, nblocks, blocksreleased = 0;
54517942Smckusick 	register int i;
546*37736Smckusick 	int error, allerror = 0;
54710736Ssam 	struct inode tip;
5489165Ssam 
54913000Ssam 	if (oip->i_size <= length) {
55013000Ssam 		oip->i_flag |= ICHG|IUPD;
551*37736Smckusick 		error = iupdat(oip, &time, &time, 1);
552*37736Smckusick 		return (error);
55313000Ssam 	}
5541203Sbill 	/*
55510736Ssam 	 * Calculate index into inode's block list of
55610736Ssam 	 * last direct and indirect blocks (if any)
55710736Ssam 	 * which we want to keep.  Lastblock is -1 when
55810736Ssam 	 * the file is truncated to 0.
5591203Sbill 	 */
56010736Ssam 	fs = oip->i_fs;
5619165Ssam 	lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1;
56210736Ssam 	lastiblock[SINGLE] = lastblock - NDADDR;
56310736Ssam 	lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs);
56410736Ssam 	lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs);
56512645Ssam 	nblocks = btodb(fs->fs_bsize);
5666569Smckusic 	/*
56717942Smckusick 	 * Update the size of the file. If the file is not being
56817942Smckusick 	 * truncated to a block boundry, the contents of the
56917942Smckusick 	 * partial block following the end of the file must be
57017942Smckusick 	 * zero'ed in case it ever become accessable again because
57117942Smckusick 	 * of subsequent file growth.
57217942Smckusick 	 */
57317942Smckusick 	osize = oip->i_size;
57417942Smckusick 	offset = blkoff(fs, length);
57517942Smckusick 	if (offset == 0) {
57617942Smckusick 		oip->i_size = length;
57717942Smckusick 	} else {
57817942Smckusick 		lbn = lblkno(fs, length);
579*37736Smckusick 		error = balloc(oip, lbn, offset, &bn, B_CLRBUF);
580*37736Smckusick 		if (error)
581*37736Smckusick 			return (error);
582*37736Smckusick 		if ((long)bn < 0)
583*37736Smckusick 			panic("itrunc: hole");
58417942Smckusick 		oip->i_size = length;
58517942Smckusick 		size = blksize(fs, oip, lbn);
58630749Skarels 		count = howmany(size, CLBYTES);
58730749Skarels 		for (i = 0; i < count; i++)
588*37736Smckusick 			munhash(oip->i_devvp, bn + i * CLBYTES / DEV_BSIZE);
589*37736Smckusick 		error = bread(oip->i_devvp, bn, size, &bp);
590*37736Smckusick 		if (error) {
59117942Smckusick 			oip->i_size = osize;
59217942Smckusick 			brelse(bp);
593*37736Smckusick 			return (error);
59417942Smckusick 		}
59526272Skarels 		bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset));
59617942Smckusick 		bdwrite(bp);
59717942Smckusick 	}
59817942Smckusick 	/*
59917942Smckusick 	 * Update file and block pointers
60010736Ssam 	 * on disk before we start freeing blocks.
60110736Ssam 	 * If we crash before free'ing blocks below,
60210736Ssam 	 * the blocks will be returned to the free list.
60310736Ssam 	 * lastiblock values are also normalized to -1
60410736Ssam 	 * for calls to indirtrunc below.
6056569Smckusic 	 */
60610736Ssam 	tip = *oip;
60717942Smckusick 	tip.i_size = osize;
60810736Ssam 	for (level = TRIPLE; level >= SINGLE; level--)
60910736Ssam 		if (lastiblock[level] < 0) {
61010736Ssam 			oip->i_ib[level] = 0;
61110736Ssam 			lastiblock[level] = -1;
6129165Ssam 		}
61310736Ssam 	for (i = NDADDR - 1; i > lastblock; i--)
61410736Ssam 		oip->i_db[i] = 0;
61510736Ssam 	oip->i_flag |= ICHG|IUPD;
616*37736Smckusick 	allerror = syncip(oip);
61710736Ssam 
6186569Smckusic 	/*
61910736Ssam 	 * Indirect blocks first.
6206569Smckusic 	 */
62117942Smckusick 	ip = &tip;
62210736Ssam 	for (level = TRIPLE; level >= SINGLE; level--) {
62310736Ssam 		bn = ip->i_ib[level];
6249165Ssam 		if (bn != 0) {
625*37736Smckusick 			error = indirtrunc(ip, bn, lastiblock[level], level,
626*37736Smckusick 				&count);
627*37736Smckusick 			if (error)
628*37736Smckusick 				allerror = error;
629*37736Smckusick 			blocksreleased += count;
63010736Ssam 			if (lastiblock[level] < 0) {
63110736Ssam 				ip->i_ib[level] = 0;
63231402Smckusick 				blkfree(ip, bn, (off_t)fs->fs_bsize);
63310736Ssam 				blocksreleased += nblocks;
63410736Ssam 			}
63510736Ssam 		}
63610736Ssam 		if (lastiblock[level] >= 0)
63710736Ssam 			goto done;
6389165Ssam 	}
63910736Ssam 
6406569Smckusic 	/*
64110736Ssam 	 * All whole direct blocks or frags.
6426569Smckusic 	 */
6439165Ssam 	for (i = NDADDR - 1; i > lastblock; i--) {
64426359Skarels 		register off_t bsize;
6459165Ssam 
6466569Smckusic 		bn = ip->i_db[i];
6479165Ssam 		if (bn == 0)
64824Sbill 			continue;
6499165Ssam 		ip->i_db[i] = 0;
65024525Sbloom 		bsize = (off_t)blksize(fs, ip, i);
65131402Smckusick 		blkfree(ip, bn, bsize);
65224525Sbloom 		blocksreleased += btodb(bsize);
65324Sbill 	}
65410736Ssam 	if (lastblock < 0)
65510736Ssam 		goto done;
65610736Ssam 
6571203Sbill 	/*
6589165Ssam 	 * Finally, look for a change in size of the
6599165Ssam 	 * last direct block; release any frags.
6601203Sbill 	 */
66110736Ssam 	bn = ip->i_db[lastblock];
66210736Ssam 	if (bn != 0) {
66326359Skarels 		off_t oldspace, newspace;
66410736Ssam 
6659165Ssam 		/*
6669165Ssam 		 * Calculate amount of space we're giving
6679165Ssam 		 * back as old block size minus new block size.
6689165Ssam 		 */
66910736Ssam 		oldspace = blksize(fs, ip, lastblock);
6709165Ssam 		ip->i_size = length;
67110736Ssam 		newspace = blksize(fs, ip, lastblock);
67210736Ssam 		if (newspace == 0)
67310736Ssam 			panic("itrunc: newspace");
67410736Ssam 		if (oldspace - newspace > 0) {
6759165Ssam 			/*
6769165Ssam 			 * Block number of space to be free'd is
6779165Ssam 			 * the old block # plus the number of frags
6789165Ssam 			 * required for the storage we're keeping.
6799165Ssam 			 */
68010736Ssam 			bn += numfrags(fs, newspace);
68131402Smckusick 			blkfree(ip, bn, oldspace - newspace);
68212645Ssam 			blocksreleased += btodb(oldspace - newspace);
6839165Ssam 		}
6849165Ssam 	}
6859165Ssam done:
68610736Ssam /* BEGIN PARANOIA */
68710736Ssam 	for (level = SINGLE; level <= TRIPLE; level++)
68810736Ssam 		if (ip->i_ib[level] != oip->i_ib[level])
68910736Ssam 			panic("itrunc1");
69010736Ssam 	for (i = 0; i < NDADDR; i++)
69110736Ssam 		if (ip->i_db[i] != oip->i_db[i])
69210736Ssam 			panic("itrunc2");
69310736Ssam /* END PARANOIA */
69412645Ssam 	oip->i_blocks -= blocksreleased;
69512645Ssam 	if (oip->i_blocks < 0)			/* sanity */
69612645Ssam 		oip->i_blocks = 0;
69712645Ssam 	oip->i_flag |= ICHG;
6989165Ssam #ifdef QUOTA
69912645Ssam 	(void) chkdq(oip, -blocksreleased, 0);
7009165Ssam #endif
701*37736Smckusick 	return (allerror);
70224Sbill }
70324Sbill 
7049165Ssam /*
7059165Ssam  * Release blocks associated with the inode ip and
7069165Ssam  * stored in the indirect block bn.  Blocks are free'd
7079165Ssam  * in LIFO order up to (but not including) lastbn.  If
70810736Ssam  * level is greater than SINGLE, the block is an indirect
70910736Ssam  * block and recursive calls to indirtrunc must be used to
71010736Ssam  * cleanse other indirect blocks.
71110736Ssam  *
71210736Ssam  * NB: triple indirect blocks are untested.
7139165Ssam  */
714*37736Smckusick indirtrunc(ip, bn, lastbn, level, countp)
7156569Smckusic 	register struct inode *ip;
7169165Ssam 	daddr_t bn, lastbn;
71710736Ssam 	int level;
718*37736Smckusick 	long *countp;
71924Sbill {
7209165Ssam 	register int i;
72131661Smckusick 	struct buf *bp;
72231661Smckusick 	register struct fs *fs = ip->i_fs;
72324Sbill 	register daddr_t *bap;
72431661Smckusick 	daddr_t *copy, nb, last;
725*37736Smckusick 	long blkcount, factor;
726*37736Smckusick 	int nblocks, blocksreleased = 0;
727*37736Smckusick 	int error, allerror = 0;
72824Sbill 
72910736Ssam 	/*
73010736Ssam 	 * Calculate index in current block of last
73110736Ssam 	 * block to be kept.  -1 indicates the entire
73210736Ssam 	 * block so we need not calculate the index.
73310736Ssam 	 */
73410736Ssam 	factor = 1;
73510736Ssam 	for (i = SINGLE; i < level; i++)
73610736Ssam 		factor *= NINDIR(fs);
7379165Ssam 	last = lastbn;
73810736Ssam 	if (lastbn > 0)
73910736Ssam 		last /= factor;
74012645Ssam 	nblocks = btodb(fs->fs_bsize);
74110736Ssam 	/*
74210736Ssam 	 * Get buffer of block pointers, zero those
74310736Ssam 	 * entries corresponding to blocks to be free'd,
74410736Ssam 	 * and update on disk copy first.
74510736Ssam 	 */
746*37736Smckusick 	error = bread(ip->i_devvp, fsbtodb(fs, bn), (int)fs->fs_bsize, &bp);
747*37736Smckusick 	if (error) {
74810736Ssam 		brelse(bp);
749*37736Smckusick 		*countp = 0;
750*37736Smckusick 		return (error);
75110736Ssam 	}
75210736Ssam 	bap = bp->b_un.b_daddr;
75331661Smckusick 	MALLOC(copy, daddr_t *, fs->fs_bsize, M_TEMP, M_WAITOK);
75431661Smckusick 	bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->fs_bsize);
75510736Ssam 	bzero((caddr_t)&bap[last + 1],
75610736Ssam 	  (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t));
757*37736Smckusick 	error = bwrite(bp);
758*37736Smckusick 	if (error)
759*37736Smckusick 		allerror = error;
76031661Smckusick 	bap = copy;
76110736Ssam 
76210736Ssam 	/*
76310736Ssam 	 * Recursively free totally unused blocks.
76410736Ssam 	 */
7659165Ssam 	for (i = NINDIR(fs) - 1; i > last; i--) {
76624Sbill 		nb = bap[i];
7679165Ssam 		if (nb == 0)
76824Sbill 			continue;
769*37736Smckusick 		if (level > SINGLE) {
770*37736Smckusick 			error = indirtrunc(ip, nb, (daddr_t)-1, level - 1,
771*37736Smckusick 				&blkcount);
772*37736Smckusick 			if (error)
773*37736Smckusick 				allerror = error;
774*37736Smckusick 			blocksreleased += blkcount;
775*37736Smckusick 		}
77631402Smckusick 		blkfree(ip, nb, (off_t)fs->fs_bsize);
7779165Ssam 		blocksreleased += nblocks;
77824Sbill 	}
77910736Ssam 
78010736Ssam 	/*
78110736Ssam 	 * Recursively free last partial block.
78210736Ssam 	 */
78310736Ssam 	if (level > SINGLE && lastbn >= 0) {
78410736Ssam 		last = lastbn % factor;
7859165Ssam 		nb = bap[i];
786*37736Smckusick 		if (nb != 0) {
787*37736Smckusick 			error = indirtrunc(ip, nb, last, level - 1, &blkcount);
788*37736Smckusick 			if (error)
789*37736Smckusick 				allerror = error;
790*37736Smckusick 			blocksreleased += blkcount;
791*37736Smckusick 		}
7929165Ssam 	}
79331661Smckusick 	FREE(copy, M_TEMP);
794*37736Smckusick 	*countp = blocksreleased;
795*37736Smckusick 	return (allerror);
79624Sbill }
79724Sbill 
79824Sbill /*
79930749Skarels  * Remove any inodes in the inode cache belonging to dev.
8007334Skre  *
8017334Skre  * There should not be any active ones, return error if any are found
80230749Skarels  * (nb: this is a user error, not a system err).
8037334Skre  */
8047651Ssam #ifdef QUOTA
8057504Sroot iflush(dev, iq)
8067492Skre 	dev_t dev;
8077504Sroot 	struct inode *iq;
8087492Skre #else
8097334Skre iflush(dev)
8107334Skre 	dev_t dev;
8117492Skre #endif
8127334Skre {
8137335Skre 	register struct inode *ip;
8147334Skre 
8157334Skre 	for (ip = inode; ip < inodeNINODE; ip++) {
8167651Ssam #ifdef QUOTA
8177492Skre 		if (ip != iq && ip->i_dev == dev)
8187492Skre #else
8197334Skre 		if (ip->i_dev == dev)
8207492Skre #endif
821*37736Smckusick 			if (ITOV(ip)->v_count)
82230749Skarels 				return (EBUSY);
8237334Skre 			else {
8247335Skre 				remque(ip);
8257334Skre 				ip->i_forw = ip;
8267334Skre 				ip->i_back = ip;
8277334Skre 				/*
828*37736Smckusick 				 * as v_count == 0, the inode was on the free
8297334Skre 				 * list already, just leave it there, it will
8307334Skre 				 * fall off the bottom eventually. We could
8317334Skre 				 * perhaps move it to the head of the free
8327334Skre 				 * list, but as umounts are done so
8337334Skre 				 * infrequently, we would gain very little,
8347334Skre 				 * while making the code bigger.
8357334Skre 				 */
8367651Ssam #ifdef QUOTA
8377492Skre 				dqrele(ip->i_dquot);
8387492Skre 				ip->i_dquot = NODQUOT;
8397492Skre #endif
840*37736Smckusick 				if (ip->i_devvp) {
841*37736Smckusick 					vrele(ip->i_devvp);
842*37736Smckusick 					ip->i_devvp = 0;
843*37736Smckusick 				}
8447334Skre 			}
8457334Skre 	}
84630749Skarels 	return (0);
8477334Skre }
8487334Skre 
8493617Sroot /*
8504818Swnj  * Lock an inode. If its already locked, set the WANT bit and sleep.
8513617Sroot  */
8524818Swnj ilock(ip)
8534818Swnj 	register struct inode *ip;
8543617Sroot {
8553617Sroot 
856*37736Smckusick 	while (ip->i_flag & ILOCKED) {
857*37736Smckusick 		ip->i_flag |= IWANT;
858*37736Smckusick 		(void) sleep((caddr_t)ip, PINOD);
859*37736Smckusick 	}
860*37736Smckusick 	ip->i_flag |= ILOCKED;
8613617Sroot }
8623617Sroot 
8633617Sroot /*
8644818Swnj  * Unlock an inode.  If WANT bit is on, wakeup.
8653617Sroot  */
8667118Smckusick iunlock(ip)
8674818Swnj 	register struct inode *ip;
8683617Sroot {
8693617Sroot 
870*37736Smckusick 	if ((ip->i_flag & ILOCKED) == 0)
871*37736Smckusick 		printf("unlocking unlocked inode %d on dev 0x%x\n",
872*37736Smckusick 			ip->i_number, ip->i_dev);
873*37736Smckusick 	ip->i_flag &= ~ILOCKED;
874*37736Smckusick 	if (ip->i_flag&IWANT) {
875*37736Smckusick 		ip->i_flag &= ~IWANT;
876*37736Smckusick 		wakeup((caddr_t)ip);
877*37736Smckusick 	}
8783617Sroot }
879*37736Smckusick 
880*37736Smckusick /*
881*37736Smckusick  * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC.
882*37736Smckusick  * The mode is shifted to select the owner/group/other fields. The
883*37736Smckusick  * super user is granted all permissions.
884*37736Smckusick  *
885*37736Smckusick  * NB: Called from vnode op table. It seems this could all be done
886*37736Smckusick  * using vattr's but...
887*37736Smckusick  */
888*37736Smckusick iaccess(ip, mode, cred)
889*37736Smckusick 	register struct inode *ip;
890*37736Smckusick 	register int mode;
891*37736Smckusick 	struct ucred *cred;
892*37736Smckusick {
893*37736Smckusick 	register gid_t *gp;
894*37736Smckusick 	register struct vnode *vp = ITOV(ip);
895*37736Smckusick 	int i;
896*37736Smckusick 
897*37736Smckusick 	/*
898*37736Smckusick 	 * If you're the super-user,
899*37736Smckusick 	 * you always get access.
900*37736Smckusick 	 */
901*37736Smckusick 	if (cred->cr_uid == 0)
902*37736Smckusick 		return (0);
903*37736Smckusick 	/*
904*37736Smckusick 	 * Access check is based on only one of owner, group, public.
905*37736Smckusick 	 * If not owner, then check group. If not a member of the
906*37736Smckusick 	 * group, then check public access.
907*37736Smckusick 	 */
908*37736Smckusick 	if (cred->cr_uid != ip->i_uid) {
909*37736Smckusick 		mode >>= 3;
910*37736Smckusick 		gp = cred->cr_groups;
911*37736Smckusick 		for (i = 0; i < cred->cr_ngroups; i++, gp++)
912*37736Smckusick 			if (ip->i_gid == *gp)
913*37736Smckusick 				goto found;
914*37736Smckusick 		mode >>= 3;
915*37736Smckusick found:
916*37736Smckusick 		;
917*37736Smckusick 	}
918*37736Smckusick 	if ((ip->i_mode & mode) != 0)
919*37736Smckusick 		return (0);
920*37736Smckusick 	return (EACCES);
921*37736Smckusick }
922