Maxim Perevedentsev
2015-Oct-16 16:44 UTC
[Libguestfs] [PATCH 0/2] Introduce get_min_size API to get minimum filesystem size.
Tried to make it in accordance with your comments. Maybe you can suggest a better name for API? Maxim Perevedentsev (2): New API: get_min_size Include resize2fs_P into get_min_size. daemon/Makefile.am | 1 + daemon/daemon.h | 2 ++ daemon/ext2.c | 37 ++++++++++++++++++++++++---- daemon/fs-min-size.c | 49 +++++++++++++++++++++++++++++++++++++ daemon/ntfs.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++ generator/actions.ml | 15 +++++++----- po/POTFILES | 1 + 7 files changed, 162 insertions(+), 11 deletions(-) create mode 100644 daemon/fs-min-size.c -- 1.8.3.1
This call provides the way to get minimum size of filesystem. This is needed for shrinking. The return units are bytes. --- daemon/Makefile.am | 1 + daemon/daemon.h | 1 + daemon/fs-min-size.c | 46 +++++++++++++++++++++++++++++++++++ daemon/ntfs.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++ generator/actions.ml | 15 ++++++++++++ po/POTFILES | 1 + src/MAX_PROC_NR | 2 +- 7 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 daemon/fs-min-size.c diff --git a/daemon/Makefile.am b/daemon/Makefile.am index 4ea3c88..0a01a24 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -116,6 +116,7 @@ guestfsd_SOURCES = \ findfs.c \ fill.c \ find.c \ + fs-min-size.c \ fsck.c \ fstrim.c \ glob.c \ diff --git a/daemon/daemon.h b/daemon/daemon.h index 508691a..8287a99 100644 --- a/daemon/daemon.h +++ b/daemon/daemon.h @@ -283,6 +283,7 @@ extern int btrfs_set_uuid_random (const char *device); /*-- in ntfs.c --*/ extern char *ntfs_get_label (const char *device); extern int ntfs_set_label (const char *device, const char *label); +extern int64_t ntfs_get_min_size (const char *device); /*-- in swap.c --*/ extern int swap_set_uuid (const char *device, const char *uuid); diff --git a/daemon/fs-min-size.c b/daemon/fs-min-size.c new file mode 100644 index 0000000..12448c0 --- /dev/null +++ b/daemon/fs-min-size.c @@ -0,0 +1,46 @@ +/* libguestfs - the guestfsd daemon + * Copyright (C) 2012 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include "daemon.h" +#include "actions.h" + +int64_t +do_get_min_size(const mountable_t *mountable) +{ + int64_t r; + + /* How we set the label depends on the filesystem type. */ + CLEANUP_FREE char *vfs_type = do_vfs_type (mountable); + if (vfs_type == NULL) + return -1; + + else if (STREQ (vfs_type, "ntfs")) + r = ntfs_get_min_size (mountable->device); + + else + NOT_SUPPORTED (-1, "don't know how to get minimum size of '%s' filesystems", + vfs_type); + + return r; +} diff --git a/daemon/ntfs.c b/daemon/ntfs.c index 1ead159..fd77716 100644 --- a/daemon/ntfs.c +++ b/daemon/ntfs.c @@ -153,6 +153,74 @@ do_ntfsresize_size (const char *device, int64_t size) return do_ntfsresize (device, size, 0); } +int64_t +ntfs_get_min_size (const char *device) +{ + CLEANUP_FREE char *err = NULL, *out = NULL; + CLEANUP_FREE_STRING_LIST char **lines = NULL; + int r; + size_t i; + char *p; + int64_t ret, volume_size = 0; + const char *size_pattern = "You might resize at ", + *full_pattern = "Volume is full", + *cluster_size_pattern = "Cluster size", + *volume_size_pattern = "Current volume size:"; + int is_full = 0; + int32_t cluster_size = 0; + + /* FS may be marked for check, so force ntfsresize */ + r = command (&out, &err, str_ntfsresize, "--info", "-ff", device, NULL); + + lines = split_lines (out); + if (lines == NULL) + return -1; + + if (verbose) { + for (i = 0; lines[i] != NULL; ++i) + fprintf (stderr, "ntfs_min_size: lines[%zu] = \"%s\"\n", i, lines[i]); + } + + if (r == -1) { + /* If volume is full, ntfsresize returns error. */ + for (i = 0; lines[i] != NULL; ++i) { + if (strstr (lines[i], full_pattern)) + is_full = 1; + else if ((p = strstr (lines[i], cluster_size_pattern))) { + if (sscanf (p + strlen(cluster_size_pattern), + "%*[ ]:%" SCNd32, &cluster_size) != 1) + return -1; + } + else if ((p = strstr (lines[i], volume_size_pattern))) { + if (sscanf (p + strlen(volume_size_pattern), + "%" SCNd64, &volume_size) != 1) + return -1; + } + } + if (is_full) { + /* Ceil to cluster size */ + if (cluster_size == 0) { + reply_with_error("%s", "Bad cluster size"); + return -1; + } + return (volume_size + cluster_size - 1) / cluster_size * cluster_size; + } + + reply_with_error ("%s", err); + return -1; + } + + for (i = 0; lines[i] != NULL; ++i) { + if ((p = strstr (lines[i], size_pattern))) { + if (sscanf (p + strlen(size_pattern), "%" SCNd64, &ret) != 1) + return -1; + return ret; + } + } + + return -1; +} + /* Takes optional arguments, consult optargs_bitmask. */ int do_ntfsfix (const char *device, int clearbadsectors) diff --git a/generator/actions.ml b/generator/actions.ml index 274ef3f..e88dfe7 100644 --- a/generator/actions.ml +++ b/generator/actions.ml @@ -12765,6 +12765,21 @@ Get the estimated minimum filesystem size of an ext2/3/4 filesystem in blocks. See also L<resize2fs(8)>." }; + { defaults with + name = "get_min_size"; added = (1, 31, 18); + style = RInt64 "sizeinbytes", [Mountable "mountable"], []; + proc_nr = Some 458; + tests = [ + InitPartition, IfAvailable "ntfsprogs", TestRun( + [["mkfs"; "ntfs"; "/dev/sda1"; ""; "NOARG"; ""; ""; "NOARG"]; + ["get_min_size"; "/dev/sda1"]]), []; + ]; + shortdesc = "get minimum filesystem size"; + longdesc = "\ +Get the minimum size of filesystem in bytes. This is the minimum possible size for filesystem shrinking. + +See also L<ntfsresize(8)>." }; + ] (* Non-API meta-commands available only in guestfish. diff --git a/po/POTFILES b/po/POTFILES index cd2c437..d90772a 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -49,6 +49,7 @@ daemon/file.c daemon/fill.c daemon/find.c daemon/findfs.c +daemon/fs-min-size.c daemon/fsck.c daemon/fstrim.c daemon/glob.c diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR index de2a00c..c92ddb6 100644 --- a/src/MAX_PROC_NR +++ b/src/MAX_PROC_NR @@ -1 +1 @@ -457 +458 -- 1.8.3.1
Maxim Perevedentsev
2015-Oct-16 16:44 UTC
[Libguestfs] [PATCH 2/2] Include resize2fs_P into get_min_size.
--- daemon/daemon.h | 1 + daemon/ext2.c | 37 ++++++++++++++++++++++++++++++++----- daemon/fs-min-size.c | 3 +++ generator/actions.ml | 20 ++++---------------- src/MAX_PROC_NR | 2 +- 5 files changed, 41 insertions(+), 22 deletions(-) diff --git a/daemon/daemon.h b/daemon/daemon.h index 8287a99..0cd3964 100644 --- a/daemon/daemon.h +++ b/daemon/daemon.h @@ -224,6 +224,7 @@ extern int sync_disks (void); #define EXT2_LABEL_MAX 16 extern int fstype_is_extfs (const char *fstype); extern int ext_set_uuid_random (const char *device); +extern int64_t ext_get_min_size (const char *device); /*-- in blkid.c --*/ extern char *get_blkid_tag (const char *device, const char *tag); diff --git a/daemon/ext2.c b/daemon/ext2.c index 0cd6a66..fcf39de 100644 --- a/daemon/ext2.c +++ b/daemon/ext2.c @@ -279,8 +279,31 @@ do_resize2fs_M (const char *device) return 0; } +static int32_t +get_block_size (const char *device) +{ + CLEANUP_FREE_STRING_LIST char **params = NULL; + const char *block_pattern = "Block size"; + size_t i; + int32_t block_size; + + params = do_tune2fs_l (device); + if (params == NULL) + return -1; + + for (i = 0; params[i] != NULL; i += 2) { + if ((!strcmp (params[i], block_pattern))) { + if (sscanf (params[i + 1], "%" SCNd32, &block_size) != 1) + return -1; + return block_size; + } + } + + return -1; +} + int64_t -do_resize2fs_P (const char *device) +ext_get_min_size (const char *device) { CLEANUP_FREE char *err = NULL, *out = NULL; CLEANUP_FREE_STRING_LIST char **lines = NULL; @@ -288,6 +311,7 @@ do_resize2fs_P (const char *device) size_t i; char *p; int64_t ret; + int32_t block_size; const char *pattern = "Estimated minimum size of the filesystem: "; r = command (&out, &err, str_resize2fs, "-P", device, NULL); @@ -301,13 +325,16 @@ do_resize2fs_P (const char *device) return -1; for (i = 0; lines[i] != NULL; ++i) { - if (verbose) - fprintf (stderr, "resize2fs_P: lines[%zu] = \"%s\"\n", i, lines[i]); - if ((p = strstr (lines[i], pattern))) { if (sscanf (p + strlen(pattern), "%" SCNd64, &ret) != 1) return -1; - return ret; + if ((block_size = get_block_size (device)) == -1) + return -1; + if (verbose) { + fprintf(stderr, "Minimum size in blocks: %" SCNd64 \ + "\nBlock count: %" SCNd32 "\n", ret, block_size); + } + return ret * block_size; } } diff --git a/daemon/fs-min-size.c b/daemon/fs-min-size.c index 12448c0..81b589a 100644 --- a/daemon/fs-min-size.c +++ b/daemon/fs-min-size.c @@ -35,6 +35,9 @@ do_get_min_size(const mountable_t *mountable) if (vfs_type == NULL) return -1; + else if (fstype_is_extfs (vfs_type)) + r = ext_get_min_size (mountable->device); + else if (STREQ (vfs_type, "ntfs")) r = ntfs_get_min_size (mountable->device); diff --git a/generator/actions.ml b/generator/actions.ml index e88dfe7..5beda4a 100644 --- a/generator/actions.ml +++ b/generator/actions.ml @@ -12752,24 +12752,12 @@ Only some filesystem types support setting UUIDs. To read the UUID on a filesystem, call C<guestfs_vfs_uuid>." }; { defaults with - name = "resize2fs_P"; added = (1, 31, 17); - style = RInt64 "sizeinblocks", [Device "device"], []; - proc_nr = Some 457; - tests = [ - InitBasicFS, Always, TestRun ( - [["resize2fs_P"; "/dev/sda1"]]), []; - ]; - shortdesc = "get minimum filesystem size in blocks"; - longdesc = "\ -Get the estimated minimum filesystem size of an ext2/3/4 filesystem in blocks. - -See also L<resize2fs(8)>." }; - - { defaults with name = "get_min_size"; added = (1, 31, 18); style = RInt64 "sizeinbytes", [Mountable "mountable"], []; - proc_nr = Some 458; + proc_nr = Some 457; tests = [ + InitBasicFS, Always, TestRun ( + [["get_min_size"; "/dev/sda1"]]), []; InitPartition, IfAvailable "ntfsprogs", TestRun( [["mkfs"; "ntfs"; "/dev/sda1"; ""; "NOARG"; ""; ""; "NOARG"]; ["get_min_size"; "/dev/sda1"]]), []; @@ -12778,7 +12766,7 @@ See also L<resize2fs(8)>." }; longdesc = "\ Get the minimum size of filesystem in bytes. This is the minimum possible size for filesystem shrinking. -See also L<ntfsresize(8)>." }; +See also L<ntfsresize(8)>, L<resize2fs(8)>." }; ] diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR index c92ddb6..de2a00c 100644 --- a/src/MAX_PROC_NR +++ b/src/MAX_PROC_NR @@ -1 +1 @@ -458 +457 -- 1.8.3.1
Richard W.M. Jones
2015-Oct-16 20:55 UTC
Re: [Libguestfs] [PATCH 1/2] New API: get_min_size
On Fri, Oct 16, 2015 at 07:44:20PM +0300, Maxim Perevedentsev wrote:> This call provides the way to get minimum size of filesystem. > This is needed for shrinking. The return units are bytes.Shall we call it 'vfs_min_size'? There are already other 'vfs_*' functions like 'vfs_type' and 'vfs_label'.> +/* libguestfs - the guestfsd daemon > + * Copyright (C) 2012 Red Hat Inc.You probably want to change at least the date, and possibly the copyright attribution too. Distributing the code ownership helps to protect the freedom of the code, by making it difficult to make proprietary in future.> diff --git a/daemon/ntfs.c b/daemon/ntfs.c > index 1ead159..fd77716 100644 > --- a/daemon/ntfs.c > +++ b/daemon/ntfs.c > @@ -153,6 +153,74 @@ do_ntfsresize_size (const char *device, int64_t size) > return do_ntfsresize (device, size, 0); > } > > +int64_t > +ntfs_get_min_size (const char *device) > +{... You must call reply_with_error or reply_with_perror, exactly once, on every error path out of the do_* function. The reply_with_* functions are a part of the protocol -- they send data back to the library -- so if they are not called or called too often, then the library and daemon lose synch.> + lines = split_lines (out); > + if (lines == NULL) > + return -1;Here, you *don't* need to call reply_with_*, because split_lines does it already. But ...> + else if ((p = strstr (lines[i], cluster_size_pattern))) { > + if (sscanf (p + strlen(cluster_size_pattern), > + "%*[ ]:%" SCNd32, &cluster_size) != 1) > + return -1;... here and several other places in this function you must call reply_with_*. [...]> + reply_with_error("%s", "Bad cluster size");This should be: reply_with_error ("Bad cluster size");> + longdesc = "\ > +Get the minimum size of filesystem in bytes. This is the minimum possible size for filesystem shrinking.You can break these long lines. Empty line = paragraph break. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com virt-builder quickly builds VMs from scratch http://libguestfs.org/virt-builder.1.html
Richard W.M. Jones
2015-Oct-16 20:56 UTC
Re: [Libguestfs] [PATCH 2/2] Include resize2fs_P into get_min_size.
On Fri, Oct 16, 2015 at 07:44:21PM +0300, Maxim Perevedentsev wrote:> + for (i = 0; params[i] != NULL; i += 2) { > + if ((!strcmp (params[i], block_pattern))) { > + if (sscanf (params[i + 1], "%" SCNd32, &block_size) != 1) > + return -1;Needs reply_with_error () call. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com virt-builder quickly builds VMs from scratch http://libguestfs.org/virt-builder.1.html