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 */
 
 /*
  * Command structure passed in to the filesystem to adjust filesystem values.
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to