Module Name: src Committed By: jdolecek Date: Thu Nov 10 19:10:05 UTC 2016
Modified Files: src/sys/ufs/ffs: ffs_inode.c Log Message: ffs_indirtrunc(): for !wapbl, restore rev 1.117 behavior of writing the zeroed (indirect) block before freeing the referenced blocks; it's necessary for fsck to recover the filesystem, if system goes down during truncate patch courtesy of hannken@ with only sligh tweaks To generate a diff of this commit: cvs rdiff -u -r1.120 -r1.121 src/sys/ufs/ffs/ffs_inode.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/ufs/ffs/ffs_inode.c diff -u src/sys/ufs/ffs/ffs_inode.c:1.120 src/sys/ufs/ffs/ffs_inode.c:1.121 --- src/sys/ufs/ffs/ffs_inode.c:1.120 Mon Nov 7 21:14:23 2016 +++ src/sys/ufs/ffs/ffs_inode.c Thu Nov 10 19:10:05 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: ffs_inode.c,v 1.120 2016/11/07 21:14:23 jdolecek Exp $ */ +/* $NetBSD: ffs_inode.c,v 1.121 2016/11/10 19:10:05 jdolecek Exp $ */ /*- * Copyright (c) 2008 The NetBSD Foundation, Inc. @@ -61,7 +61,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ffs_inode.c,v 1.120 2016/11/07 21:14:23 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ffs_inode.c,v 1.121 2016/11/10 19:10:05 jdolecek Exp $"); #if defined(_KERNEL_OPT) #include "opt_ffs.h" @@ -533,6 +533,8 @@ out: * blocks were deallocated creating a hole, but that is okay. */ if (error == EAGAIN) { + if (!allerror) + allerror = error; length = osize; uvm_vnp_setsize(ovp, length); } @@ -573,10 +575,12 @@ ffs_indirtrunc(struct inode *ip, daddr_t int64_t *bap2 = NULL; struct vnode *vp; daddr_t nb, nlbn, last; + char *copy = NULL; int64_t factor; int64_t nblocks; - int error = 0; + int error = 0, allerror = 0; const int needswap = UFS_FSNEEDSWAP(fs); + const int wapbl = (ip->i_ump->um_mountp->mnt_wapbl != NULL); #define RBAP(ip, i) (((ip)->i_ump->um_fstype == UFS1) ? \ ufs_rw32(bap1[i], needswap) : ufs_rw64(bap2[i], needswap)) @@ -602,7 +606,7 @@ ffs_indirtrunc(struct inode *ip, daddr_t 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. Since + * to blocks to be free'd, and update on disk copy first. Since * double(triple) indirect before single(double) indirect, calls * to bmap on these blocks will fail. However, we already have * the on disk address, so we have to set the b_blkno field @@ -635,13 +639,35 @@ ffs_indirtrunc(struct inode *ip, daddr_t return error; } - if (ip->i_ump->um_fstype == UFS1) - bap1 = (int32_t *)bp->b_data; - else - bap2 = (int64_t *)bp->b_data; + /* + * Clear reference to blocks to be removed on disk, before actually + * reclaiming them, so that fsck is more likely to be able to recover + * the filesystem if system goes down during the truncate process. + * This assumes the truncate process would not fail, contrary + * to the wapbl case. + */ + if (lastbn >= 0 && !wapbl) { + copy = kmem_alloc(fs->fs_bsize, KM_SLEEP); + memcpy((void *)copy, bp->b_data, (u_int)fs->fs_bsize); + for (i = last + 1; i < FFS_NINDIR(fs); i++) + BAP_ASSIGN(ip, i, 0); + error = bwrite(bp); + if (error) + allerror = error; + + if (ip->i_ump->um_fstype == UFS1) + bap1 = (int32_t *)copy; + else + bap2 = (int64_t *)copy; + } else { + if (ip->i_ump->um_fstype == UFS1) + bap1 = (int32_t *)bp->b_data; + else + bap2 = (int64_t *)bp->b_data; + } /* - * Recursively free totally unused blocks, starting from first. + * Recursively free totally unused blocks. */ for (i = FFS_NINDIR(fs) - 1, nlbn = lbn + 1 - i * factor; i > last; i--, nlbn += factor) { @@ -686,15 +712,22 @@ ffs_indirtrunc(struct inode *ip, daddr_t } out: - if (lastbn < 0 && error == 0) { + if (error && !allerror) + allerror = error; + + if (copy != NULL) { + kmem_free(copy, fs->fs_bsize); + } else if (lastbn < 0 && error == 0) { /* all freed, release without writing back */ brelse(bp, BC_INVAL); - } else { - /* only partially freed, write the updated block */ - (void) bwrite(bp); + } else if (wapbl) { + /* only partially freed, write the updated block */ + error = bwrite(bp); + if (!allerror) + allerror = error; } - return (error); + return (allerror); } void