]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
repair: fix quota inode handling in secondary superblocks
authorDave Chinner <dchinner@redhat.com>
Tue, 8 Jul 2014 00:36:39 +0000 (10:36 +1000)
committerDave Chinner <david@fromorbit.com>
Tue, 8 Jul 2014 00:36:39 +0000 (10:36 +1000)
Changes to support separate project quota inodes changed the way
quota inodes got written to the superblock. The current code is
tailored for the needs to the kernel, where the inodes should only
be written if certain falgs are set saying a quota type is enabled.

Unfortunately, when recovering a corrupt secondary superblock, we
need to unconditionally write the quota inode fields after we
unconditionally zero the quota flags field. The result of this bug
is that the bad quota inode fields cannot be cleared and hence
always are reported by bad by repair in subsequent runs.

Fix this by directly clearing the quota inodes in the superblock
buffers so that we do need to set special flags to get
xfs_sb_to_disk() to do the right thing as setting flags leave bad
flag values in the superblock instead of bad inode numbers....

Also, when clearing the inode numbers, write them as NULLFSINO
rather than 0 as this is what the kernel will write them as if quota
is turned off.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Dave Chinner <david@fromorbit.com>
include/libxfs.h
libxfs/rdwr.c
repair/agheader.c
repair/sb.c
repair/scan.c

index 7203d7993bba35a3ba7f0ac7ccd530ad04ef6747..45a924fc90dfff4d59742c71bf26328390b226b2 100644 (file)
@@ -759,6 +759,7 @@ bool xfs_dinode_verify(struct xfs_mount *mp, xfs_ino_t ino,
 /* xfs_sb.h */
 #define libxfs_mod_sb                  xfs_mod_sb
 #define libxfs_sb_from_disk            xfs_sb_from_disk
+#define libxfs_sb_quota_from_disk      xfs_sb_quota_from_disk
 #define libxfs_sb_to_disk              xfs_sb_to_disk
 
 /* xfs_symlink.h */
index 9743d04a2870b3d61c3b2568f72a46c239685a15..0294c98dd5af1e87f10a1383c64a0901206da721 100644 (file)
@@ -944,10 +944,10 @@ libxfs_writebufr(xfs_buf_t *bp)
        }
 
 #ifdef IO_DEBUG
