[Libguestfs] [PATCH] Added btrfs support for vfs_min_size.

Maxim Perevedentsev mperevedentsev at virtuozzo.com
Thu Oct 22 17:05:37 UTC 2015


---
 daemon/btrfs.c       | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 daemon/daemon.h      |  1 +
 daemon/fs-min-size.c | 50 ++++++++++++++++++++++++++++++++++++-
 generator/actions.ml |  6 ++++-
 4 files changed, 124 insertions(+), 2 deletions(-)

diff --git a/daemon/btrfs.c b/daemon/btrfs.c
index ddb029d..d2d85f3 100644
--- a/daemon/btrfs.c
+++ b/daemon/btrfs.c
@@ -2190,3 +2190,72 @@ do_btrfs_replace (const char *srcdev, const char *targetdev,

   return 0;
 }
+
+/* btrfs command add a new command
+ * inspect-internal min-dev-size <path>
+ * since v4.2
+ * We could check whether 'btrfs' supports
+ * 'min-dev-size' command by checking the output of
+ * 'btrfs --help' command.
+ */
+static int
+test_btrfs_min_dev_size (void)
+{
+  CLEANUP_FREE char *err = NULL, *out = NULL;
+  static int result = -1;
+  if (result != -1)
+    return result;
+
+  const char *cmd_pattern = "btrfs inspect-internal min-dev-size";
+
+  int r = commandr (&out, &err, str_btrfs, "--help", NULL);
+
+  if (r == -1) {
+    reply_with_error ("btrfs: %s", err);
+    return -1;
+  }
+
+  if (strstr (out, cmd_pattern) == NULL)
+    result = 0;
+  else
+    result = 1;
+
+  return result;
+}
+
+int64_t
+btrfs_minimum_size (const char *path)
+{
+  CLEANUP_FREE char *err = NULL, *out = NULL;
+  int64_t ret = 0;
+  int min_size_supported = test_btrfs_min_dev_size ();
+  if (min_size_supported == -1)
+    return -1;
+  else if (min_size_supported == 0)
+    NOT_SUPPORTED (-1, "'btrfs inspect-internal min-dev-size' \
+                        needs btrfs-progs >= 4.2");
+
+  int r = command (&out, &err, str_btrfs, "inspect-internal",
+                   "min-dev-size", path, NULL);
+
+  if (r == -1) {
+    reply_with_error ("%s", err);
+    return -1;
+  }
+
+#if __WORDSIZE == 64
+#define XSTRTOD64 xstrtol
+#else
+#define XSTRTOD64 xstrtoll
+#endif
+
+  if (XSTRTOD64 (out, NULL, 10, &ret, NULL) != LONGINT_OK) {
+    reply_with_error ("cannot parse minimum size");
+    return -1;
+  }
+
+#undef XSTRTOD64
+
+  return ret;
+}
+
diff --git a/daemon/daemon.h b/daemon/daemon.h
index 8bcc9bd..4a969dd 100644
--- a/daemon/daemon.h
+++ b/daemon/daemon.h
@@ -280,6 +280,7 @@ extern char *btrfs_get_label (const char *device);
 extern int btrfs_set_label (const char *device, const char *label);
 extern int btrfs_set_uuid (const char *device, const char *uuid);
 extern int btrfs_set_uuid_random (const char *device);
+extern int64_t btrfs_minimum_size (const char *path);

 /*-- in ntfs.c --*/
 extern char *ntfs_get_label (const char *device);
diff --git a/daemon/fs-min-size.c b/daemon/fs-min-size.c
index 4f93f8c..cb67b6f 100644
--- a/daemon/fs-min-size.c
+++ b/daemon/fs-min-size.c
@@ -21,16 +21,57 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
+#include <mntent.h>
+#include <sys/stat.h>
+#include <sys/types.h>

 #include "daemon.h"
 #include "actions.h"

+static char*
+get_mount_point (const char *device)
+{
+  FILE *fp;
+  struct mntent *m;
+  struct stat stat1, stat2;
+  char *path;
+
+  if (stat (device, &stat1) == -1) {
+    reply_with_perror ("stat: %s", device);
+    return NULL;
+  }
+
+  /* NB: Eventually we should aim to parse /proc/self/mountinfo, but
+   * that requires custom parsing code.
+   */
+  fp = setmntent ("/proc/mounts", "r");
+  if (fp == NULL) {
+    fprintf (stderr, "setmntent: %s: %m\n", "/proc/mounts");
+    exit (EXIT_FAILURE);
+  }
+
+  while ((m = getmntent (fp)) != NULL) {
+      if (stat (m->mnt_fsname, &stat2) == 0) {
+        if (stat1.st_rdev == stat2.st_rdev) {
+          /* found it */
+		   path = strdup (m->mnt_dir);
+          endmntent (fp);
+          return path;
+        }
+      }
+  }
+
+  endmntent (fp);
+  reply_with_error ("device not mounted: %s", device);
+  return NULL;
+}
+
 int64_t
 do_vfs_minimum_size (const mountable_t *mountable)
 {
   int64_t r;

-  /* How we set the label depends on the filesystem type. */
+  /* How we get minimum size depends on the filesystem type. */
   CLEANUP_FREE char *vfs_type = do_vfs_type (mountable);
   if (vfs_type == NULL)
     return -1;
@@ -41,6 +82,13 @@ do_vfs_minimum_size (const mountable_t *mountable)
   else if (STREQ (vfs_type, "ntfs"))
     r = ntfs_minimum_size (mountable->device);

+  else if (STREQ (vfs_type, "btrfs")) {
+    CLEANUP_FREE char *path = get_mount_point (mountable->device);
+    if (path == NULL)
+      return -1;
+    r = btrfs_minimum_size (path);
+  }
+
   else
     NOT_SUPPORTED (-1, "don't know how to get minimum size of '%s' filesystems",
                    vfs_type);
diff --git a/generator/actions.ml b/generator/actions.ml
index 62176ab..8832410 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -12761,6 +12761,10 @@ To read the UUID on a filesystem, call C<guestfs_vfs_uuid>." };
       InitPartition, IfAvailable "ntfsprogs", TestRun(
         [["mkfs"; "ntfs"; "/dev/sda1"; ""; "NOARG"; ""; ""; "NOARG"];
          ["vfs_minimum_size"; "/dev/sda1"]]), [];
+      InitPartition, Always, TestRun (
+        [["mkfs"; "btrfs"; "/dev/sda1"; ""; "NOARG"; ""; ""; "NOARG"];
+         ["mount"; "/dev/sda1"; "/"];
+         ["vfs_minimum_size"; "/dev/sda1"]]), [];
     ];
     shortdesc = "get minimum filesystem size";
     longdesc = "\
@@ -12770,7 +12774,7 @@ This is the minimum possible size for filesystem shrinking.
 If getting minimum size of specified filesystem is not supported,
 this will fail and set errno as ENOTSUP.

-See also L<ntfsresize(8)>, L<resize2fs(8)>." };
+See also L<ntfsresize(8)>, L<resize2fs(8)>, L<btrfs(8)>." };

 ]

--
1.8.3.1




More information about the Libguestfs mailing list