[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
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
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
participants (2)
-
Maxim Perevedentsev -
Richard W.M. Jones