-/* 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
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);
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;
*/
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
*/
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.
if ((ip->i_flag & ILOCKED) == 0)
panic("iput");
- iunlock(ip);
+ IUNLOCK(ip);
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;
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.
}
ip->i_freef = NULL;
ifreet = &ip->i_freef;
- }
+ } else if (!(ip->i_flag & ILOCKED))
+ ITIMES(ip, &time, &time);
ip->i_count--;
}
{
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;
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);
* 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)
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;
}
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)
* 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;
*/
bn = ip->i_db[lastblock];
if (bn != 0) {
- int oldspace, newspace;
+ off_t oldspace, newspace;
/*
* Calculate amount of space we're giving
*/
bn += numfrags(fs, newspace);
free(ip, bn, oldspace - newspace);
-#ifdef QUOTA
- blocksreleased += (oldspace - newspace) / DEV_BSIZE;
-#endif
+ blocksreleased += btodb(oldspace - newspace);
}
}
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
}
*
* NB: triple indirect blocks are untested.
*/
-#ifdef QUOTA
long
-#endif
indirtrunc(ip, bn, lastbn, level)
register struct inode *ip;
daddr_t bn, lastbn;
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
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);
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
}
/*
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)
#endif
{
register struct inode *ip;
- register open = 0;
for (ip = inode; ip < inodeNINODE; ip++) {
#ifdef QUOTA
if (ip->i_dev == dev)
#endif
if (ip->i_count)
- return(-1);
+ return (EBUSY);
else {
remque(ip);
ip->i_forw = ip;
ip->i_dquot = NODQUOT;
#endif
}
- else if (ip->i_count && (ip->i_mode&IFMT)==IFBLK &&
- ip->i_rdev == dev)
- open++;
}
- return (open);
+ return (0);
}
/*