X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/4da9d0523c15573b1a67a10237a5d9d326307d69..0880b18ef40ee52f08a23527900e6354275bcc33:/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 62bba731f8..23dfa09173 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 6.4 84/05/22 */ - -#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 (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 64 +#define INOHSZ 512 #if ((INOHSZ&(INOHSZ-1)) == 0) #define INOHASH(dev,ino) (((dev)+(ino))&(INOHSZ-1)) #else @@ -112,6 +118,13 @@ loop: 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); @@ -146,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; @@ -160,15 +175,16 @@ 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 bp = bread(dev, fsbtodb(fs, itod(fs, ino)), (int)fs->fs_bsize); /* * Check I/O errors @@ -209,6 +225,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. @@ -222,7 +268,7 @@ iput(ip) if ((ip->i_flag & ILOCKED) == 0) panic("iput"); - iunlock(ip); + IUNLOCK(ip); irele(ip); } @@ -233,7 +279,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; @@ -247,7 +293,7 @@ irele(ip) #endif } IUPDAT(ip, &time, &time, 0); - iunlock(ip); + IUNLOCK(ip); ip->i_flag = 0; /* * Put the inode on the end of the free list. @@ -328,18 +374,21 @@ 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, s; + long nblocks, blocksreleased = 0; + register int i; + dev_t dev; struct inode tip; - long blocksreleased = 0, nblocks; - long indirtrunc(); - int level; + extern long indirtrunc(); + extern struct cmap *mfind(); if (oip->i_size <= length) { oip->i_flag |= ICHG|IUPD; @@ -359,15 +408,50 @@ itrunc(oip, length) lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs); 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, DEV_BSIZE); + dev = oip->i_dev; + s = splimp(); + for (i = 0; i < count; i += CLSIZE) + if (mfind(dev, bn + i)) + munhash(dev, bn + i); + splx(s); + 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; @@ -375,14 +459,13 @@ 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) { @@ -402,15 +485,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); - blocksreleased += btodb(size); + bsize = (off_t)blksize(fs, ip, i); + free(ip, bn, bsize); + blocksreleased += btodb(bsize); } if (lastblock < 0) goto done; @@ -421,7 +504,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 @@ -526,7 +609,7 @@ indirtrunc(ip, bn, lastbn, level) if (level > SINGLE) blocksreleased += indirtrunc(ip, nb, (daddr_t)-1, level - 1); - free(ip, nb, (int)fs->fs_bsize); + free(ip, nb, (off_t)fs->fs_bsize); blocksreleased += nblocks; }