diff options
Diffstat (limited to 'sys/ufs/ffs/ffs_softdep.c')
-rw-r--r-- | sys/ufs/ffs/ffs_softdep.c | 455 |
1 files changed, 351 insertions, 104 deletions
diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c index a1422ac..345bfde 100644 --- a/sys/ufs/ffs/ffs_softdep.c +++ b/sys/ufs/ffs/ffs_softdep.c @@ -54,6 +54,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/kernel.h> #include <sys/systm.h> +#include <sys/stdint.h> #include <sys/bio.h> #include <sys/buf.h> #include <sys/malloc.h> @@ -163,7 +164,8 @@ static void handle_allocdirect_partdone(struct allocdirect *); static void handle_allocindir_partdone(struct allocindir *); static void initiate_write_filepage(struct pagedep *, struct buf *); static void handle_written_mkdir(struct mkdir *, int); -static void initiate_write_inodeblock(struct inodedep *, struct buf *); +static void initiate_write_inodeblock_ufs1(struct inodedep *, struct buf *); +static void initiate_write_inodeblock_ufs2(struct inodedep *, struct buf *); static void handle_workitem_freefile(struct freefile *); static void handle_workitem_remove(struct dirrem *, struct vnode *); static struct dirrem *newdirrem(struct buf *, struct inode *, @@ -171,7 +173,8 @@ static struct dirrem *newdirrem(struct buf *, struct inode *, static void free_diradd(struct diradd *); static void free_allocindir(struct allocindir *, struct inodedep *); static void free_newdirblk(struct newdirblk *); -static int indir_trunc(struct freeblks *, ufs_daddr_t, int, ufs_lbn_t, long *); +static int indir_trunc(struct freeblks *, ufs2_daddr_t, int, ufs_lbn_t, + ufs2_daddr_t *); static void deallocate_dependencies(struct buf *, struct inodedep *); static void free_allocdirect(struct allocdirectlst *, struct allocdirect *, int); @@ -181,14 +184,14 @@ static void handle_workitem_freeblocks(struct freeblks *, int); static void merge_inode_lists(struct inodedep *); static void setup_allocindir_phase2(struct buf *, struct inode *, struct allocindir *); -static struct allocindir *newallocindir(struct inode *, int, ufs_daddr_t, - ufs_daddr_t); +static struct allocindir *newallocindir(struct inode *, int, ufs2_daddr_t, + ufs2_daddr_t); static void handle_workitem_freefrag(struct freefrag *); -static struct freefrag *newfreefrag(struct inode *, ufs_daddr_t, long); +static struct freefrag *newfreefrag(struct inode *, ufs2_daddr_t, long); static void allocdirect_merge(struct allocdirectlst *, struct allocdirect *, struct allocdirect *); static struct bmsafemap *bmsafemap_lookup(struct buf *); -static int newblk_lookup(struct fs *, ufs_daddr_t, int, struct newblk **); +static int newblk_lookup(struct fs *, ufs2_daddr_t, int, struct newblk **); static int inodedep_lookup(struct fs *, ino_t, int, struct inodedep **); static int pagedep_lookup(struct inode *, ufs_lbn_t, int, struct pagedep **); static void pause_timer(void *); @@ -1036,7 +1039,7 @@ top: inodedep->id_ino = inum; inodedep->id_state = ALLCOMPLETE; inodedep->id_nlinkdelta = 0; - inodedep->id_savedino = NULL; + inodedep->id_savedino1 = NULL; inodedep->id_savedsize = -1; inodedep->id_buf = NULL; LIST_INIT(&inodedep->id_pendinghd); @@ -1068,7 +1071,7 @@ static struct sema newblk_in_progress; static int newblk_lookup(fs, newblkno, flags, newblkpp) struct fs *fs; - ufs_daddr_t newblkno; + ufs2_daddr_t newblkno; int flags; struct newblk **newblkpp; { @@ -1139,7 +1142,7 @@ softdep_mount(devvp, mp, fs, cred) struct fs *fs; struct ucred *cred; { - struct csum cstotal; + struct csum_total cstotal; struct cg *cgp; struct buf *bp; int error, cyl; @@ -1246,7 +1249,7 @@ void softdep_setup_blkmapdep(bp, fs, newblkno) struct buf *bp; /* buffer for cylgroup block with block map */ struct fs *fs; /* filesystem doing allocation */ - ufs_daddr_t newblkno; /* number of newly allocated block */ + ufs2_daddr_t newblkno; /* number of newly allocated block */ { struct newblk *newblk; struct bmsafemap *bmsafemap; @@ -1332,8 +1335,8 @@ void softdep_setup_allocdirect(ip, lbn, newblkno, oldblkno, newsize, oldsize, bp) struct inode *ip; /* inode to which block is being added */ ufs_lbn_t lbn; /* block pointer within inode */ - ufs_daddr_t newblkno; /* disk block number being added */ - ufs_daddr_t oldblkno; /* previous block number, 0 unless frag */ + ufs2_daddr_t newblkno; /* disk block number being added */ + ufs2_daddr_t oldblkno; /* previous block number, 0 unless frag */ long newsize; /* size of new block */ long oldsize; /* size of new block */ struct buf *bp; /* bp for allocated block */ @@ -1457,9 +1460,11 @@ allocdirect_merge(adphead, newadp, oldadp) newadp->ad_oldsize != oldadp->ad_newsize || newadp->ad_lbn >= NDADDR) { FREE_LOCK(&lk); - panic("allocdirect_merge: old %d != new %d || lbn %ld >= %d", - newadp->ad_oldblkno, oldadp->ad_newblkno, newadp->ad_lbn, - NDADDR); + panic("%s %lld != new %lld || old size %ld != new %ld", + "allocdirect_merge: old blkno", + (intmax_t)newadp->ad_oldblkno, + (intmax_t)oldadp->ad_newblkno, + newadp->ad_oldsize, oldadp->ad_newsize); } newadp->ad_oldblkno = oldadp->ad_oldblkno; newadp->ad_oldsize = oldadp->ad_oldsize; @@ -1504,7 +1509,7 @@ allocdirect_merge(adphead, newadp, oldadp) static struct freefrag * newfreefrag(ip, blkno, size) struct inode *ip; - ufs_daddr_t blkno; + ufs2_daddr_t blkno; long size; { struct freefrag *freefrag; @@ -1521,7 +1526,6 @@ newfreefrag(ip, blkno, size) freefrag->ff_state = 0; freefrag->ff_inum = ip->i_number; freefrag->ff_mnt = ITOV(ip)->v_mount; - freefrag->ff_devvp = ip->i_devvp; freefrag->ff_blkno = blkno; freefrag->ff_fragsize = size; return (freefrag); @@ -1535,9 +1539,10 @@ static void handle_workitem_freefrag(freefrag) struct freefrag *freefrag; { + struct ufsmount *ump = VFSTOUFS(freefrag->ff_mnt); - ffs_blkfree(VFSTOUFS(freefrag->ff_mnt)->um_fs, freefrag->ff_devvp, - freefrag->ff_blkno, freefrag->ff_fragsize, freefrag->ff_inum); + ffs_blkfree(ump->um_fs, ump->um_devvp, freefrag->ff_blkno, + freefrag->ff_fragsize, freefrag->ff_inum); FREE(freefrag, M_FREEFRAG); } @@ -1573,8 +1578,8 @@ static struct allocindir * newallocindir(ip, ptrno, newblkno, oldblkno) struct inode *ip; /* inode for file being extended */ int ptrno; /* offset of pointer in indirect block */ - ufs_daddr_t newblkno; /* disk block number being added */ - ufs_daddr_t oldblkno; /* previous block number, 0 if none */ + ufs2_daddr_t newblkno; /* disk block number being added */ + ufs2_daddr_t oldblkno; /* previous block number, 0 if none */ { struct allocindir *aip; @@ -1599,8 +1604,8 @@ softdep_setup_allocindir_page(ip, lbn, bp, ptrno, newblkno, oldblkno, nbp) ufs_lbn_t lbn; /* allocated block number within file */ struct buf *bp; /* buffer with indirect blk referencing page */ int ptrno; /* offset of pointer in indirect block */ - ufs_daddr_t newblkno; /* disk block number being added */ - ufs_daddr_t oldblkno; /* previous block number, 0 if none */ + ufs2_daddr_t newblkno; /* disk block number being added */ + ufs2_daddr_t oldblkno; /* previous block number, 0 if none */ struct buf *nbp; /* buffer holding allocated page */ { struct allocindir *aip; @@ -1631,7 +1636,7 @@ softdep_setup_allocindir_meta(nbp, ip, bp, ptrno, newblkno) struct inode *ip; /* inode for file being extended */ struct buf *bp; /* indirect block referencing allocated block */ int ptrno; /* offset of pointer in indirect block */ - ufs_daddr_t newblkno; /* disk block number being added */ + ufs2_daddr_t newblkno; /* disk block number being added */ { struct allocindir *aip; @@ -1658,7 +1663,7 @@ setup_allocindir_phase2(bp, ip, aip) struct allocindir *oldaip; struct freefrag *freefrag; struct newblk *newblk; - ufs_daddr_t blkno; + ufs2_daddr_t blkno; if (bp->b_lblkno >= 0) panic("setup_allocindir_phase2: not indir blk"); @@ -1719,8 +1724,12 @@ setup_allocindir_phase2(bp, ip, aip) free_allocindir(oldaip, NULL); } LIST_INSERT_HEAD(&indirdep->ir_deplisthd, aip, ai_next); - ((ufs_daddr_t *)indirdep->ir_savebp->b_data) - [aip->ai_offset] = aip->ai_oldblkno; + if (ip->i_ump->um_fstype == UFS1) + ((ufs1_daddr_t *)indirdep->ir_savebp->b_data) + [aip->ai_offset] = aip->ai_oldblkno; + else + ((ufs2_daddr_t *)indirdep->ir_savebp->b_data) + [aip->ai_offset] = aip->ai_oldblkno; FREE_LOCK(&lk); if (freefrag != NULL) handle_workitem_freefrag(freefrag); @@ -1736,6 +1745,8 @@ setup_allocindir_phase2(bp, ip, aip) M_INDIRDEP, M_SOFTDEP_FLAGS); newindirdep->ir_list.wk_type = D_INDIRDEP; newindirdep->ir_state = ATTACHED; + if (ip->i_ump->um_fstype == UFS1) + newindirdep->ir_state |= UFS1FMT; LIST_INIT(&newindirdep->ir_deplisthd); LIST_INIT(&newindirdep->ir_donehd); if (bp->b_blkno == bp->b_lblkno) { @@ -1803,17 +1814,18 @@ softdep_setup_freeblocks(ip, length) freeblks->fb_mnt = ITOV(ip)->v_mount; freeblks->fb_oldsize = ip->i_size; freeblks->fb_newsize = length; - freeblks->fb_chkcnt = ip->i_blocks; + freeblks->fb_chkcnt = DIP(ip, i_blocks); for (i = 0; i < NDADDR; i++) { - freeblks->fb_dblks[i] = ip->i_db[i]; - ip->i_db[i] = 0; + freeblks->fb_dblks[i] = DIP(ip, i_db[i]); + DIP(ip, i_db[i]) = 0; } for (i = 0; i < NIADDR; i++) { - freeblks->fb_iblks[i] = ip->i_ib[i]; - ip->i_ib[i] = 0; + freeblks->fb_iblks[i] = DIP(ip, i_ib[i]); + DIP(ip, i_ib[i]) = 0; } - ip->i_blocks = 0; + DIP(ip, i_blocks) = 0; ip->i_size = 0; + DIP(ip, i_size) = 0; /* * If the file was removed, then the space being freed was * accounted for then (see softdep_filereleased()). If the @@ -1832,8 +1844,12 @@ softdep_setup_freeblocks(ip, length) brelse(bp); softdep_error("softdep_setup_freeblocks", error); } - *((struct dinode *)bp->b_data + ino_to_fsbo(fs, ip->i_number)) = - ip->i_din; + if (ip->i_ump->um_fstype == UFS1) + *((struct ufs1_dinode *)bp->b_data + + ino_to_fsbo(fs, ip->i_number)) = *ip->i_din1; + else + *((struct ufs2_dinode *)bp->b_data + + ino_to_fsbo(fs, ip->i_number)) = *ip->i_din2; /* * Find and eliminate any inode dependencies. */ @@ -2116,9 +2132,9 @@ free_newdirblk(newdirblk) */ void softdep_freefile(pvp, ino, mode) - struct vnode *pvp; - ino_t ino; - int mode; + struct vnode *pvp; + ino_t ino; + int mode; { struct inode *ip = VTOI(pvp); struct inodedep *inodedep; @@ -2188,9 +2204,9 @@ check_inode_unwritten(inodedep) inodedep->id_buf = NULL; if (inodedep->id_state & ONWORKLIST) WORKLIST_REMOVE(&inodedep->id_list); - if (inodedep->id_savedino != NULL) { - FREE(inodedep->id_savedino, M_INODEDEP); - inodedep->id_savedino = NULL; + if (inodedep->id_savedino1 != NULL) { + FREE(inodedep->id_savedino1, M_INODEDEP); + inodedep->id_savedino1 = NULL; } if (free_inodedep(inodedep) == 0) { FREE_LOCK(&lk); @@ -2214,7 +2230,7 @@ free_inodedep(inodedep) LIST_FIRST(&inodedep->id_inowait) != NULL || TAILQ_FIRST(&inodedep->id_inoupdt) != NULL || TAILQ_FIRST(&inodedep->id_newinoupdt) != NULL || - inodedep->id_nlinkdelta != 0 || inodedep->id_savedino != NULL) + inodedep->id_nlinkdelta != 0 || inodedep->id_savedino1 != NULL) return (0); LIST_REMOVE(inodedep, id_hash); WORKITEM_FREE(inodedep, D_INODEDEP); @@ -2237,10 +2253,9 @@ handle_workitem_freeblocks(freeblks, flags) { struct inode *ip; struct vnode *vp; - ufs_daddr_t bn; struct fs *fs; - int i, level, bsize; - long nblocks, blocksreleased = 0; + int i, nblocks, level, bsize; + ufs2_daddr_t bn, blocksreleased = 0; int error, allerror = 0; ufs_lbn_t baselbns[NIADDR], tmpval; @@ -2288,7 +2303,7 @@ handle_workitem_freeblocks(freeblks, flags) VFS_VGET(freeblks->fb_mnt, freeblks->fb_previousinum, (flags & LK_NOWAIT) | LK_EXCLUSIVE, &vp) == 0) { ip = VTOI(vp); - ip->i_blocks += freeblks->fb_chkcnt - blocksreleased; + DIP(ip, i_blocks) += freeblks->fb_chkcnt - blocksreleased; ip->i_flag |= IN_CHANGE; vput(vp); } @@ -2313,18 +2328,19 @@ handle_workitem_freeblocks(freeblks, flags) static int indir_trunc(freeblks, dbn, level, lbn, countp) struct freeblks *freeblks; - ufs_daddr_t dbn; + ufs2_daddr_t dbn; int level; ufs_lbn_t lbn; - long *countp; + ufs2_daddr_t *countp; { struct buf *bp; - ufs_daddr_t *bap; - ufs_daddr_t nb; struct fs *fs; struct worklist *wk; struct indirdep *indirdep; - int i, lbnadd, nblocks; + ufs1_daddr_t *bap1 = 0; + ufs2_daddr_t nb, *bap2 = 0; + ufs_lbn_t lbnadd; + int i, nblocks, ufs1fmt; int error, allerror = 0; fs = VFSTOUFS(freeblks->fb_mnt)->um_fs; @@ -2371,10 +2387,20 @@ indir_trunc(freeblks, dbn, level, lbn, countp) /* * Recursively free indirect blocks. */ - bap = (ufs_daddr_t *)bp->b_data; + if (VFSTOUFS(freeblks->fb_mnt)->um_fstype == UFS1) { + ufs1fmt = 1; + bap1 = (ufs1_daddr_t *)bp->b_data; + } else { + ufs1fmt = 0; + bap2 = (ufs2_daddr_t *)bp->b_data; + } nblocks = btodb(fs->fs_bsize); for (i = NINDIR(fs) - 1; i >= 0; i--) { - if ((nb = bap[i]) == 0) + if (ufs1fmt) + nb = bap1[i]; + else + nb = bap2[i]; + if (nb == 0) continue; if (level != 0) { if ((error = indir_trunc(freeblks, fsbtodb(fs, nb), @@ -2449,7 +2475,7 @@ softdep_setup_directory_add(bp, dp, diroffset, newinum, newdirbp, isnewblk) struct buf *bp; /* buffer containing directory block */ struct inode *dp; /* inode for directory */ off_t diroffset; /* offset of new entry in directory */ - long newinum; /* inode referenced by new directory entry */ + ino_t newinum; /* inode referenced by new directory entry */ struct buf *newdirbp; /* non-NULL => contents of new mkdir */ int isnewblk; /* entry is in a newly allocated block */ { @@ -2868,7 +2894,7 @@ softdep_setup_directory_change(bp, dp, ip, newinum, isrmdir) struct buf *bp; /* buffer containing directory block */ struct inode *dp; /* inode for the directory being modified */ struct inode *ip; /* inode for directory entry being removed */ - long newinum; /* new inode number for changed entry */ + ino_t newinum; /* new inode number for changed entry */ int isrmdir; /* indicates if doing RMDIR */ { int offset; @@ -3028,7 +3054,7 @@ softdep_releasefile(ip) if ((inodedep_lookup(ip->i_fs, ip->i_number, 0, &inodedep))) inodedep->id_state |= SPACECOUNTED; FREE_LOCK(&lk); - ip->i_fs->fs_pendingblocks += ip->i_blocks; + ip->i_fs->fs_pendingblocks += DIP(ip, i_blocks); ip->i_fs->fs_pendinginodes += 1; ip->i_flag |= IN_SPACECOUNTED; } @@ -3066,6 +3092,7 @@ handle_workitem_remove(dirrem, xp) */ if ((dirrem->dm_state & RMDIR) == 0) { ip->i_nlink--; + DIP(ip, i_nlink) = ip->i_nlink; ip->i_flag |= IN_CHANGE; if (ip->i_nlink < ip->i_effnlink) { FREE_LOCK(&lk); @@ -3086,6 +3113,7 @@ handle_workitem_remove(dirrem, xp) * the parent decremented to account for the loss of "..". */ ip->i_nlink -= 2; + DIP(ip, i_nlink) = ip->i_nlink; ip->i_flag |= IN_CHANGE; if (ip->i_nlink < ip->i_effnlink) { FREE_LOCK(&lk); @@ -3193,6 +3221,7 @@ softdep_disk_io_initiation(bp) { struct worklist *wk, *nextwk; struct indirdep *indirdep; + struct inodedep *inodedep; /* * We only care about write operations. There should never @@ -3212,7 +3241,11 @@ softdep_disk_io_initiation(bp) continue; case D_INODEDEP: - initiate_write_inodeblock(WK_INODEDEP(wk), bp); + inodedep = WK_INODEDEP(wk); + if (inodedep->id_fs->fs_magic == FS_UFS1_MAGIC) + initiate_write_inodeblock_ufs1(inodedep, bp); + else + initiate_write_inodeblock_ufs2(inodedep, bp); continue; case D_INDIRDEP: @@ -3309,39 +3342,43 @@ initiate_write_filepage(pagedep, bp) } /* + * Version of initiate_write_inodeblock that handles UFS1 dinodes. + * Note that any bug fixes made to this routine must be done in the + * version found below. + * * Called from within the procedure above to deal with unsatisfied * allocation dependencies in an inodeblock. The buffer must be * locked, thus, no I/O completion operations can occur while we * are manipulating its associated dependencies. */ static void -initiate_write_inodeblock(inodedep, bp) +initiate_write_inodeblock_ufs1(inodedep, bp) struct inodedep *inodedep; struct buf *bp; /* The inode block */ { struct allocdirect *adp, *lastadp; - struct dinode *dp; + struct ufs1_dinode *dp; struct fs *fs; - ufs_lbn_t prevlbn = 0; - int i, deplist; + ufs_lbn_t i, prevlbn = 0; + int deplist; if (inodedep->id_state & IOSTARTED) - panic("initiate_write_inodeblock: already started"); + panic("initiate_write_inodeblock_ufs1: already started"); inodedep->id_state |= IOSTARTED; fs = inodedep->id_fs; - dp = (struct dinode *)bp->b_data + + dp = (struct ufs1_dinode *)bp->b_data + ino_to_fsbo(fs, inodedep->id_ino); /* * If the bitmap is not yet written, then the allocated * inode cannot be written to disk. */ if ((inodedep->id_state & DEPCOMPLETE) == 0) { - if (inodedep->id_savedino != NULL) - panic("initiate_write_inodeblock: already doing I/O"); - MALLOC(inodedep->id_savedino, struct dinode *, - sizeof(struct dinode), M_INODEDEP, M_SOFTDEP_FLAGS); - *inodedep->id_savedino = *dp; - bzero((caddr_t)dp, sizeof(struct dinode)); + if (inodedep->id_savedino1 != NULL) + panic("initiate_write_inodeblock_ufs1: I/O underway"); + MALLOC(inodedep->id_savedino1, struct ufs1_dinode *, + sizeof(struct ufs1_dinode), M_INODEDEP, M_SOFTDEP_FLAGS); + *inodedep->id_savedino1 = *dp; + bzero((caddr_t)dp, sizeof(struct ufs1_dinode)); return; } /* @@ -3365,16 +3402,172 @@ initiate_write_inodeblock(inodedep, bp) if (adp->ad_lbn < NDADDR && dp->di_db[adp->ad_lbn] != adp->ad_newblkno) { FREE_LOCK(&lk); - panic("%s: direct pointer #%ld mismatch %d != %d", - "softdep_write_inodeblock", adp->ad_lbn, - dp->di_db[adp->ad_lbn], adp->ad_newblkno); + panic("%s: direct pointer #%lld mismatch %d != %lld", + "softdep_write_inodeblock", + (intmax_t)adp->ad_lbn, + dp->di_db[adp->ad_lbn], + (intmax_t)adp->ad_newblkno); } if (adp->ad_lbn >= NDADDR && dp->di_ib[adp->ad_lbn - NDADDR] != adp->ad_newblkno) { FREE_LOCK(&lk); - panic("%s: indirect pointer #%ld mismatch %d != %d", - "softdep_write_inodeblock", adp->ad_lbn - NDADDR, - dp->di_ib[adp->ad_lbn - NDADDR], adp->ad_newblkno); + panic("%s: indirect pointer #%lld mismatch %d != %lld", + "softdep_write_inodeblock", + (intmax_t)adp->ad_lbn - NDADDR, + dp->di_ib[adp->ad_lbn - NDADDR], + (intmax_t)adp->ad_newblkno); + } + deplist |= 1 << adp->ad_lbn; + if ((adp->ad_state & ATTACHED) == 0) { + FREE_LOCK(&lk); + panic("softdep_write_inodeblock: Unknown state 0x%x", + adp->ad_state); + } +#endif /* DIAGNOSTIC */ + adp->ad_state &= ~ATTACHED; + adp->ad_state |= UNDONE; + } + /* + * The on-disk inode cannot claim to be any larger than the last + * fragment that has been written. Otherwise, the on-disk inode + * might have fragments that were not the last block in the file + * which would corrupt the filesystem. + */ + for (lastadp = NULL, adp = TAILQ_FIRST(&inodedep->id_inoupdt); adp; + lastadp = adp, adp = TAILQ_NEXT(adp, ad_next)) { + if (adp->ad_lbn >= NDADDR) + break; + dp->di_db[adp->ad_lbn] = adp->ad_oldblkno; + /* keep going until hitting a rollback to a frag */ + if (adp->ad_oldsize == 0 || adp->ad_oldsize == fs->fs_bsize) + continue; + dp->di_size = fs->fs_bsize * adp->ad_lbn + adp->ad_oldsize; + for (i = adp->ad_lbn + 1; i < NDADDR; i++) { +#ifdef DIAGNOSTIC + if (dp->di_db[i] != 0 && (deplist & (1 << i)) == 0) { + FREE_LOCK(&lk); + panic("softdep_write_inodeblock: lost dep1"); + } +#endif /* DIAGNOSTIC */ + dp->di_db[i] = 0; + } + for (i = 0; i < NIADDR; i++) { +#ifdef DIAGNOSTIC + if (dp->di_ib[i] != 0 && + (deplist & ((1 << NDADDR) << i)) == 0) { + FREE_LOCK(&lk); + panic("softdep_write_inodeblock: lost dep2"); + } +#endif /* DIAGNOSTIC */ + dp->di_ib[i] = 0; + } + FREE_LOCK(&lk); + return; + } + /* + * If we have zero'ed out the last allocated block of the file, + * roll back the size to the last currently allocated block. + * We know that this last allocated block is a full-sized as + * we already checked for fragments in the loop above. + */ + if (lastadp != NULL && + dp->di_size <= (lastadp->ad_lbn + 1) * fs->fs_bsize) { + for (i = lastadp->ad_lbn; i >= 0; i--) + if (dp->di_db[i] != 0) + break; + dp->di_size = (i + 1) * fs->fs_bsize; + } + /* + * The only dependencies are for indirect blocks. + * + * The file size for indirect block additions is not guaranteed. + * Such a guarantee would be non-trivial to achieve. The conventional + * synchronous write implementation also does not make this guarantee. + * Fsck should catch and fix discrepancies. Arguably, the file size + * can be over-estimated without destroying integrity when the file + * moves into the indirect blocks (i.e., is large). If we want to + * postpone fsck, we are stuck with this argument. + */ + for (; adp; adp = TAILQ_NEXT(adp, ad_next)) + dp->di_ib[adp->ad_lbn - NDADDR] = 0; + FREE_LOCK(&lk); +} + +/* + * Version of initiate_write_inodeblock that handles UFS2 dinodes. + * Note that any bug fixes made to this routine must be done in the + * version found above. + * + * Called from within the procedure above to deal with unsatisfied + * allocation dependencies in an inodeblock. The buffer must be + * locked, thus, no I/O completion operations can occur while we + * are manipulating its associated dependencies. + */ +static void +initiate_write_inodeblock_ufs2(inodedep, bp) + struct inodedep *inodedep; + struct buf *bp; /* The inode block */ +{ + struct allocdirect *adp, *lastadp; + struct ufs2_dinode *dp; + struct fs *fs; + ufs_lbn_t i, prevlbn = 0; + int deplist; + + if (inodedep->id_state & IOSTARTED) + panic("initiate_write_inodeblock_ufs2: already started"); + inodedep->id_state |= IOSTARTED; + fs = inodedep->id_fs; + dp = (struct ufs2_dinode *)bp->b_data + + ino_to_fsbo(fs, inodedep->id_ino); + /* + * If the bitmap is not yet written, then the allocated + * inode cannot be written to disk. + */ + if ((inodedep->id_state & DEPCOMPLETE) == 0) { + if (inodedep->id_savedino2 != NULL) + panic("initiate_write_inodeblock_ufs2: I/O underway"); + MALLOC(inodedep->id_savedino2, struct ufs2_dinode *, + sizeof(struct ufs2_dinode), M_INODEDEP, M_SOFTDEP_FLAGS); + *inodedep->id_savedino2 = *dp; + bzero((caddr_t)dp, sizeof(struct ufs2_dinode)); + return; + } + /* + * If no dependencies, then there is nothing to roll back. + */ + inodedep->id_savedsize = dp->di_size; + if (TAILQ_FIRST(&inodedep->id_inoupdt) == NULL) + return; + /* + * Set the dependencies to busy. + */ + ACQUIRE_LOCK(&lk); + for (deplist = 0, adp = TAILQ_FIRST(&inodedep->id_inoupdt); adp; + adp = TAILQ_NEXT(adp, ad_next)) { +#ifdef DIAGNOSTIC + if (deplist != 0 && prevlbn >= adp->ad_lbn) { + FREE_LOCK(&lk); + panic("softdep_write_inodeblock: lbn order"); + } + prevlbn = adp->ad_lbn; + if (adp->ad_lbn < NDADDR && + dp->di_db[adp->ad_lbn] != adp->ad_newblkno) { + FREE_LOCK(&lk); + panic("%s: direct pointer #%lld mismatch %lld != %lld", + "softdep_write_inodeblock", + (intmax_t)adp->ad_lbn, + (intmax_t)dp->di_db[adp->ad_lbn], + (intmax_t)adp->ad_newblkno); + } + if (adp->ad_lbn >= NDADDR && + dp->di_ib[adp->ad_lbn - NDADDR] != adp->ad_newblkno) { + FREE_LOCK(&lk); + panic("%s indirect pointer #%lld mismatch %lld != %lld", + "softdep_write_inodeblock:", + (intmax_t)adp->ad_lbn - NDADDR, + (intmax_t)dp->di_ib[adp->ad_lbn - NDADDR], + (intmax_t)adp->ad_newblkno); } deplist |= 1 << adp->ad_lbn; if ((adp->ad_state & ATTACHED) == 0) { @@ -3683,8 +3876,12 @@ handle_allocindir_partdone(aip) LIST_INSERT_HEAD(&indirdep->ir_donehd, aip, ai_next); return; } - ((ufs_daddr_t *)indirdep->ir_savebp->b_data)[aip->ai_offset] = - aip->ai_newblkno; + if (indirdep->ir_state & UFS1FMT) + ((ufs1_daddr_t *)indirdep->ir_savebp->b_data)[aip->ai_offset] = + aip->ai_newblkno; + else + ((ufs2_daddr_t *)indirdep->ir_savebp->b_data)[aip->ai_offset] = + aip->ai_newblkno; LIST_REMOVE(aip, ai_next); if (aip->ai_freefrag != NULL) add_to_worklist(&aip->ai_freefrag->ff_list); @@ -3704,8 +3901,9 @@ handle_written_inodeblock(inodedep, bp) { struct worklist *wk, *filefree; struct allocdirect *adp, *nextadp; - struct dinode *dp; - int hadchanges; + struct ufs1_dinode *dp1 = NULL; + struct ufs2_dinode *dp2 = NULL; + int hadchanges, fstype; if ((inodedep->id_state & IOSTARTED) == 0) { lk.lkt_held = NOHOLDER; @@ -3713,8 +3911,15 @@ handle_written_inodeblock(inodedep, bp) } inodedep->id_state &= ~IOSTARTED; inodedep->id_state |= COMPLETE; - dp = (struct dinode *)bp->b_data + - ino_to_fsbo(inodedep->id_fs, inodedep->id_ino); + if (inodedep->id_fs->fs_magic == FS_UFS1_MAGIC) { + fstype = UFS1; + dp1 = (struct ufs1_dinode *)bp->b_data + + ino_to_fsbo(inodedep->id_fs, inodedep->id_ino); + } else { + fstype = UFS2; + dp2 = (struct ufs2_dinode *)bp->b_data + + ino_to_fsbo(inodedep->id_fs, inodedep->id_ino); + } /* * If we had to rollback the inode allocation because of * bitmaps being incomplete, then simply restore it. @@ -3722,10 +3927,13 @@ handle_written_inodeblock(inodedep, bp) * all associated dependencies have been cleared and the * corresponding updates written to disk. */ - if (inodedep->id_savedino != NULL) { - *dp = *inodedep->id_savedino; - FREE(inodedep->id_savedino, M_INODEDEP); - inodedep->id_savedino = NULL; + if (inodedep->id_savedino1 != NULL) { + if (fstype == UFS1) + *dp1 = *inodedep->id_savedino1; + else + *dp2 = *inodedep->id_savedino2; + FREE(inodedep->id_savedino1, M_INODEDEP); + inodedep->id_savedino1 = NULL; if ((bp->b_flags & B_DELWRI) == 0) stat_inode_bitmap++; bdirty(bp); @@ -3742,24 +3950,55 @@ handle_written_inodeblock(inodedep, bp) lk.lkt_held = NOHOLDER; panic("handle_written_inodeblock: new entry"); } - if (adp->ad_lbn < NDADDR) { - if (dp->di_db[adp->ad_lbn] != adp->ad_oldblkno) { - lk.lkt_held = NOHOLDER; - panic("%s: %s #%ld mismatch %d != %d", - "handle_written_inodeblock", - "direct pointer", adp->ad_lbn, - dp->di_db[adp->ad_lbn], adp->ad_oldblkno); + if (fstype == UFS1) { + if (adp->ad_lbn < NDADDR) { + if (dp1->di_db[adp->ad_lbn]!=adp->ad_oldblkno) { + lk.lkt_held = NOHOLDER; + panic("%s %s #%lld mismatch %d != %lld", + "handle_written_inodeblock:", + "direct pointer", + (intmax_t)adp->ad_lbn, + dp1->di_db[adp->ad_lbn], + (intmax_t)adp->ad_oldblkno); + } + dp1->di_db[adp->ad_lbn] = adp->ad_newblkno; + } else { + if (dp1->di_ib[adp->ad_lbn - NDADDR] != 0) { + lk.lkt_held = NOHOLDER; + panic("%s: %s #%lld allocated as %d", + "handle_written_inodeblock", + "indirect pointer", + (intmax_t)adp->ad_lbn - NDADDR, + dp1->di_ib[adp->ad_lbn - NDADDR]); + } + dp1->di_ib[adp->ad_lbn - NDADDR] = + adp->ad_newblkno; } - dp->di_db[adp->ad_lbn] = adp->ad_newblkno; } else { - if (dp->di_ib[adp->ad_lbn - NDADDR] != 0) { - lk.lkt_held = NOHOLDER; - panic("%s: %s #%ld allocated as %d", - "handle_written_inodeblock", - "indirect pointer", adp->ad_lbn - NDADDR, - dp->di_ib[adp->ad_lbn - NDADDR]); + if (adp->ad_lbn < NDADDR) { + if (dp2->di_db[adp->ad_lbn]!=adp->ad_oldblkno) { + lk.lkt_held = NOHOLDER; + panic("%s: %s #%lld %s %lld != %lld", + "handle_written_inodeblock", + "direct pointer", + (intmax_t)adp->ad_lbn, "mismatch", + (intmax_t)dp2->di_db[adp->ad_lbn], + (intmax_t)adp->ad_oldblkno); + } + dp2->di_db[adp->ad_lbn] = adp->ad_newblkno; + } else { + if (dp2->di_ib[adp->ad_lbn - NDADDR] != 0) { + lk.lkt_held = NOHOLDER; + panic("%s: %s #%lld allocated as %lld", + "handle_written_inodeblock", + "indirect pointer", + (intmax_t)adp->ad_lbn - NDADDR, + (intmax_t) + dp2->di_ib[adp->ad_lbn - NDADDR]); + } + dp2->di_ib[adp->ad_lbn - NDADDR] = + adp->ad_newblkno; } - dp->di_ib[adp->ad_lbn - NDADDR] = adp->ad_newblkno; } adp->ad_state &= ~UNDONE; adp->ad_state |= ATTACHED; @@ -3774,9 +4013,16 @@ handle_written_inodeblock(inodedep, bp) lk.lkt_held = NOHOLDER; panic("handle_written_inodeblock: bad size"); } - if (dp->di_size != inodedep->id_savedsize) { - dp->di_size = inodedep->id_savedsize; - hadchanges = 1; + if (fstype == UFS1) { + if (dp1->di_size != inodedep->id_savedsize) { + dp1->di_size = inodedep->id_savedsize; + hadchanges = 1; + } + } else { + if (dp2->di_size != inodedep->id_savedsize) { + dp2->di_size = inodedep->id_savedsize; + hadchanges = 1; + } } inodedep->id_savedsize = -1; /* @@ -4859,7 +5105,8 @@ softdep_request_cleanup(fs, vp) struct fs *fs; struct vnode *vp; { - long starttime, needed; + long starttime; + ufs2_daddr_t needed; needed = fs->fs_cstotal.cs_nbfree + fs->fs_contigsumsize; starttime = time_second + tickdelay; |