btrfs-progs: Allow parse_qgroupid() to resolve subvolume path into qgroupid
authorQu Wenruo <quwenruo@cn.fujitsu.com>
Fri, 27 Feb 2015 08:26:36 +0000 (16:26 +0800)
committerDavid Sterba <dsterba@suse.cz>
Mon, 23 Mar 2015 23:27:50 +0000 (00:27 +0100)
Now parse_qgroupid() can resolve subvolume path into qgroupid.
This is quite handy for handling level 0 qgroupid, and user don't need
to resolve rootid by hand now.

Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com>
[constify string in __is_subvol]
Signed-off-by: David Sterba <dsterba@suse.cz>
utils.c

diff --git a/utils.c b/utils.c
index ca8efca..7b977ee 100644 (file)
--- a/utils.c
+++ b/utils.c
@@ -1708,6 +1708,25 @@ scan_again:
 }
 
 /*
+ * Unsafe subvolume check.
+ *
+ * This only checks ino == BTRFS_FIRST_FREE_OBJECTID, even it is not in a
+ * btrfs mount point.
+ * Must use together with other reliable method like btrfs ioctl.
+ */
+static int __is_subvol(const char *path)
+{
+       struct stat st;
+       int ret;
+
+       ret = lstat(path, &st);
+       if (ret < 0)
+               return ret;
+
+       return st.st_ino == BTRFS_FIRST_FREE_OBJECTID;
+}
+
+/*
  * A not-so-good version fls64. No fascinating optimization since
  * no one except parse_size use it
  */
@@ -1802,24 +1821,45 @@ u64 parse_qgroupid(const char *p)
        char *ptr_parse_end = NULL;
        u64 level;
        u64 id;
+       int fd;
+       int ret = 0;
+
+       if (p[0] == '/')
+               goto path;
 
+       /* Numeric format like '0/257' is the primary case */
        if (!s) {
                id = strtoull(p, &ptr_parse_end, 10);
                if (ptr_parse_end != ptr_src_end)
-                       goto err;
+                       goto path;
                return id;
        }
        level = strtoull(p, &ptr_parse_end, 10);
        if (ptr_parse_end != s)
-               goto err;
+               goto path;
 
        id = strtoull(s + 1, &ptr_parse_end, 10);
        if (ptr_parse_end != ptr_src_end)
-               goto  err;
+               goto  path;
 
        return (level << BTRFS_QGROUP_LEVEL_SHIFT) | id;
+
+path:
+       /* Path format like subv at 'my_subvol' is the fallback case */
+       ret = __is_subvol(p);
+       if (ret < 0 || !ret)
+               goto err;
+       fd = open(p, O_RDONLY);
+       if (fd < 0)
+               goto err;
+       ret = lookup_ino_rootid(fd, &id);
+       close(fd);
+       if (ret < 0)
+               goto err;
+       return id;
+
 err:
-       fprintf(stderr, "ERROR: invalid qgroupid %s\n", p);
+       fprintf(stderr, "ERROR: invalid qgroupid or subvolume path: %s\n", p);
        exit(-1);
 }