-       printf("%lx: %s: wrote %u bytes, blkno=%llu(%llu), %p\n",
+       printf("%lx: %s: wrote %u bytes, blkno=%llu(%llu), %p, error %d\n",
                        pthread_self(), __FUNCTION__, bp->b_bcount,
                        (long long)LIBXFS_BBTOOFF64(bp->b_bn),
-                       (long long)bp->b_bn, bp);
+                       (long long)bp->b_bn, bp, error);
 #endif
        if (!error) {
                bp->b_flags |= LIBXFS_B_UPTODATE;
index fc5dac93e8b7f77a3664bd19eb92ba879fc2b4f7..416dbd833959b4c701e41a98585c007435a5c267 100644 (file)
@@ -245,13 +245,17 @@ compare_sb(xfs_mount_t *mp, xfs_sb_t *sb)
  * superblocks, not just the secondary superblocks.
  */
 static int
-secondary_sb_wack(xfs_mount_t *mp, xfs_buf_t *sbuf, xfs_sb_t *sb,
-       xfs_agnumber_t i)
+secondary_sb_wack(
+       struct xfs_mount *mp,
+       struct xfs_buf  *sbuf,
+       struct xfs_sb   *sb,
+       xfs_agnumber_t  i)
 {
-       int do_bzero;
-       int size;
-       char *ip;
-       int rval;
+       struct xfs_dsb  *dsb = XFS_BUF_TO_SBP(sbuf);
+       int             do_bzero = 0;
+       int             size;
+       char            *ip;
+       int             rval = 0;;
 
        rval = do_bzero = 0;
 
@@ -334,12 +338,18 @@ secondary_sb_wack(xfs_mount_t *mp, xfs_buf_t *sbuf, xfs_sb_t *sb,
        }
 
        /*
-        * quota inodes and flags in secondary superblocks
-        * are never set by mkfs.  However, they could be set
-        * in a secondary if a fs with quotas was growfs'ed since
-        * growfs copies the new primary into the secondaries.
+        * quota inodes and flags in secondary superblocks are never set by
+        * mkfs.  However, they could be set in a secondary if a fs with quotas
+        * was growfs'ed since growfs copies the new primary into the
+        * secondaries.
+        *
+        * Also, the in-core inode flags now have different meaning to the
+        * on-disk flags, and so libxfs_sb_to_disk cannot directly write the
+        * sb_gquotino/sb_pquotino fields without specific sb_qflags being set.
+        * Hence we need to zero those fields directly in the sb buffer here.
         */
-       if (sb->sb_inprogress == 1 && sb->sb_uquotino)  {
+
+       if (sb->sb_inprogress == 1 && sb->sb_uquotino != NULLFSINO)  {
                if (!no_modify)
                        sb->sb_uquotino = 0;
                if (sb->sb_versionnum & XR_PART_SECSB_VNMASK || !do_bzero)  {
@@ -352,9 +362,11 @@ secondary_sb_wack(xfs_mount_t *mp, xfs_buf_t *sbuf, xfs_sb_t *sb,
                        rval |= XR_AG_SB_SEC;
        }
 
-       if (sb->sb_inprogress == 1 && sb->sb_gquotino)  {
-               if (!no_modify)
+       if (sb->sb_inprogress == 1 && sb->sb_gquotino != NULLFSINO)  {
+               if (!no_modify) {
                        sb->sb_gquotino = 0;
+                       dsb->sb_gquotino = 0;
+               }
                if (sb->sb_versionnum & XR_PART_SECSB_VNMASK || !do_bzero)  {
                        rval |= XR_AG_SB;
                        do_warn(
@@ -365,9 +377,11 @@ secondary_sb_wack(xfs_mount_t *mp, xfs_buf_t *sbuf, xfs_sb_t *sb,
                        rval |= XR_AG_SB_SEC;
        }
 
-       if (sb->sb_inprogress == 1 && sb->sb_pquotino)  {
-               if (!no_modify)
+       if (sb->sb_inprogress == 1 && sb->sb_pquotino != NULLFSINO)  {
+               if (!no_modify) {
                        sb->sb_pquotino = 0;
+                       dsb->sb_pquotino = 0;
+               }
                if (sb->sb_versionnum & XR_PART_SECSB_VNMASK || !do_bzero)  {
                        rval |= XR_AG_SB;
                        do_warn(
index 5e0b0f268456ff0fe8e872171149307cfe1fc1d9..bc421cca78db65e28bd5fc0fcb76cdbe3de3179e 100644 (file)
@@ -138,6 +138,7 @@ find_secondary_sb(xfs_sb_t *rsb)
                for (i = 0; !done && i < bsize; i += BBSIZE)  {
                        c_bufsb = (char *)sb + i;
                        libxfs_sb_from_disk(&bufsb, (xfs_dsb_t *)c_bufsb);
+                       libxfs_sb_quota_from_disk(&bufsb);
 
                        if (verify_sb(c_bufsb, &bufsb, 0) != XR_OK)
                                continue;
@@ -538,6 +539,7 @@ get_sb(xfs_sb_t *sbp, xfs_off_t off, int size, xfs_agnumber_t agno)
                do_error("%s\n", strerror(error));
        }
        libxfs_sb_from_disk(sbp, buf);
+       libxfs_sb_quota_from_disk(sbp);
 
        rval = verify_sb((char *)buf, sbp, agno == 0);
        free(buf);
index 1b64d8b84f1653a45ba083805762ecda1e80f72e..f29ff8d6cc311bce8df36515a17481d1e21f9336 100644 (file)
@@ -1496,6 +1496,7 @@ scan_ag(
                goto out_free_sb;
        }
        libxfs_sb_from_disk(sb, XFS_BUF_TO_SBP(sbbuf));
+       libxfs_sb_quota_from_disk(sb);
 
        agfbuf = libxfs_readbuf(mp->m_dev,
                        XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)),