📄 ufs_gnode.c
字号:
for (i = 0; i < count; i += CLSIZE) { smp_lock(&lk_cmap, LK_RETRY); if (mfind(ogp->g_dev, bn + i, ogp)) munhash(ogp->g_dev, bn + i, ogp); smp_unlock(&lk_cmap); } splx(s); bp = bread(ogp->g_dev, bn, size, (struct gnode *)0); if (bp->b_flags & B_ERROR) { u.u_error = EIO; ogp->g_size = osize; brelse(bp); return(EIO); } 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. */ tip = *ogp; /* structure copy */ tip.g_size = osize; for (level = TRIPLE; level >= SINGLE; level--) if (lastiblock[level] < 0) { G_TO_I(ogp)->di_ib[level] = 0; lastiblock[level] = -1; } for (i = NDADDR - 1; i > lastblock; i--) { G_TO_I(ogp)->di_db[i] = 0; } ogp->g_size = length; ogp->g_flag |= GCHG|GUPD; ufs_gupdat(ogp, timepick, timepick, 1, (struct ucred *) 0); /* * Indirect blocks first. */ ufs_ip = G_TO_I(&tip); for (level = TRIPLE; level >= SINGLE; level--) { bn = ufs_ip->di_ib[level]; if (bn != 0) { blocksreleased += indirtrunc(&tip, bn, lastiblock[level], level); if (lastiblock[level] < 0) { ufs_ip->di_ib[level] = 0; free(&tip, bn, (off_t)fs->fs_bsize); blocksreleased += nblocks; } } if (lastiblock[level] >= 0) goto done; } /* * All whole direct blocks or frags. */ for (i = NDADDR - 1; i > lastblock; i--) { register int bsize; bn = ufs_ip->di_db[i]; if (bn == 0) continue; ufs_ip->di_db[i] = 0; bsize = (off_t)blksize(fs, &tip, i); free(&tip, bn, bsize); blocksreleased += btodb(bsize); } if (lastblock < 0) goto done; /* * Finally, look for a change in size of the * last direct block; release any frags. */ bn = ufs_ip->di_db[lastblock]; if (bn != 0) { int oldspace, newspace; /* * Calculate amount of space we're giving * back as old block size minus new block size. */ oldspace = blksize(fs, &tip, lastblock); tip.g_size = length; newspace = blksize(fs, &tip, lastblock); if (newspace == 0) panic("ufs_gtrunc: newspace"); if (oldspace - newspace > 0) { /* * Block number of space to be free'd is * the old block # plus the number of frags * required for the storage we're keeping. */ bn += numfrags(fs, newspace); free(&tip, bn, oldspace - newspace); blocksreleased += btodb(oldspace - newspace); } }done:/* BEGIN PARANOIA */ for (level = SINGLE; level <= TRIPLE; level++) if (ufs_ip->di_ib[level] != G_TO_I(ogp)->di_ib[level]) panic("ufs_gtrunc1"); for (i = 0; i < NDADDR; i++) if (ufs_ip->di_db[i] != G_TO_I(ogp)->di_db[i]) panic("ufs_gtrunc2");/* END PARANOIA */ ogp->g_blocks -= blocksreleased; G_TO_I(ogp)->di_blocks = ogp->g_blocks; if (G_TO_I(ogp)->di_blocks < 0) { /* sanity */ ogp->g_blocks = G_TO_I(ogp)->di_blocks = 0; } ogp->g_flag |= GCHG;#ifdef QUOTA (void) chkdq(ogp, -blocksreleased, 0);#endif return(0);}/* * Release blocks associated with the gnode gp and * stored in the indirect block bn. Blocks are free'd * in LIFO order up to (but not including) lastbn. If * level is greater than SINGLE, the block is an indirect * block and recursive calls to indirtrunc must be used to * cleanse other indirect blocks. * * NB: triple indirect blocks are untested. */longindirtrunc(gp, bn, lastbn, level) register struct gnode *gp; daddr_t bn, lastbn; int level;{ register int i; struct buf *bp, *copy; register daddr_t *bap; register struct fs *fs = FS(gp); register daddr_t nb; daddr_t last; register long factor; int blocksreleased = 0, nblocks; /* * Calculate index in current block of last * block to be kept. -1 indicates the entire * block so we need not calculate the index. */ factor = 1;/* printf("indirtrunc: fs 0x%x\n", fs); */ for (i = SINGLE; i < level; i++) factor *= NINDIR(fs); last = lastbn; if (lastbn > 0) last /= factor; 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); bp = bread(gp->g_dev, fsbtodb(fs, bn), (int)fs->fs_bsize, (struct gnode *) NULL); if (bp->b_flags&B_ERROR) { brelse(copy); brelse(bp); return (0); } bap = bp->b_un.b_daddr; bcopy((caddr_t)bap, (caddr_t)copy->b_un.b_daddr, (u_int)fs->fs_bsize); bzero((caddr_t)&bap[last + 1], (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t)); bwrite(bp); bp = copy, bap = bp->b_un.b_daddr; /* * Recursively free totally unused blocks. */ for (i = NINDIR(fs) - 1; i > last; i--) { nb = bap[i]; if (nb == 0) continue; if (level > SINGLE) blocksreleased += indirtrunc(gp, nb, (daddr_t)-1, level - 1); free(gp, nb, (int)fs->fs_bsize); blocksreleased += nblocks; } /* * Recursively free last partial block. */ if (level > SINGLE && lastbn >= 0) { last = lastbn % factor; nb = bap[i]; if (nb != 0) blocksreleased += indirtrunc(gp, nb, last, level - 1); } brelse(bp); return (blocksreleased);}/* * Lock a gnode. If its already locked, set the WANT bit and sleep. */ufs_glock(gp) register struct gnode *gp;{ if (gp->g_mp->m_fstype != GT_ULTRIX) { printf("ufs_glock: gp 0x%x type %d\n", gp, gp->g_mp->m_fstype); panic("ufs_glock: gp type not GT_ULTRIX"); } gfs_lock(gp);}/* * Unlock a gnode. If WANT bit is on, wakeup. */ufs_gunlock(gp) register struct gnode *gp;{ if (!glocked(gp)) { cprintf("ufs_gunlock: gp unlocked, dev 0x%x gno %d\n", gp->g_dev, gp->g_number); panic("ufs_gunlock"); } if (gp->g_mp->m_fstype != GT_ULTRIX) { printf("ufs_gulock: gp 0x%x type %d\n", gp, gp->g_mp->m_fstype); panic("ufs_gulock: gp type not GT_ULTRIX"); } gfs_unlock(gp);}/* * Check accessed and update flags on * a gnode structure. * If any is on, update the gnode * with the appropriate time. * If waitfor is given, then must insure * i/o order so wait for write to complete. */struct timeval guniqtm; /* unique UFS timestamp */extern struct lock_t lk_gnode;extern struct timeval atime;extern struct timeval btime;ufs_gupdat(gp, ta, tm, waitfor, cred) register struct gnode *gp; register struct timeval *ta, *tm; int waitfor; struct ucred *cred;{ register struct buf *bp; register struct ufs_inode *dp; register struct fs *fs; gassert(gp); if ((gp->g_flag & (GUPD|GACC|GCHG|GMOD)) != 0) { fs = FS(gp); G_TO_I(gp)->di_blocks = gp->g_blocks; if (((gp->g_mode & GFMT) == GFCHR) || ((gp->g_mode & GFMT) == GFBLK)) G_TO_I(gp)->di_rdev = gp->g_rdev; if (fs->fs_ronly) return(EROFS); bp = bread(gp->g_dev, fsbtodb(fs, itod(fs, gp->g_number)), (int)fs->fs_bsize, (struct gnode *) NULL); if (bp->b_flags & B_ERROR) { brelse(bp); return(EIO); } if ((gp->g_flag & (GUPD|GACC|GCHG)) != 0) { /* * Mark gnode with the current (unique) timestamp. * We need to synchronize with a spin lock to do this, * lk_gnode seems reasonable to me -- chet. */ smp_lock(&lk_gnode, LK_RETRY); if (timepick->tv_sec > guniqtm.tv_sec || timepick->tv_usec > guniqtm.tv_usec) guniqtm = *(timepick); else guniqtm.tv_usec++; if (gp->g_flag & GACC) { if (ta == &atime || ta == &btime) gp->g_atime = guniqtm; else gp->g_atime= *ta; } if (gp->g_flag & GUPD) { if (tm == &atime || tm == &btime) gp->g_mtime = guniqtm; else gp->g_mtime = *tm; } if (gp->g_flag & GCHG) gp->g_ctime = guniqtm; smp_unlock(&lk_gnode); } gp->g_flag &= ~(GUPD|GACC|GCHG|GMOD); dp = bp->b_un.b_dino + itoo(fs, gp->g_number); bcopy(&G_TO_I(gp)->di_ic, &dp->di_ic, sizeof(struct ufs_inode)); if (waitfor) bwrite(bp); else { if (gp->g_mp->m_flags & M_SYNC) bwrite(bp); else bdwrite(bp); } } return(u.u_error);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -