Maxim Perevedentsev
2015-Oct-22 17:05 UTC
[Libguestfs] [PATCH] Added btrfs support for vfs_min_size.
---
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
Richard W.M. Jones
2015-Oct-23 09:13 UTC
Re: [Libguestfs] [PATCH] Added btrfs support for vfs_min_size.
On Thu, Oct 22, 2015 at 08:05:37PM +0300, Maxim Perevedentsev wrote:> +/* 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);Let's move variable decls to the top of the function, and add a newline between variable decls and the rest of the code.> + 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);Same here.> + 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) > +{This function now exists in daemon/mount.c and here. It should be shared. Just make the function in daemon/mount.c non-static, and declare it in daemon/guestfsd.h, and you don't need the copy.> + 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)>." }; > > ] >The rest looks fine to me. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com virt-top is 'top' for virtual machines. Tiny program with many powerful monitoring features, net stats, disk stats, logging, etc. http://people.redhat.com/~rjones/virt-top
Maxim Perevedentsev
2015-Oct-23 15:48 UTC
Re: [Libguestfs] [PATCH] Added btrfs support for vfs_min_size.
On 23.10.2015 12:13, Richard W.M. Jones wrote:> On Thu, Oct 22, 2015 at 08:05:37PM +0300, Maxim Perevedentsev wrote: >> +static char* >> +get_mount_point (const char *device) >> +{ > This function now exists in daemon/mount.c and here. It should > be shared. Just make the function in daemon/mount.c non-static, > and declare it in daemon/guestfsd.h, and you don't need the copy.There's a difference in this function and mount.c: is_device_mounted() get_mount_point: return ANY of mount points for specific device. is_device_mounted: return whether a device has a mountpoint under /sysroot Even is_device_mounted() { return (get_mount_point() != NULL); } may not work in case of multiple mountpoints, some under /sysroot and others - not. So it's not obvious how to merge(?) these functions. Other way is to use do_mountpoints() and check the returned hash (but this will have malloc overhead). -- С уважением, Максим Переведенцев Your sincerely, Maxim Perevedentsev
Possibly Parallel Threads
- [PATCHv3] Added btrfs support to vfs_minimum_size.
- Re: [PATCH] Added btrfs support for vfs_min_size.
- [PATCHv2] Added btrfs support for vfs_min_size.
- [PATCHv3 0/2] Introduce vfs_min_size API to get minimum filesystem size.
- [PATCHv3 2/2] Include resize2fs_P into vfs_min_size.