-/* ufs_inode.c 6.6 84/07/02 */
-
-#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 64
+#define INOHSZ 512
#if ((INOHSZ&(INOHSZ-1)) == 0)
#define INOHASH(dev,ino) (((dev)+(ino))&(INOHSZ-1))
#else
register struct buf *bp;
register struct dinode *dp;
register struct inode *iq;
- struct inode *xp;
-
loop:
ih = &ihead[INOHASH(dev, ino)];
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;
- ip->i_id = ++nextinodeid; /* also used in rename */
- /*
- * At an absurd rate of 100 calls/second,
- * this should occur once every 8 months.
- */
- if (nextinodeid < 0)
- for (nextinodeid = 0, xp = inode; xp < inodeNINODE; xp++)
- xp->i_id = 0;
+ 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
*/
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;
#endif
}
IUPDAT(ip, &time, &time, 0);
- iunlock(ip);
+ IUNLOCK(ip);
ip->i_flag = 0;
/*
* Put the inode on the end of the free list.
{
register struct buf *bp;
struct dinode *dp;
- register struct fs *fp;
+ register struct fs *fs;
- fp = ip->i_fs;
+ fs = ip->i_fs;
if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) != 0) {
- if (fp->fs_ronly)
+ 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;
if (ip->i_flag&ICHG)
ip->i_ctime = time.tv_sec;
ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD);
- dp = bp->b_un.b_dino + itoo(fp, ip->i_number);
+ 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;
- long blocksreleased = 0, nblocks;
- long indirtrunc();
- int level;
+ extern long indirtrunc();
if (oip->i_size <= length) {
oip->i_flag |= ICHG|IUPD;
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, 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) {
* 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;
*/
bn = ip->i_db[lastblock];
if (bn != 0) {
- int oldspace, newspace;
+ off_t oldspace, newspace;
/*
* Calculate amount of space we're giving
* 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);
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;
}
}
/*
- * 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);
}
/*