svn commit: r344860 - in stable/12: sbin/fsck_ffs sbin/fsdb sys/ufs/ffs
Kirk McKusick
mckusick at FreeBSD.org
Wed Mar 6 23:54:58 UTC 2019
Author: mckusick
Date: Wed Mar 6 23:54:55 2019
New Revision: 344860
URL: https://svnweb.freebsd.org/changeset/base/344860
Log:
MFC of 344552 and 344732
Have fsck_ffs adjust size for files with hole at end
Tighten last lbn calculation
Sponsored by: Netflix
Modified:
stable/12/sbin/fsck_ffs/fsck.h
stable/12/sbin/fsck_ffs/globs.c
stable/12/sbin/fsck_ffs/inode.c
stable/12/sbin/fsck_ffs/pass1.c
stable/12/sbin/fsck_ffs/setup.c
stable/12/sbin/fsdb/fsdb.c
stable/12/sys/ufs/ffs/ffs_alloc.c
stable/12/sys/ufs/ffs/fs.h
Directory Properties:
stable/12/ (props changed)
Modified: stable/12/sbin/fsck_ffs/fsck.h
==============================================================================
--- stable/12/sbin/fsck_ffs/fsck.h Wed Mar 6 23:31:42 2019 (r344859)
+++ stable/12/sbin/fsck_ffs/fsck.h Wed Mar 6 23:54:55 2019 (r344860)
@@ -232,6 +232,7 @@ struct inodesc {
ufs_lbn_t id_lbn; /* logical block number of current block */
ufs2_daddr_t id_blkno; /* current block number being examined */
int id_numfrags; /* number of frags contained in block */
+ ufs_lbn_t id_lballoc; /* pass1: last LBN that is allocated */
off_t id_filesize; /* for DATA nodes, the size of the directory */
ufs2_daddr_t id_entryno;/* for DATA nodes, current entry number */
int id_loc; /* for DATA nodes, current location in dir */
@@ -291,6 +292,7 @@ extern long countdirs; /* number of directories we ac
#define MIBSIZE 3 /* size of fsck sysctl MIBs */
extern int adjrefcnt[MIBSIZE]; /* MIB command to adjust inode reference cnt */
extern int adjblkcnt[MIBSIZE]; /* MIB command to adjust inode block count */
+extern int setsize[MIBSIZE]; /* MIB command to set inode size */
extern int adjndir[MIBSIZE]; /* MIB command to adjust number of directories */
extern int adjnbfree[MIBSIZE]; /* MIB command to adjust number of free blocks */
extern int adjnifree[MIBSIZE]; /* MIB command to adjust number of free inodes */
Modified: stable/12/sbin/fsck_ffs/globs.c
==============================================================================
--- stable/12/sbin/fsck_ffs/globs.c Wed Mar 6 23:31:42 2019 (r344859)
+++ stable/12/sbin/fsck_ffs/globs.c Wed Mar 6 23:54:55 2019 (r344860)
@@ -63,6 +63,7 @@ unsigned long numdirs, listmax;
long countdirs; /* number of directories we actually found */
int adjrefcnt[MIBSIZE]; /* MIB command to adjust inode reference cnt */
int adjblkcnt[MIBSIZE]; /* MIB command to adjust inode block count */
+int setsize[MIBSIZE]; /* MIB command to set inode size */
int adjndir[MIBSIZE]; /* MIB command to adjust number of directories */
int adjnbfree[MIBSIZE]; /* MIB command to adjust number of free blocks */
int adjnifree[MIBSIZE]; /* MIB command to adjust number of free inodes */
@@ -131,6 +132,7 @@ fsckinit(void)
countdirs = 0;
bzero(adjrefcnt, sizeof(int) * MIBSIZE);
bzero(adjblkcnt, sizeof(int) * MIBSIZE);
+ bzero(setsize, sizeof(int) * MIBSIZE);
bzero(adjndir, sizeof(int) * MIBSIZE);
bzero(adjnbfree, sizeof(int) * MIBSIZE);
bzero(adjnifree, sizeof(int) * MIBSIZE);
Modified: stable/12/sbin/fsck_ffs/inode.c
==============================================================================
--- stable/12/sbin/fsck_ffs/inode.c Wed Mar 6 23:31:42 2019 (r344859)
+++ stable/12/sbin/fsck_ffs/inode.c Wed Mar 6 23:54:55 2019 (r344860)
@@ -126,9 +126,9 @@ ckinode(union dinode *dp, struct inodesc *idesc)
ret = iblock(idesc, i + 1, remsize, BT_LEVEL1 + i);
if (ret & STOP)
return (ret);
- } else {
+ } else if (remsize > 0) {
idesc->id_lbn += sizepb / sblock.fs_bsize;
- if (idesc->id_type == DATA && remsize > 0) {
+ if (idesc->id_type == DATA) {
/* An empty block in a directory XXX */
getpathname(pathbuf, idesc->id_number,
idesc->id_number);
Modified: stable/12/sbin/fsck_ffs/pass1.c
==============================================================================
--- stable/12/sbin/fsck_ffs/pass1.c Wed Mar 6 23:31:42 2019 (r344859)
+++ stable/12/sbin/fsck_ffs/pass1.c Wed Mar 6 23:54:55 2019 (r344860)
@@ -247,6 +247,7 @@ checkinode(ino_t inumber, struct inodesc *idesc, int r
off_t kernmaxfilesize;
ufs2_daddr_t ndb;
mode_t mode;
+ uintmax_t fixsize;
int j, ret, offset;
if ((dp = getnextinode(inumber, rebuildcg)) == NULL)
@@ -377,6 +378,7 @@ checkinode(ino_t inumber, struct inodesc *idesc, int r
idesc->id_type = SNAP;
else
idesc->id_type = ADDR;
+ idesc->id_lballoc = -1;
(void)ckinode(dp, idesc);
if (sblock.fs_magic == FS_UFS2_MAGIC && dp->dp2.di_extsize > 0) {
idesc->id_type = ADDR;
@@ -422,6 +424,46 @@ checkinode(ino_t inumber, struct inodesc *idesc, int r
rwerror("ADJUST INODE BLOCK COUNT", cmd.value);
}
}
+ /*
+ * Soft updates will always ensure that the file size is correct
+ * 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. Thus, id_lballoc tracks the last allocated
+ * block in the file. Here, for files that extend into indirect
+ * blocks, we check for a size past the last allocated block of
+ * the file and if that is found, shorten the file to reference
+ * the last allocated block to avoid having it reference a hole
+ * at its end.
+ */
+ if (DIP(dp, di_size) > UFS_NDADDR * sblock.fs_bsize &&
+ idesc->id_lballoc < lblkno(&sblock, DIP(dp, di_size) - 1)) {
+ fixsize = lblktosize(&sblock, idesc->id_lballoc + 1);
+ pwarn("INODE %lu: FILE SIZE %ju BEYOND END OF ALLOCATED FILE, "
+ "SIZE SHOULD BE %ju", (u_long)inumber,
+ (uintmax_t)DIP(dp, di_size), fixsize);
+ if (preen)
+ printf(" (ADJUSTED)\n");
+ else if (reply("ADJUST") == 0)
+ return (1);
+ if (bkgrdflag == 0) {
+ dp = ginode(inumber);
+ DIP_SET(dp, di_size, fixsize);
+ inodirty(dp);
+ } else {
+ cmd.value = idesc->id_number;
+ cmd.size = fixsize;
+ if (debug)
+ printf("setsize ino %ju size set to %ju\n",
+ (uintmax_t)cmd.value, (uintmax_t)cmd.size);
+ if (sysctl(setsize, MIBSIZE, 0, 0,
+ &cmd, sizeof cmd) == -1)
+ rwerror("SET INODE SIZE", cmd.value);
+ }
+
+ }
return (1);
unknown:
pfatal("UNKNOWN FILE TYPE I=%lu", (u_long)inumber);
@@ -523,5 +565,7 @@ pass1check(struct inodesc *idesc)
*/
idesc->id_entryno++;
}
+ if (idesc->id_lballoc == -1 || idesc->id_lballoc < idesc->id_lbn)
+ idesc->id_lballoc = idesc->id_lbn;
return (res);
}
Modified: stable/12/sbin/fsck_ffs/setup.c
==============================================================================
--- stable/12/sbin/fsck_ffs/setup.c Wed Mar 6 23:31:42 2019 (r344859)
+++ stable/12/sbin/fsck_ffs/setup.c Wed Mar 6 23:54:55 2019 (r344860)
@@ -140,6 +140,7 @@ setup(char *dev)
size = MIBSIZE;
if (sysctlnametomib("vfs.ffs.adjrefcnt", adjrefcnt, &size) < 0||
sysctlnametomib("vfs.ffs.adjblkcnt", adjblkcnt, &size) < 0||
+ sysctlnametomib("vfs.ffs.setsize", setsize, &size) < 0 ||
sysctlnametomib("vfs.ffs.freefiles", freefiles, &size) < 0||
sysctlnametomib("vfs.ffs.freedirs", freedirs, &size) < 0 ||
sysctlnametomib("vfs.ffs.freeblks", freeblks, &size) < 0) {
Modified: stable/12/sbin/fsdb/fsdb.c
==============================================================================
--- stable/12/sbin/fsdb/fsdb.c Wed Mar 6 23:31:42 2019 (r344859)
+++ stable/12/sbin/fsdb/fsdb.c Wed Mar 6 23:54:55 2019 (r344860)
@@ -157,6 +157,7 @@ CMDFUNC(chctime); /* Change ctime */
CMDFUNC(chatime); /* Change atime */
CMDFUNC(chinum); /* Change inode # of dirent */
CMDFUNC(chname); /* Change dirname of dirent */
+CMDFUNC(chsize); /* Change size */
struct cmdtable cmds[] = {
{ "help", "Print out help", 1, 1, FL_RO, helpfn },
@@ -186,6 +187,7 @@ struct cmdtable cmds[] = {
{ "chgrp", "Change group of current inode to GROUP", 2, 2, FL_WR, chgroup },
{ "chflags", "Change flags of current inode to FLAGS", 2, 2, FL_WR, chaflags },
{ "chgen", "Change generation number of current inode to GEN", 2, 2, FL_WR, chgen },
+ { "chsize", "Change size of current inode to SIZE", 2, 2, FL_WR, chsize },
{ "btime", "Change btime of current inode to BTIME", 2, 2, FL_WR, chbtime },
{ "mtime", "Change mtime of current inode to MTIME", 2, 2, FL_WR, chmtime },
{ "ctime", "Change ctime of current inode to CTIME", 2, 2, FL_WR, chctime },
@@ -1013,6 +1015,31 @@ CMDFUNCSTART(chgen)
}
DIP_SET(curinode, di_gen, gen);
inodirty();
+ printactive(0);
+ return rval;
+}
+
+CMDFUNCSTART(chsize)
+{
+ int rval = 1;
+ off_t size;
+ char *cp;
+
+ if (!checkactive())
+ return 1;
+
+ size = strtoll(argv[1], &cp, 0);
+ if (cp == argv[1] || *cp != '\0') {
+ warnx("bad size `%s'", argv[1]);
+ return 1;
+ }
+
+ if (size < 0) {
+ warnx("size set to negative (%jd)\n", (intmax_t)size);
+ return(1);
+ }
+ DIP_SET(curinode, di_size, size);
+ inodirty(curinode);
printactive(0);
return rval;
}
Modified: stable/12/sys/ufs/ffs/ffs_alloc.c
==============================================================================
--- stable/12/sys/ufs/ffs/ffs_alloc.c Wed Mar 6 23:31:42 2019 (r344859)
+++ stable/12/sys/ufs/ffs/ffs_alloc.c Wed Mar 6 23:54:55 2019 (r344860)
@@ -3020,6 +3020,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]
@@ -3061,6 +3063,9 @@ SYSCTL_PROC(_vfs_ffs, FFS_ADJ_REFCNT, adjrefcnt, CTLFL
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");
@@ -3208,6 +3213,23 @@ sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS)
break;
ip = VTOI(vp);
DIP_SET(ip, i_blocks, DIP(ip, i_blocks) + cmd.size);
+ ip->i_flag |= IN_CHANGE | IN_MODIFIED;
+ error = ffs_update(vp, 1);
+ 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);
Modified: stable/12/sys/ufs/ffs/fs.h
==============================================================================
--- stable/12/sys/ufs/ffs/fs.h Wed Mar 6 23:31:42 2019 (r344859)
+++ stable/12/sys/ufs/ffs/fs.h Wed Mar 6 23:54:55 2019 (r344860)
@@ -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.
More information about the svn-src-all
mailing list