X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/a3a9487d7c80fac9d6da8d126b0c7f36eb233a2b..ec67a3ceda66aa86254f7b83e41d127ac95e7622:/usr/src/sys/ufs/ffs/ufs_inode.c diff --git a/usr/src/sys/ufs/ffs/ufs_inode.c b/usr/src/sys/ufs/ffs/ufs_inode.c index 0af7c31b7a..c72684c27e 100644 --- a/usr/src/sys/ufs/ffs/ufs_inode.c +++ b/usr/src/sys/ufs/ffs/ufs_inode.c @@ -1,20 +1,26 @@ -/* ufs_inode.c 4.33 83/02/10 */ - -#include "../h/param.h" -#include "../h/systm.h" -#include "../h/mount.h" -#include "../h/dir.h" -#include "../h/user.h" -#include "../h/inode.h" -#include "../h/fs.h" -#include "../h/conf.h" -#include "../h/buf.h" +/* + * Copyright (c) 1982, 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)ufs_inode.c 7.1.1.1 (Berkeley) %G% + */ + +#include "param.h" +#include "systm.h" +#include "mount.h" +#include "dir.h" +#include "user.h" +#include "inode.h" +#include "fs.h" +#include "buf.h" +#include "cmap.h" #ifdef QUOTA -#include "../h/quota.h" +#include "quota.h" #endif -#include "../h/kernel.h" +#include "kernel.h" -#define INOHSZ 63 +#define INOHSZ 512 #if ((INOHSZ&(INOHSZ-1)) == 0) #define INOHASH(dev,ino) (((dev)+(ino))&(INOHSZ-1)) #else @@ -109,11 +115,16 @@ iget(dev, fs, ino) register struct inode *iq; loop: - if (getfs(dev) != fs) - panic("iget: bad fs"); ih = &ihead[INOHASH(dev, ino)]; for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw) if (ino == ip->i_number && dev == ip->i_dev) { + /* + * Following is essentially an inline expanded + * copy of igrab(), expanded inline for speed, + * and so that the test for a mounted on inode + * can be deferred until after we are sure that + * the inode isn't busy. + */ if ((ip->i_flag&ILOCKED) != 0) { ip->i_flag |= IWANT; sleep((caddr_t)ip, PINOD); @@ -148,6 +159,8 @@ loop: u.u_error = ENFILE; return(NULL); } + if (ip->i_count) + panic("free inode isn't"); if (iq = ip->i_freef) iq->i_freeb = &ifreeh; ifreeh = iq; @@ -162,16 +175,22 @@ loop: */ remque(ip); insque(ip, ih); -#ifdef QUOTA - dqrele(ip->i_dquot); -#endif ip->i_dev = dev; ip->i_fs = fs; ip->i_number = ino; + cacheinval(ip); ip->i_flag = ILOCKED; ip->i_count++; ip->i_lastr = 0; +#ifdef QUOTA + dqrele(ip->i_dquot); +#endif +#ifdef SECSIZE + bp = bread(dev, fsbtodb(fs, itod(fs, ino)), (int)fs->fs_bsize, + fs->fs_dbsize); +#else SECSIZE bp = bread(dev, fsbtodb(fs, itod(fs, ino)), (int)fs->fs_bsize); +#endif SECSIZE /* * Check I/O errors */ @@ -211,6 +230,36 @@ loop: return (ip); } +/* + * Convert a pointer to an inode into a reference to an inode. + * + * This is basically the internal piece of iget (after the + * inode pointer is located) but without the test for mounted + * filesystems. It is caller's responsibility to check that + * the inode pointer is valid. + */ +igrab(ip) + register struct inode *ip; +{ + while ((ip->i_flag&ILOCKED) != 0) { + ip->i_flag |= IWANT; + sleep((caddr_t)ip, PINOD); + } + if (ip->i_count == 0) { /* ino on free list */ + register struct inode *iq; + + if (iq = ip->i_freef) + iq->i_freeb = ip->i_freeb; + else + ifreet = ip->i_freeb; + *ip->i_freeb = iq; + ip->i_freef = NULL; + ip->i_freeb = NULL; + } + ip->i_count++; + ip->i_flag |= ILOCKED; +} + /* * Decrement reference count of * an inode structure. @@ -224,7 +273,7 @@ iput(ip) if ((ip->i_flag & ILOCKED) == 0) panic("iput"); - iunlock(ip); + IUNLOCK(ip); irele(ip); } @@ -235,7 +284,7 @@ irele(ip) if (ip->i_count == 1) { ip->i_flag |= ILOCKED; - if (ip->i_nlink <= 0) { + if (ip->i_nlink <= 0 && ip->i_fs->fs_ronly == 0) { itrunc(ip, (u_long)0); mode = ip->i_mode; ip->i_mode = 0; @@ -243,13 +292,13 @@ irele(ip) ip->i_flag |= IUPD|ICHG; ifree(ip, ip->i_number, mode); #ifdef QUOTA - (void)chkiq(ip->i_dev, ip, ip->i_uid, 0); + (void) chkiq(ip->i_dev, ip, ip->i_uid, 0); dqrele(ip->i_dquot); ip->i_dquot = NODQUOT; #endif } IUPDAT(ip, &time, &time, 0); - iunlock(ip); + IUNLOCK(ip); ip->i_flag = 0; /* * Put the inode on the end of the free list. @@ -270,7 +319,8 @@ irele(ip) } ip->i_freef = NULL; ifreet = &ip->i_freef; - } + } else if (!(ip->i_flag & ILOCKED)) + ITIMES(ip, &time, &time); ip->i_count--; } @@ -289,14 +339,19 @@ iupdat(ip, ta, tm, waitfor) { register struct buf *bp; struct dinode *dp; - register struct fs *fp; + register struct fs *fs; - fp = ip->i_fs; - if ((ip->i_flag & (IUPD|IACC|ICHG)) != 0) { - if (fp->fs_ronly) + fs = ip->i_fs; + if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) != 0) { + if (fs->fs_ronly) return; - bp = bread(ip->i_dev, fsbtodb(fp, itod(fp, ip->i_number)), - (int)fp->fs_bsize); +#ifdef SECSIZE + bp = bread(ip->i_dev, fsbtodb(fs, itod(fs, ip->i_number)), + (int)fs->fs_bsize, fs->fs_dbsize); +#else SECSIZE + bp = bread(ip->i_dev, fsbtodb(fs, itod(fs, ip->i_number)), + (int)fs->fs_bsize); +#endif SECSIZE if (bp->b_flags & B_ERROR) { brelse(bp); return; @@ -307,8 +362,8 @@ iupdat(ip, ta, tm, waitfor) ip->i_mtime = tm->tv_sec; if (ip->i_flag&ICHG) ip->i_ctime = time.tv_sec; - ip->i_flag &= ~(IUPD|IACC|ICHG); - dp = bp->b_un.b_dino + itoo(fp, ip->i_number); + ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD); + dp = bp->b_un.b_dino + itoo(fs, ip->i_number); dp->di_ic = ip->i_ic; if (waitfor) bwrite(bp); @@ -329,23 +384,26 @@ iupdat(ip, ta, tm, waitfor) * NB: triple indirect blocks are untested. */ itrunc(oip, length) - struct inode *oip; + register struct inode *oip; u_long length; { - register i; register daddr_t lastblock; - daddr_t bn, lastiblock[NIADDR]; + daddr_t bn, lbn, lastiblock[NIADDR]; register struct fs *fs; register struct inode *ip; + struct buf *bp; + int offset, osize, size, count, level; + long nblocks, blocksreleased = 0; + register int i; + dev_t dev; struct inode tip; - int level; -#ifdef QUOTA - long blocksreleased = 0, nblocks; - long indirtrunc(); -#endif + extern long indirtrunc(); - if (oip->i_size <= length) + if (oip->i_size <= length) { + oip->i_flag |= ICHG|IUPD; + iupdat(oip, &time, &time, 1); return; + } /* * Calculate index into inode's block list of * last direct and indirect blocks (if any) @@ -357,19 +415,53 @@ itrunc(oip, length) lastiblock[SINGLE] = lastblock - NDADDR; lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs); lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs); -#ifdef QUOTA - nblocks = fs->fs_bsize / DEV_BSIZE; -#endif + nblocks = btodb(fs->fs_bsize); /* - * Update size of file and block pointers + * Update the size of the file. If the file is not being + * truncated to a block boundry, the contents of the + * partial block following the end of the file must be + * zero'ed in case it ever become accessable again because + * of subsequent file growth. + */ + osize = oip->i_size; + offset = blkoff(fs, length); + if (offset == 0) { + oip->i_size = length; + } else { + lbn = lblkno(fs, length); + bn = fsbtodb(fs, bmap(oip, lbn, B_WRITE, offset)); + if (u.u_error || (long)bn < 0) + return; + oip->i_size = length; + size = blksize(fs, oip, lbn); + count = howmany(size, CLBYTES); + dev = oip->i_dev; + for (i = 0; i < count; i++) +#ifdef SECSIZE + munhash(dev, bn + i * CLBYTES / fs->fs_dbsize); +#else SECSIZE + munhash(dev, bn + i * CLBYTES / DEV_BSIZE); +#endif SECSIZE + bp = bread(dev, bn, size); + if (bp->b_flags & B_ERROR) { + u.u_error = EIO; + oip->i_size = osize; + brelse(bp); + return; + } + bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset)); + bdwrite(bp); + } + /* + * Update file and block pointers * on disk before we start freeing blocks. * If we crash before free'ing blocks below, * the blocks will be returned to the free list. * lastiblock values are also normalized to -1 * for calls to indirtrunc below. - * (? fsck doesn't check validity of pointers in indirect blocks) */ tip = *oip; + tip.i_size = osize; for (level = TRIPLE; level >= SINGLE; level--) if (lastiblock[level] < 0) { oip->i_ib[level] = 0; @@ -377,27 +469,22 @@ itrunc(oip, length) } for (i = NDADDR - 1; i > lastblock; i--) oip->i_db[i] = 0; - oip->i_size = length; oip->i_flag |= ICHG|IUPD; - iupdat(oip, &time, &time, 1); - ip = &tip; + syncip(oip); /* * Indirect blocks first. */ + ip = &tip; for (level = TRIPLE; level >= SINGLE; level--) { bn = ip->i_ib[level]; if (bn != 0) { -#ifdef QUOTA blocksreleased += -#endif - indirtrunc(ip, bn, lastiblock[level], level); + indirtrunc(ip, bn, lastiblock[level], level); if (lastiblock[level] < 0) { ip->i_ib[level] = 0; free(ip, bn, (off_t)fs->fs_bsize); -#ifdef QUOTA blocksreleased += nblocks; -#endif } } if (lastiblock[level] >= 0) @@ -408,17 +495,15 @@ itrunc(oip, length) * All whole direct blocks or frags. */ for (i = NDADDR - 1; i > lastblock; i--) { - register int size; + register off_t bsize; bn = ip->i_db[i]; if (bn == 0) continue; ip->i_db[i] = 0; - size = (off_t)blksize(fs, ip, i); - free(ip, bn, size); -#ifdef QUOTA - blocksreleased += size / DEV_BSIZE; -#endif + bsize = (off_t)blksize(fs, ip, i); + free(ip, bn, bsize); + blocksreleased += btodb(bsize); } if (lastblock < 0) goto done; @@ -429,7 +514,7 @@ itrunc(oip, length) */ bn = ip->i_db[lastblock]; if (bn != 0) { - int oldspace, newspace; + off_t oldspace, newspace; /* * Calculate amount of space we're giving @@ -448,9 +533,7 @@ itrunc(oip, length) */ bn += numfrags(fs, newspace); free(ip, bn, oldspace - newspace); -#ifdef QUOTA - blocksreleased += (oldspace - newspace) / DEV_BSIZE; -#endif + blocksreleased += btodb(oldspace - newspace); } } done: @@ -462,8 +545,12 @@ done: if (ip->i_db[i] != oip->i_db[i]) panic("itrunc2"); /* END PARANOIA */ + oip->i_blocks -= blocksreleased; + if (oip->i_blocks < 0) /* sanity */ + oip->i_blocks = 0; + oip->i_flag |= ICHG; #ifdef QUOTA - (void) chkdq(ip, -blocksreleased, 0); + (void) chkdq(oip, -blocksreleased, 0); #endif } @@ -477,9 +564,7 @@ done: * * NB: triple indirect blocks are untested. */ -#ifdef QUOTA long -#endif indirtrunc(ip, bn, lastbn, level) register struct inode *ip; daddr_t bn, lastbn; @@ -491,9 +576,7 @@ indirtrunc(ip, bn, lastbn, level) register struct fs *fs = ip->i_fs; daddr_t nb, last; long factor; -#ifdef QUOTA int blocksreleased = 0, nblocks; -#endif /* * Calculate index in current block of last @@ -506,22 +589,23 @@ indirtrunc(ip, bn, lastbn, level) last = lastbn; if (lastbn > 0) last /= factor; -#ifdef QUOTA - nblocks = fs->fs_bsize / DEV_BSIZE; -#endif + nblocks = btodb(fs->fs_bsize); /* * Get buffer of block pointers, zero those * entries corresponding to blocks to be free'd, * and update on disk copy first. */ copy = geteblk((int)fs->fs_bsize); +#ifdef SECSIZE + bp = bread(ip->i_dev, fsbtodb(fs, bn), (int)fs->fs_bsize, + fs->fs_dbsize); +#else SECSIZE bp = bread(ip->i_dev, fsbtodb(fs, bn), (int)fs->fs_bsize); +#endif SECSIZE if (bp->b_flags&B_ERROR) { brelse(copy); brelse(bp); -#ifdef QUOTA return (0); -#endif } bap = bp->b_un.b_daddr; bcopy((caddr_t)bap, (caddr_t)copy->b_un.b_daddr, (u_int)fs->fs_bsize); @@ -538,14 +622,10 @@ indirtrunc(ip, bn, lastbn, level) if (nb == 0) continue; if (level > SINGLE) -#ifdef QUOTA blocksreleased += -#endif - indirtrunc(ip, nb, (daddr_t)-1, level - 1); - free(ip, nb, (int)fs->fs_bsize); -#ifdef QUOTA + indirtrunc(ip, nb, (daddr_t)-1, level - 1); + free(ip, nb, (off_t)fs->fs_bsize); blocksreleased += nblocks; -#endif } /* @@ -555,29 +635,17 @@ indirtrunc(ip, bn, lastbn, level) last = lastbn % factor; nb = bap[i]; if (nb != 0) -#ifdef QUOTA - blocksreleased += -#endif - indirtrunc(ip, nb, last, level - 1); + blocksreleased += indirtrunc(ip, nb, last, level - 1); } brelse(bp); -#ifdef QUOTA return (blocksreleased); -#endif } /* - * remove any inodes in the inode cache belonging to dev + * Remove any inodes in the inode cache belonging to dev. * * There should not be any active ones, return error if any are found - * (nb: this is a user error, not a system err) - * - * Also, count the references to dev by block devices - this really - * has nothing to do with the object of the procedure, but as we have - * to scan the inode table here anyway, we might as well get the - * extra benefit. - * - * this is called from sumount()/sys3.c when dev is being unmounted + * (nb: this is a user error, not a system err). */ #ifdef QUOTA iflush(dev, iq) @@ -589,7 +657,6 @@ iflush(dev) #endif { register struct inode *ip; - register open = 0; for (ip = inode; ip < inodeNINODE; ip++) { #ifdef QUOTA @@ -598,7 +665,7 @@ iflush(dev) if (ip->i_dev == dev) #endif if (ip->i_count) - return(-1); + return (EBUSY); else { remque(ip); ip->i_forw = ip; @@ -617,11 +684,8 @@ iflush(dev) ip->i_dquot = NODQUOT; #endif } - else if (ip->i_count && (ip->i_mode&IFMT)==IFBLK && - ip->i_rdev == dev) - open++; } - return (open); + return (0); } /*