[Libguestfs] [PATCH 4/5] resize2fs: Run 'e2fsck -f' automatically if filesystem is not mounted.

Richard W.M. Jones rjones at redhat.com
Fri Mar 9 18:14:08 UTC 2012


From: "Richard W.M. Jones" <rjones at redhat.com>

---
 daemon/daemon.h                |    1 +
 daemon/ext2.c                  |   37 ++++++++++++++++++++++++++++++++++
 daemon/mount.c                 |   43 ++++++++++++++++++++++++++++++++++++++++
 generator/generator_actions.ml |   13 +----------
 resize/resize.ml               |    4 +--
 5 files changed, 84 insertions(+), 14 deletions(-)

diff --git a/daemon/daemon.h b/daemon/daemon.h
index c45a7fe..b515fe4 100644
--- a/daemon/daemon.h
+++ b/daemon/daemon.h
@@ -111,6 +111,7 @@ extern uint64_t optargs_bitmask;
 
 /*-- in mount.c --*/
 extern int is_root_mounted (void);
+extern int is_device_mounted (const char *device);
 
 /*-- in stubs.c (auto-generated) --*/
 extern void dispatch_incoming_message (XDR *);
diff --git a/daemon/ext2.c b/daemon/ext2.c
index a427d7a..09037fb 100644
--- a/daemon/ext2.c
+++ b/daemon/ext2.c
@@ -187,6 +187,34 @@ do_get_e2uuid (const char *device)
   return do_vfs_uuid (device);
 }
 
+/* If the filesystem is not mounted, run e2fsck -f on it unconditionally. */
+static int
+if_not_mounted_run_e2fsck (const char *device)
+{
+  char *err;
+  int r, mounted;
+  char prog[] = "e2fsck";
+
+  if (e2prog (prog) == -1)
+    return -1;
+
+  mounted = is_device_mounted (device);
+  if (mounted == -1)
+    return -1;
+
+  if (!mounted) {
+    r = command (NULL, &err, prog, "-fy", device, NULL);
+    if (r == -1) {
+      reply_with_error ("%s", err);
+      free (err);
+      return -1;
+    }
+    free (err);
+  }
+
+  return 0;
+}
+
 int
 do_resize2fs (const char *device)
 {
@@ -197,6 +225,9 @@ do_resize2fs (const char *device)
   if (e2prog (prog) == -1)
     return -1;
 
+  if (if_not_mounted_run_e2fsck (device) == -1)
+    return -1;
+
   r = command (NULL, &err, prog, device, NULL);
   if (r == -1) {
     reply_with_error ("%s", err);
@@ -229,6 +260,9 @@ do_resize2fs_size (const char *device, int64_t size)
   }
   size /= 1024;
 
+  if (if_not_mounted_run_e2fsck (device) == -1)
+    return -1;
+
   char buf[32];
   snprintf (buf, sizeof buf, "%" PRIi64 "K", size);
 
@@ -253,6 +287,9 @@ do_resize2fs_M (const char *device)
   if (e2prog (prog) == -1)
     return -1;
 
+  if (if_not_mounted_run_e2fsck (device) == -1)
+    return -1;
+
   r = command (NULL, &err, prog, "-M", device, NULL);
   if (r == -1) {
     reply_with_error ("%s", err);
diff --git a/daemon/mount.c b/daemon/mount.c
index 98b9488..0c393f7 100644
--- a/daemon/mount.c
+++ b/daemon/mount.c
@@ -65,6 +65,49 @@ is_root_mounted (void)
   return 0;
 }
 
+/* Return true iff 'device' is mounted under /sysroot.
+ *   1  : true, device is mounted
+ *   0  : false, device is not mounted
+ *   -1 : error, reply_with_* has been called
+ */
+int
+is_device_mounted (const char *device)
+{
+  FILE *fp;
+  struct mntent *m;
+  struct stat stat1, stat2;
+
+  if (stat (device, &stat1) == -1) {
+    reply_with_perror ("stat: %s", device);
+    return -1;
+  }
+
+  /* NB: Eventually we should aim to parse /proc/self/mountinfo, but
+   * that requires custom parsing code.
+   */
+  fp = setmntent ("/proc/mounts", "r");
+  if (fp == NULL) {
+    perror ("/proc/mounts");
+    exit (EXIT_FAILURE);
+  }
+
+  while ((m = getmntent (fp)) != NULL) {
+    if ((sysroot_len > 0 && STREQ (m->mnt_dir, sysroot)) ||
+        (STRPREFIX (m->mnt_dir, sysroot) && m->mnt_dir[sysroot_len] == '/')) {
+      if (stat (m->mnt_fsname, &stat2) == 0) {
+        if (stat1.st_rdev == stat2.st_rdev) {
+          /* found it */
+          endmntent (fp);
+          return 1;
+        }
+      }
+    }
+  }
+
+  endmntent (fp);
+  return 0;
+}
+
 /* The "simple mount" call offers no complex options, you can just
  * mount a device on a mountpoint.  The variations like mount_ro,
  * mount_options and mount_vfs let you set progressively more things.
diff --git a/generator/generator_actions.ml b/generator/generator_actions.ml
index b859e5f..3c87d6d 100644
--- a/generator/generator_actions.ml
+++ b/generator/generator_actions.ml
@@ -3502,13 +3502,7 @@ is lost.");
    "resize an ext2, ext3 or ext4 filesystem",
    "\
 This resizes an ext2, ext3 or ext4 filesystem to match the size of
-the underlying device.
-
-I<Note:> It is sometimes required that you run C<guestfs_e2fsck_f>
-on the C<device> before calling this command.  For unknown reasons
-C<resize2fs> sometimes gives an error about this and sometimes not.
-In any case, it is always safe to call C<guestfs_e2fsck_f> before
-calling this function.");
+the underlying device.");
 
   ("find", (RStringList "names", [Pathname "directory"], []), 107, [ProtocolLimitWarning],
    [InitBasicFS, Always, TestOutputList (
@@ -3557,10 +3551,7 @@ See also C<guestfs_find0>.");
    "\
 This runs C<e2fsck -p -f device>, ie. runs the ext2/ext3
 filesystem checker on C<device>, noninteractively (I<-p>),
-even if the filesystem appears to be clean (I<-f>).
-
-This command is only needed because of C<guestfs_resize2fs>
-(q.v.).  Normally you should use C<guestfs_fsck>.");
+even if the filesystem appears to be clean (I<-f>).");
 
   ("sleep", (RErr, [Int "secs"], []), 109, [],
    [InitNone, Always, TestRun (
diff --git a/resize/resize.ml b/resize/resize.ml
index 675a6e1..407d80f 100644
--- a/resize/resize.ml
+++ b/resize/resize.ml
@@ -1120,9 +1120,7 @@ let () =
     (* Helper function to expand partition or LV content. *)
     let do_expand_content target = function
       | PVResize -> g#pvresize target
-      | Resize2fs ->
-          g#e2fsck_f target;
-          g#resize2fs target
+      | Resize2fs -> g#resize2fs target
       | NTFSResize -> g#ntfsresize_opts ~force:ntfsresize_force target
       | BtrfsFilesystemResize ->
           (* Complicated ...  Btrfs forces us to mount the filesystem
-- 
1.7.9.1




More information about the Libguestfs mailing list