|
|
1.1 root 1: /*
2: * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: * 3. All advertising materials mentioning features or use of this software
14: * must display the following acknowledgement:
15: * This product includes software developed by the University of
16: * California, Berkeley and its contributors.
17: * 4. Neither the name of the University nor the names of its contributors
18: * may be used to endorse or promote products derived from this software
19: * without specific prior written permission.
20: *
21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31: * SUCH DAMAGE.
32: *
1.1.1.2 ! root 33: * from: @(#)ufs_inode.c 7.40 (Berkeley) 5/8/91
! 34: * ufs_inode.c,v 1.4.2.1 1993/07/31 12:10:46 cgd Exp
1.1 root 35: */
36:
37: #include "param.h"
38: #include "systm.h"
39: #include "mount.h"
40: #include "proc.h"
41: #include "file.h"
42: #include "buf.h"
43: #include "vnode.h"
44: #include "kernel.h"
45: #include "malloc.h"
46:
47: #include "quota.h"
48: #include "inode.h"
49: #include "fs.h"
50: #include "ufsmount.h"
51:
52: #define INOHSZ 512
53: #if ((INOHSZ&(INOHSZ-1)) == 0)
54: #define INOHASH(dev,ino) (((dev)+(ino))&(INOHSZ-1))
55: #else
56: #define INOHASH(dev,ino) (((unsigned)((dev)+(ino)))%INOHSZ)
57: #endif
58:
59: union ihead {
60: union ihead *ih_head[2];
61: struct inode *ih_chain[2];
62: } ihead[INOHSZ];
63:
64: int prtactive; /* 1 => print out reclaim of active vnodes */
65:
66: /*
67: * Initialize hash links for inodes.
68: */
69: ufs_init()
70: {
71: register int i;
72: register union ihead *ih = ihead;
73:
74: #ifndef lint
75: if (VN_MAXPRIVATE < sizeof(struct inode))
76: panic("ihinit: too small");
77: #endif /* not lint */
78: for (i = INOHSZ; --i >= 0; ih++) {
79: ih->ih_head[0] = ih;
80: ih->ih_head[1] = ih;
81: }
82: #ifdef QUOTA
83: dqinit();
84: #endif /* QUOTA */
85: }
86:
87: /*
88: * Look up a UFS dinode number to find its incore vnode.
89: * If it is not in core, read it in from the specified device.
90: * If it is in core, wait for the lock bit to clear, then
91: * return the inode locked. Detection and handling of mount
92: * points must be done by the calling routine.
93: */
94: iget(xp, ino, ipp)
95: struct inode *xp;
96: ino_t ino;
97: struct inode **ipp;
98: {
99: dev_t dev = xp->i_dev;
100: struct mount *mntp = ITOV(xp)->v_mount;
101: register struct fs *fs = VFSTOUFS(mntp)->um_fs;
102: extern struct vnodeops ufs_vnodeops, spec_inodeops;
103: register struct inode *ip, *iq;
104: register struct vnode *vp;
105: struct vnode *nvp;
106: struct buf *bp;
107: struct dinode *dp;
108: union ihead *ih;
109: int i, error;
110:
111: ih = &ihead[INOHASH(dev, ino)];
112: loop:
113: for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw) {
114: if (ino != ip->i_number || dev != ip->i_dev)
115: continue;
116: if ((ip->i_flag&ILOCKED) != 0) {
117: ip->i_flag |= IWANT;
1.1.1.2 ! root 118: tsleep((caddr_t)ip, PINOD, "iget", 0);
1.1 root 119: goto loop;
120: }
121: if (vget(ITOV(ip)))
122: goto loop;
123: *ipp = ip;
124: return(0);
125: }
126: /*
127: * Allocate a new inode.
128: */
129: if (error = getnewvnode(VT_UFS, mntp, &ufs_vnodeops, &nvp)) {
130: *ipp = 0;
131: return (error);
132: }
133: ip = VTOI(nvp);
134: ip->i_vnode = nvp;
135: ip->i_flag = 0;
136: ip->i_devvp = 0;
137: ip->i_mode = 0;
138: ip->i_diroff = 0;
139: ip->i_lockf = 0;
140: #ifdef QUOTA
141: for (i = 0; i < MAXQUOTAS; i++)
142: ip->i_dquot[i] = NODQUOT;
143: #endif
1.1.1.2 ! root 144:
! 145: /*
! 146: * XXX:
! 147: * This is done here to try to force existing inodes to have blank
! 148: * spare fields. It should eventually be removed.
! 149: */
! 150: for (i=0; i < DI_SPARE_SZ; i++)
! 151: ip->i_di_spare[i] = (unsigned long)0L;
! 152: if (!FASTLINK(ip))
! 153: ip->i_fsize = (unsigned long)0L;
! 154:
1.1 root 155: /*
156: * Put it onto its hash chain and lock it so that other requests for
157: * this inode will block if they arrive while we are sleeping waiting
158: * for old data structures to be purged or for the contents of the
159: * disk portion of this inode to be read.
160: */
161: ip->i_dev = dev;
162: ip->i_number = ino;
163: insque(ip, ih);
164: ILOCK(ip);
165: /*
166: * Read in the disk contents for the inode.
167: */
168: if (error = bread(VFSTOUFS(mntp)->um_devvp, fsbtodb(fs, itod(fs, ino)),
169: (int)fs->fs_bsize, NOCRED, &bp)) {
170: /*
171: * The inode does not contain anything useful, so it would
172: * be misleading to leave it on its hash chain.
173: * Iput() will take care of putting it back on the free list.
174: */
175: remque(ip);
176: ip->i_forw = ip;
177: ip->i_back = ip;
178: /*
179: * Unlock and discard unneeded inode.
180: */
181: iput(ip);
182: brelse(bp);
183: *ipp = 0;
184: return (error);
185: }
186: dp = bp->b_un.b_dino;
187: dp += itoo(fs, ino);
188: ip->i_din = *dp;
189: brelse(bp);
190: /*
191: * Initialize the associated vnode
192: */
193: vp = ITOV(ip);
194: vp->v_type = IFTOVT(ip->i_mode);
195: if (vp->v_type == VFIFO) {
196: #ifdef FIFO
197: extern struct vnodeops fifo_inodeops;
198: vp->v_op = &fifo_inodeops;
199: #else
200: iput(ip);
201: *ipp = 0;
202: return (EOPNOTSUPP);
203: #endif /* FIFO */
204: }
205: if (vp->v_type == VCHR || vp->v_type == VBLK) {
206: vp->v_op = &spec_inodeops;
207: if (nvp = checkalias(vp, ip->i_rdev, mntp)) {
208: /*
209: * Reinitialize aliased inode.
210: */
211: vp = nvp;
212: iq = VTOI(vp);
213: iq->i_vnode = vp;
214: iq->i_flag = 0;
215: ILOCK(iq);
216: iq->i_din = ip->i_din;
217: iq->i_dev = dev;
218: iq->i_number = ino;
219: insque(iq, ih);
220: /*
221: * Discard unneeded vnode
222: */
223: ip->i_mode = 0;
224: iput(ip);
225: ip = iq;
226: }
227: }
228: if (ino == ROOTINO)
229: vp->v_flag |= VROOT;
230: /*
231: * Finish inode initialization.
232: */
233: ip->i_fs = fs;
234: ip->i_devvp = VFSTOUFS(mntp)->um_devvp;
235: VREF(ip->i_devvp);
236: /*
237: * Set up a generation number for this inode if it does not
238: * already have one. This should only happen on old filesystems.
239: */
240: if (ip->i_gen == 0) {
241: if (++nextgennumber < (u_long)time.tv_sec)
242: nextgennumber = time.tv_sec;
243: ip->i_gen = nextgennumber;
244: if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
245: ip->i_flag |= IMOD;
246: }
247: *ipp = ip;
248: return (0);
249: }
250:
251: /*
252: * Unlock and decrement the reference count of an inode structure.
253: */
254: iput(ip)
255: register struct inode *ip;
256: {
257:
258: if ((ip->i_flag & ILOCKED) == 0)
259: panic("iput");
260: IUNLOCK(ip);
261: vrele(ITOV(ip));
262: }
263:
264: /*
265: * Last reference to an inode, write the inode out and if necessary,
266: * truncate and deallocate the file.
267: */
268: ufs_inactive(vp, p)
269: struct vnode *vp;
270: struct proc *p;
271: {
272: register struct inode *ip = VTOI(vp);
273: int mode, error = 0;
274:
275: if (prtactive && vp->v_usecount != 0)
276: vprint("ufs_inactive: pushing active", vp);
277: /*
278: * Get rid of inodes related to stale file handles.
279: */
280: if (ip->i_mode == 0) {
281: if ((vp->v_flag & VXLOCK) == 0)
282: vgone(vp);
283: return (0);
284: }
285: ILOCK(ip);
286: if (ip->i_nlink <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
287: #ifdef QUOTA
288: if (!getinoquota(ip))
289: (void) chkiq(ip, -1, NOCRED, 0);
290: #endif
291: error = itrunc(ip, (u_long)0, 0);
292: mode = ip->i_mode;
293: ip->i_mode = 0;
294: ip->i_rdev = 0;
295: ip->i_flag |= IUPD|ICHG;
296: ifree(ip, ip->i_number, mode);
297: }
298: IUPDAT(ip, &time, &time, 0);
299: IUNLOCK(ip);
300: ip->i_flag = 0;
301: /*
302: * If we are done with the inode, reclaim it
303: * so that it can be reused immediately.
304: */
305: if (vp->v_usecount == 0 && ip->i_mode == 0)
306: vgone(vp);
307: return (error);
308: }
309:
310: /*
311: * Reclaim an inode so that it can be used for other purposes.
312: */
313: ufs_reclaim(vp)
314: register struct vnode *vp;
315: {
316: register struct inode *ip = VTOI(vp);
317: int i;
318:
319: if (prtactive && vp->v_usecount != 0)
320: vprint("ufs_reclaim: pushing active", vp);
321: /*
322: * Remove the inode from its hash chain.
323: */
324: remque(ip);
325: ip->i_forw = ip;
326: ip->i_back = ip;
327: /*
328: * Purge old data structures associated with the inode.
329: */
330: cache_purge(vp);
331: if (ip->i_devvp) {
332: vrele(ip->i_devvp);
333: ip->i_devvp = 0;
334: }
335: #ifdef QUOTA
336: for (i = 0; i < MAXQUOTAS; i++) {
337: if (ip->i_dquot[i] != NODQUOT) {
338: dqrele(vp, ip->i_dquot[i]);
339: ip->i_dquot[i] = NODQUOT;
340: }
341: }
342: #endif
343: ip->i_flag = 0;
344: return (0);
345: }
346:
347: /*
348: * Update the access, modified, and inode change times as specified
349: * by the IACC, IMOD, and ICHG flags respectively. The IUPD flag
350: * is used to specify that the inode needs to be updated but that
351: * the times have already been set. The access and modified times
352: * are taken from the second and third parameters; the inode change
353: * time is always taken from the current time. If waitfor is set,
354: * then wait for the disk write of the inode to complete.
355: */
356: iupdat(ip, ta, tm, waitfor)
357: register struct inode *ip;
358: struct timeval *ta, *tm;
359: int waitfor;
360: {
361: struct buf *bp;
362: struct vnode *vp = ITOV(ip);
363: struct dinode *dp;
364: register struct fs *fs;
365: int error;
366:
367: fs = ip->i_fs;
368: if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) == 0)
369: return (0);
370: if (vp->v_mount->mnt_flag & MNT_RDONLY)
371: return (0);
372: error = bread(ip->i_devvp, fsbtodb(fs, itod(fs, ip->i_number)),
373: (int)fs->fs_bsize, NOCRED, &bp);
374: if (error) {
375: brelse(bp);
376: return (error);
377: }
378: if (ip->i_flag&IACC)
379: ip->i_atime = ta->tv_sec;
380: if (ip->i_flag&IUPD)
381: ip->i_mtime = tm->tv_sec;
382: if (ip->i_flag&ICHG)
383: ip->i_ctime = time.tv_sec;
384: ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD);
385: dp = bp->b_un.b_dino + itoo(fs, ip->i_number);
386: *dp = ip->i_din;
387: if (waitfor) {
388: return (bwrite(bp));
389: } else {
390: bdwrite(bp);
391: return (0);
392: }
393: }
394:
395: #define SINGLE 0 /* index of single indirect block */
396: #define DOUBLE 1 /* index of double indirect block */
397: #define TRIPLE 2 /* index of triple indirect block */
398: /*
399: * Truncate the inode ip to at most length size. Free affected disk
400: * blocks -- the blocks of the file are removed in reverse order.
401: *
402: * NB: triple indirect blocks are untested.
403: */
404: itrunc(oip, length, flags)
405: register struct inode *oip;
406: u_long length;
407: int flags;
408: {
409: register daddr_t lastblock;
410: daddr_t bn, lbn, lastiblock[NIADDR];
411: register struct fs *fs;
412: register struct inode *ip;
413: struct buf *bp;
414: int offset, osize, size, level;
415: long count, nblocks, blocksreleased = 0;
416: register int i;
417: int aflags, error, allerror;
418: struct inode tip;
419:
420: vnode_pager_setsize(ITOV(oip), length);
1.1.1.2 ! root 421: if (FASTLINK(oip)) {
! 422: if (length != 0)
! 423: panic("itrunc fastlink to non-zero");
! 424: bzero(oip->i_symlink, MAXFASTLINK);
! 425: oip->i_size = 0;
! 426: oip->i_din.di_spare[0] = 0;
! 427: }
1.1 root 428: if (oip->i_size <= length) {
429: oip->i_flag |= ICHG|IUPD;
430: error = iupdat(oip, &time, &time, 1);
431: return (error);
432: }
433: /*
434: * Calculate index into inode's block list of
435: * last direct and indirect blocks (if any)
436: * which we want to keep. Lastblock is -1 when
437: * the file is truncated to 0.
438: */
439: fs = oip->i_fs;
440: lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1;
441: lastiblock[SINGLE] = lastblock - NDADDR;
442: lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs);
443: lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs);
444: nblocks = btodb(fs->fs_bsize);
445: /*
446: * Update the size of the file. If the file is not being
447: * truncated to a block boundry, the contents of the
448: * partial block following the end of the file must be
449: * zero'ed in case it ever become accessable again because
450: * of subsequent file growth.
451: */
452: osize = oip->i_size;
453: offset = blkoff(fs, length);
454: if (offset == 0) {
455: oip->i_size = length;
456: } else {
457: lbn = lblkno(fs, length);
458: aflags = B_CLRBUF;
459: if (flags & IO_SYNC)
460: aflags |= B_SYNC;
461: #ifdef QUOTA
462: if (error = getinoquota(oip))
463: return (error);
464: #endif
465: if (error = balloc(oip, lbn, offset, &bp, aflags))
466: return (error);
467: oip->i_size = length;
468: size = blksize(fs, oip, lbn);
469: (void) vnode_pager_uncache(ITOV(oip));
470: bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset));
471: allocbuf(bp, size);
472: if (flags & IO_SYNC)
473: bwrite(bp);
474: else
475: bdwrite(bp);
476: }
477: /*
478: * Update file and block pointers
479: * on disk before we start freeing blocks.
480: * If we crash before free'ing blocks below,
481: * the blocks will be returned to the free list.
482: * lastiblock values are also normalized to -1
483: * for calls to indirtrunc below.
484: */
485: tip = *oip;
486: tip.i_size = osize;
487: for (level = TRIPLE; level >= SINGLE; level--)
488: if (lastiblock[level] < 0) {
489: oip->i_ib[level] = 0;
490: lastiblock[level] = -1;
491: }
492: for (i = NDADDR - 1; i > lastblock; i--)
493: oip->i_db[i] = 0;
494: oip->i_flag |= ICHG|IUPD;
495: vinvalbuf(ITOV(oip), (length > 0));
496: allerror = iupdat(oip, &time, &time, MNT_WAIT);
497:
498: /*
499: * Indirect blocks first.
500: */
501: ip = &tip;
502: for (level = TRIPLE; level >= SINGLE; level--) {
503: bn = ip->i_ib[level];
504: if (bn != 0) {
505: error = indirtrunc(ip, bn, lastiblock[level], level,
506: &count);
507: if (error)
508: allerror = error;
509: blocksreleased += count;
510: if (lastiblock[level] < 0) {
511: ip->i_ib[level] = 0;
512: blkfree(ip, bn, (off_t)fs->fs_bsize);
513: blocksreleased += nblocks;
514: }
515: }
516: if (lastiblock[level] >= 0)
517: goto done;
518: }
519:
520: /*
521: * All whole direct blocks or frags.
522: */
523: for (i = NDADDR - 1; i > lastblock; i--) {
524: register off_t bsize;
525:
526: bn = ip->i_db[i];
527: if (bn == 0)
528: continue;
529: ip->i_db[i] = 0;
530: bsize = (off_t)blksize(fs, ip, i);
531: blkfree(ip, bn, bsize);
532: blocksreleased += btodb(bsize);
533: }
534: if (lastblock < 0)
535: goto done;
536:
537: /*
538: * Finally, look for a change in size of the
539: * last direct block; release any frags.
540: */
541: bn = ip->i_db[lastblock];
542: if (bn != 0) {
543: off_t oldspace, newspace;
544:
545: /*
546: * Calculate amount of space we're giving
547: * back as old block size minus new block size.
548: */
549: oldspace = blksize(fs, ip, lastblock);
550: ip->i_size = length;
551: newspace = blksize(fs, ip, lastblock);
552: if (newspace == 0)
553: panic("itrunc: newspace");
554: if (oldspace - newspace > 0) {
555: /*
556: * Block number of space to be free'd is
557: * the old block # plus the number of frags
558: * required for the storage we're keeping.
559: */
560: bn += numfrags(fs, newspace);
561: blkfree(ip, bn, oldspace - newspace);
562: blocksreleased += btodb(oldspace - newspace);
563: }
564: }
565: done:
566: /* BEGIN PARANOIA */
567: for (level = SINGLE; level <= TRIPLE; level++)
568: if (ip->i_ib[level] != oip->i_ib[level])
569: panic("itrunc1");
570: for (i = 0; i < NDADDR; i++)
571: if (ip->i_db[i] != oip->i_db[i])
572: panic("itrunc2");
573: /* END PARANOIA */
574: oip->i_blocks -= blocksreleased;
575: if (oip->i_blocks < 0) /* sanity */
576: oip->i_blocks = 0;
577: oip->i_flag |= ICHG;
578: #ifdef QUOTA
579: if (!getinoquota(oip))
580: (void) chkdq(oip, -blocksreleased, NOCRED, 0);
581: #endif
582: return (allerror);
583: }
584:
585: /*
586: * Release blocks associated with the inode ip and
587: * stored in the indirect block bn. Blocks are free'd
588: * in LIFO order up to (but not including) lastbn. If
589: * level is greater than SINGLE, the block is an indirect
590: * block and recursive calls to indirtrunc must be used to
591: * cleanse other indirect blocks.
592: *
593: * NB: triple indirect blocks are untested.
594: */
595: indirtrunc(ip, bn, lastbn, level, countp)
596: register struct inode *ip;
597: daddr_t bn, lastbn;
598: int level;
599: long *countp;
600: {
601: register int i;
602: struct buf *bp;
603: register struct fs *fs = ip->i_fs;
604: register daddr_t *bap;
605: daddr_t *copy, nb, last;
606: long blkcount, factor;
607: int nblocks, blocksreleased = 0;
608: int error, allerror = 0;
609:
610: /*
611: * Calculate index in current block of last
612: * block to be kept. -1 indicates the entire
613: * block so we need not calculate the index.
614: */
615: factor = 1;
616: for (i = SINGLE; i < level; i++)
617: factor *= NINDIR(fs);
618: last = lastbn;
619: if (lastbn > 0)
620: last /= factor;
621: nblocks = btodb(fs->fs_bsize);
622: /*
623: * Get buffer of block pointers, zero those
624: * entries corresponding to blocks to be free'd,
625: * and update on disk copy first.
626: */
627: error = bread(ip->i_devvp, fsbtodb(fs, bn), (int)fs->fs_bsize,
628: NOCRED, &bp);
629: if (error) {
630: brelse(bp);
631: *countp = 0;
632: return (error);
633: }
634: bap = bp->b_un.b_daddr;
635: MALLOC(copy, daddr_t *, fs->fs_bsize, M_TEMP, M_WAITOK);
636: bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->fs_bsize);
637: bzero((caddr_t)&bap[last + 1],
638: (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t));
639: if (last == -1)
640: bp->b_flags |= B_INVAL;
641: error = bwrite(bp);
642: if (error)
643: allerror = error;
644: bap = copy;
645:
646: /*
647: * Recursively free totally unused blocks.
648: */
649: for (i = NINDIR(fs) - 1; i > last; i--) {
650: nb = bap[i];
651: if (nb == 0)
652: continue;
653: if (level > SINGLE) {
654: error = indirtrunc(ip, nb, (daddr_t)-1, level - 1,
655: &blkcount);
656: if (error)
657: allerror = error;
658: blocksreleased += blkcount;
659: }
660: blkfree(ip, nb, (off_t)fs->fs_bsize);
661: blocksreleased += nblocks;
662: }
663:
664: /*
665: * Recursively free last partial block.
666: */
667: if (level > SINGLE && lastbn >= 0) {
668: last = lastbn % factor;
669: nb = bap[i];
670: if (nb != 0) {
671: error = indirtrunc(ip, nb, last, level - 1, &blkcount);
672: if (error)
673: allerror = error;
674: blocksreleased += blkcount;
675: }
676: }
677: FREE(copy, M_TEMP);
678: *countp = blocksreleased;
679: return (allerror);
680: }
681:
682: /*
683: * Lock an inode. If its already locked, set the WANT bit and sleep.
684: */
685: ilock(ip)
686: register struct inode *ip;
687: {
688:
689: while (ip->i_flag & ILOCKED) {
690: ip->i_flag |= IWANT;
691: if (ip->i_spare0 == curproc->p_pid)
692: panic("locking against myself");
693: ip->i_spare1 = curproc->p_pid;
1.1.1.2 ! root 694: (void) tsleep((caddr_t)ip, PINOD, "ilock", 0);
1.1 root 695: }
696: ip->i_spare1 = 0;
697: ip->i_spare0 = curproc->p_pid;
698: ip->i_flag |= ILOCKED;
699: }
700:
701: /*
702: * Unlock an inode. If WANT bit is on, wakeup.
703: */
704: iunlock(ip)
705: register struct inode *ip;
706: {
707:
708: if ((ip->i_flag & ILOCKED) == 0)
709: vprint("iunlock: unlocked inode", ITOV(ip));
710: ip->i_spare0 = 0;
711: ip->i_flag &= ~ILOCKED;
712: if (ip->i_flag&IWANT) {
713: ip->i_flag &= ~IWANT;
714: wakeup((caddr_t)ip);
715: }
716: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.