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