]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
repair: handle repair of image files on large sector size filesystems
authorDave Chinner <dchinner@redhat.com>
Mon, 10 Oct 2011 01:08:31 +0000 (01:08 +0000)
committerAlex Elder <aelder@sgi.com>
Thu, 13 Oct 2011 10:01:11 +0000 (05:01 -0500)
Because repair uses direct IO, it cannot do IO smaller than a sector
on the underlying device. When repairing a filesystem image, the
filesystem hosting the image may have a sector size larger than the
sector size of the image, and so single image sector reads and
writes will fail.

To avoid this, when checking a file and there is a sector size
mismatch like this, turn off direct IO. While there, fix a compile
bug in the IO_DEBUG option for libxfs which was found during triage.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Alex Elder <aelder@sgi.com>
libxfs/rdwr.c
repair/sb.c
repair/xfs_repair.c

index fe8ae09801b6c7980a7b031344ad30f8c336b251..c3edb89e1fb0a94f1c8abac2481d197b0b8bf0fe 100644 (file)
@@ -365,7 +365,7 @@ libxfs_getbufr(dev_t device, xfs_daddr_t blkno, int bblen)
                libxfs_initbuf(bp, device, blkno, blen);
 #ifdef IO_DEBUG
        printf("%lx: %s: allocated %u bytes buffer, key=%llu(%llu), %p\n",
-               pthread_self(), __FUNCTION__, BBTOB(len),
+               pthread_self(), __FUNCTION__, blen,
                (long long)LIBXFS_BBTOOFF64(blkno), (long long)blkno, bp);
 #endif
 
index 6d2e91abf5732808ba3924c92b7d320ed9079101..004319f47e8f67b31a9baf161dbbea785f7cf3fc 100644 (file)
@@ -689,7 +689,14 @@ verify_set_primary_sb(xfs_sb_t             *rsb,
         */
        num_sbs = MIN(NUM_SBS, rsb->sb_agcount);
        skip = howmany(num_sbs, rsb->sb_agcount);
-       size = NUM_AGH_SECTS * rsb->sb_sectsize;
+
+       /*
+        * We haven't been able to validate the sector size yet properly
+        * (e.g. in the case of repairing an image in a file), so we need to
+        * take into account sector mismatches and so use the maximum possible
+        * sector size rather than the sector size in @rsb.
+        */
+       size = NUM_AGH_SECTS * (1 << (XFS_MAX_SECTORSIZE_LOG));
        retval = 0;
        list = NULL;
        num_ok = 0;
index 4e2b022b92a0b11963c3e002fa6f49afb1c55c6e..69b7eabf499bcf1bb82747115e5c94f851ed82ee 100644 (file)
@@ -569,6 +569,35 @@ main(int argc, char **argv)
        memset(&xfs_m, 0, sizeof(xfs_mount_t));
        libxfs_sb_from_disk(&xfs_m.m_sb, XFS_BUF_TO_SBP(sbp));
 
+       /*
+        * if the sector size of the filesystem we are trying to repair is
+        * smaller than that of the underlying filesystem (i.e. we are repairing
+        * an image), the we have to turn off direct IO because we cannot do IO
+        * smaller than the host filesystem's sector size.
+        */
+       if (isa_file) {
+               int     fd = libxfs_device_to_fd(x.ddev);
+               struct xfs_fsop_geom_v1 geom = { 0 };
+
+               if (ioctl(fd, XFS_IOC_FSGEOMETRY_V1, &geom) < 0) {
+                       do_warn(_("Cannot get host filesystem geometry.\n"
+               "Repair may fail if there is a sector size mismatch between\n"
+               "the image and the host filesystem.\n"));
+                       geom.sectsize = BBSIZE;
+               }
+
+               if (xfs_m.m_sb.sb_sectsize < geom.sectsize) {
+                       long    old_flags;
+
+                       old_flags = fcntl(fd, F_GETFL, 0);
+                       if (fcntl(fd, F_SETFL, old_flags & ~O_DIRECT) < 0) {
+                               do_warn(_(
+               "Sector size on host filesystem larger than image sector size.\n"
+               "Cannot turn off direct IO, so exiting.\n"));
+                               exit(1);
+                       }
+               }
+       }
        mp = libxfs_mount(&xfs_m, &xfs_m.m_sb, x.ddev, x.logdev, x.rtdev, 0);
 
        if (!mp)  {