Date: Wed, 6 Mar 2019 23:54:55 +0000 (UTC) From: Kirk McKusick <mckusick@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org Subject: svn commit: r344860 - in stable/12: sbin/fsck_ffs sbin/fsdb sys/ufs/ffs Message-ID: <201903062354.x26NstKN086003@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
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.
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201903062354.x26NstKN086003>