aboutsummaryrefslogtreecommitdiff
path: root/sys/ufs
diff options
context:
space:
mode:
authorKirk McKusick <mckusick@FreeBSD.org>2019-02-25 21:58:19 +0000
committerKirk McKusick <mckusick@FreeBSD.org>2019-02-25 21:58:19 +0000
commitac4b20a0a71e693d9b241a8396ec4540fc4cef68 (patch)
tree7ccbacf263cde50d88aae9e36a7a6fed7dad8103 /sys/ufs
parent2528b7e2cb5c0d6fe0ad020dd80a1573d02a6240 (diff)
downloadsrc-ac4b20a0a71e693d9b241a8396ec4540fc4cef68.tar.gz
src-ac4b20a0a71e693d9b241a8396ec4540fc4cef68.zip
After a crash, a file that extends into indirect blocks may end up
shorter than its size resulting in a hole as its final block (which is a violation of the invarients of the UFS filesystem). Soft updates will always ensure that the file size is correct when writing inodes to disk for files that contain only direct block pointers. However soft updates does not roll back sizes for files with indirect blocks that it has set to unallocated because their contents have not yet been written to disk. Hence, the file can appear to have a hole at its end because the block pointer has been rolled back to zero when its inode was written to disk. Thus, fsck_ffs calculates the last allocated block in the file. For files that extend into indirect blocks, fsck_ffs checks for a size past the last allocated block of the file and if that is found, shortens the file to reference the last allocated block thus avoiding having it reference a hole at its end. Submitted by: Chuck Silvers <chs@netflix.com> Tested by: Chuck Silvers <chs@netflix.com> MFC after: 1 week Sponsored by: Netflix
Notes
Notes: svn path=/head/; revision=344552
Diffstat (limited to 'sys/ufs')
-rw-r--r--sys/ufs/ffs/ffs_alloc.c22
-rw-r--r--sys/ufs/ffs/fs.h3
2 files changed, 24 insertions, 1 deletions
diff --git a/sys/ufs/ffs/ffs_alloc.c b/sys/ufs/ffs/ffs_alloc.c
index e70da0e746ab..f4bdd5789ab5 100644
--- a/sys/ufs/ffs/ffs_alloc.c
+++ b/sys/ufs/ffs/ffs_alloc.c
@@ -3037,6 +3037,8 @@ ffs_fserr(fs, inum, cp)
* the count to zero will cause the inode to be freed.
* adjblkcnt(inode, amt) - adjust the number of blocks used by the
* inode by the specified amount.
+ * adjsize(inode, size) - set the size of the inode to the
+ * specified size.
* adjndir, adjbfree, adjifree, adjffree, adjnumclusters(amt) -
* adjust the superblock summary.
* freedirs(inode, count) - directory inodes [inode..inode + count - 1]
@@ -3078,6 +3080,9 @@ SYSCTL_PROC(_vfs_ffs, FFS_ADJ_REFCNT, adjrefcnt, CTLFLAG_WR|CTLTYPE_STRUCT,
static SYSCTL_NODE(_vfs_ffs, FFS_ADJ_BLKCNT, adjblkcnt, CTLFLAG_WR,
sysctl_ffs_fsck, "Adjust Inode Used Blocks Count");
+static SYSCTL_NODE(_vfs_ffs, FFS_SET_SIZE, setsize, CTLFLAG_WR,
+ sysctl_ffs_fsck, "Set the inode size");
+
static SYSCTL_NODE(_vfs_ffs, FFS_ADJ_NDIR, adjndir, CTLFLAG_WR,
sysctl_ffs_fsck, "Adjust number of directories");
@@ -3230,6 +3235,23 @@ sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS)
vput(vp);
break;
+ case FFS_SET_SIZE:
+#ifdef DEBUG
+ if (fsckcmds) {
+ printf("%s: set inode %jd size to %jd\n",
+ mp->mnt_stat.f_mntonname, (intmax_t)cmd.value,
+ (intmax_t)cmd.size);
+ }
+#endif /* DEBUG */
+ if ((error = ffs_vget(mp, (ino_t)cmd.value, LK_EXCLUSIVE, &vp)))
+ break;
+ ip = VTOI(vp);
+ DIP_SET(ip, i_size, cmd.size);
+ ip->i_flag |= IN_CHANGE | IN_MODIFIED;
+ error = ffs_update(vp, 1);
+ vput(vp);
+ break;
+
case FFS_DIR_FREE:
filetype = IFDIR;
/* fall through */
diff --git a/sys/ufs/ffs/fs.h b/sys/ufs/ffs/fs.h
index 0560bc693afa..d052b603d5f1 100644
--- a/sys/ufs/ffs/fs.h
+++ b/sys/ufs/ffs/fs.h
@@ -221,7 +221,8 @@
#define FFS_UNLINK 14 /* remove a name in the filesystem */
#define FFS_SET_INODE 15 /* update an on-disk inode */
#define FFS_SET_BUFOUTPUT 16 /* set buffered writing on descriptor */
-#define FFS_MAXID 16 /* number of valid ffs ids */
+#define FFS_SET_SIZE 17 /* set inode size */
+#define FFS_MAXID 17 /* number of valid ffs ids */
/*
* Command structure passed in to the filesystem to adjust filesystem values.