On Wed, Mar 06, 2019 at 11:59:56PM +0000, Kirk McKusick wrote: > Author: mckusick > Date: Wed Mar 6 23:59:56 2019 > New Revision: 344861 > URL: https://svnweb.freebsd.org/changeset/base/344861 > > 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/11/sbin/fsck_ffs/fsck.h > stable/11/sbin/fsck_ffs/globs.c > stable/11/sbin/fsck_ffs/inode.c > stable/11/sbin/fsck_ffs/pass1.c > stable/11/sbin/fsck_ffs/setup.c > stable/11/sbin/fsdb/fsdb.c > stable/11/sys/ufs/ffs/ffs_alloc.c > stable/11/sys/ufs/ffs/fs.h > Directory Properties: > stable/11/ (props changed) > > Modified: stable/11/sbin/fsck_ffs/fsck.h > ============================================================================== > --- stable/11/sbin/fsck_ffs/fsck.h Wed Mar 6 23:54:55 2019 > (r344860) > +++ stable/11/sbin/fsck_ffs/fsck.h Wed Mar 6 23:59:56 2019 > (r344861) > @@ -230,6 +230,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 */ > @@ -289,6 +290,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/11/sbin/fsck_ffs/globs.c > ============================================================================== > --- stable/11/sbin/fsck_ffs/globs.c Wed Mar 6 23:54:55 2019 > (r344860) > +++ stable/11/sbin/fsck_ffs/globs.c Wed Mar 6 23:59:56 2019 > (r344861) > @@ -61,6 +61,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 > */ > @@ -128,6 +129,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/11/sbin/fsck_ffs/inode.c > ============================================================================== > --- stable/11/sbin/fsck_ffs/inode.c Wed Mar 6 23:54:55 2019 > (r344860) > +++ stable/11/sbin/fsck_ffs/inode.c Wed Mar 6 23:59:56 2019 > (r344861) > @@ -124,9 +124,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/11/sbin/fsck_ffs/pass1.c > ============================================================================== > --- stable/11/sbin/fsck_ffs/pass1.c Wed Mar 6 23:54:55 2019 > (r344860) > +++ stable/11/sbin/fsck_ffs/pass1.c Wed Mar 6 23:59:56 2019 > (r344861) > @@ -245,6 +245,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) > @@ -375,6 +376,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; > @@ -420,6 +422,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); > @@ -521,5 +563,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/11/sbin/fsck_ffs/setup.c > ============================================================================== > --- stable/11/sbin/fsck_ffs/setup.c Wed Mar 6 23:54:55 2019 > (r344860) > +++ stable/11/sbin/fsck_ffs/setup.c Wed Mar 6 23:59:56 2019 > (r344861) > @@ -134,6 +134,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/11/sbin/fsdb/fsdb.c > ============================================================================== > --- stable/11/sbin/fsdb/fsdb.c Wed Mar 6 23:54:55 2019 > (r344860) > +++ stable/11/sbin/fsdb/fsdb.c Wed Mar 6 23:59:56 2019 > (r344861) > @@ -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 }, > @@ -1009,6 +1011,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/11/sys/ufs/ffs/ffs_alloc.c > ============================================================================== > --- stable/11/sys/ufs/ffs/ffs_alloc.c Wed Mar 6 23:54:55 2019 > (r344860) > +++ stable/11/sys/ufs/ffs/ffs_alloc.c Wed Mar 6 23:59:56 2019 > (r344861) > @@ -2688,6 +2688,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] > @@ -2729,6 +2731,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"); > > @@ -2875,6 +2880,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/11/sys/ufs/ffs/fs.h > ============================================================================== > --- stable/11/sys/ufs/ffs/fs.h Wed Mar 6 23:54:55 2019 > (r344860) > +++ stable/11/sys/ufs/ffs/fs.h Wed Mar 6 23:59:56 2019 > (r344861) > @@ -219,7 +219,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 */
Hey Kirk, This MFC breaks buildworld: http://jenkins.hardenedbsd.org/jenkins/job/HardenedBSD-11-STABLE-amd64/904/console I'll take a look at providing a patch to fix it soon, unless you're able to get to it before I am. Thanks, -- Shawn Webb Cofounder and Security Engineer HardenedBSD Tor-ified Signal: +1 443-546-8752 Tor+XMPP+OTR: latt...@is.a.hacker.sx GPG Key ID: 0x6A84658F52456EEE GPG Key Fingerprint: 2ABA B6BD EF6A F486 BE89 3D9E 6A84 658F 5245 6EEE
signature.asc
Description: PGP signature