Hu Tao
2014-Dec-12 07:03 UTC
[Libguestfs] [PATCH v3 00/11] btrfs support part2: qgroup/quota commands
Hi,
This is v3 series to add support to btrfs qgroup related commands, inclduing
quota commands, and two leftover of subvolume commands.
Regards,
Hu
changes:
v3:
- don't intialize fs_buf (patch 1)
- check the return value of sysroot_path (patch 1)
- check fs_buf rather than fs (patch 1)
- fprintf (stderr,...) -> reply_with_error()
v2:
- add tests for new APIs
- combine btrfs_quota_enable and btrfs_quota_disable
- following APIs changed to operate on Mountable_or_Path:
btrfs_subvolume_get_default, btrfs_quota_enable, btrfs_quota_rescan.
Hu Tao (11):
daemon: btrfs: add helper functions mount and umount
New API: btrfs_subvolume_get_default
New API: btrfs_subvolume_show
New API: btrfs_quota_enable
New API: btrfs_quota_rescan
New API: btrfs_qgroup_limit
New API: btrfs_qgroup_create
New API: btrfs_qgroup_destroy
New API: btrfs_qgroup_show
New API: btrfs_qgroup_assign
New API: btrfs_qgroup_remove
daemon/btrfs.c | 666 ++++++++++++++++++++++++++++---
generator/actions.ml | 203 ++++++++++
generator/structs.ml | 10 +
gobject/Makefile.inc | 2 +
java/Makefile.inc | 1 +
java/com/redhat/et/libguestfs/.gitignore | 1 +
po/POTFILES | 1 +
src/MAX_PROC_NR | 2 +-
8 files changed, 837 insertions(+), 49 deletions(-)
--
1.9.3
Hu Tao
2014-Dec-12 07:03 UTC
[Libguestfs] [PATCH v3 01/11] daemon: btrfs: add helper functions mount and umount
Signed-off-by: Hu Tao <hutao@cn.fujitsu.com>
---
daemon/btrfs.c | 106 +++++++++++++++++++++++++++++++--------------------------
1 file changed, 58 insertions(+), 48 deletions(-)
diff --git a/daemon/btrfs.c b/daemon/btrfs.c
index 754fdcd..514ba37 100644
--- a/daemon/btrfs.c
+++ b/daemon/btrfs.c
@@ -326,6 +326,58 @@ do_btrfs_subvolume_create (const char *dest, const char
*qgroupid)
return 0;
}
+static char
+*mount (const mountable_t *fs)
+{
+ char *fs_buf;
+
+ if (fs->type == MOUNTABLE_PATH) {
+ fs_buf = sysroot_path (fs->device);
+ if (fs_buf == NULL)
+ reply_with_perror ("malloc");
+ } else {
+ fs_buf = strdup ("/tmp/btrfs.XXXXXX");
+ if (fs_buf == NULL) {
+ reply_with_perror ("strdup");
+ return NULL;
+ }
+
+ if (mkdtemp (fs_buf) == NULL) {
+ reply_with_perror ("mkdtemp");
+ free (fs_buf);
+ return NULL;
+ }
+
+ if (mount_vfs_nochroot ("", NULL, fs, fs_buf,
"<internal>") == -1) {
+ if (rmdir (fs_buf) == -1 && errno != ENOENT)
+ reply_with_error ("rmdir: %m\n");
+ free (fs_buf);
+ return NULL;
+ }
+ }
+
+ return fs_buf;
+}
+
+static int
+umount (char *fs_buf, const mountable_t *fs)
+{
+ if (fs->type != MOUNTABLE_PATH) {
+ CLEANUP_FREE char *err = NULL;
+ if (command (NULL, &err, str_umount, fs_buf, NULL) == -1) {
+ reply_with_error ("%s", err ? err : "malloc");
+ return -1;
+ }
+
+ if (rmdir (fs_buf) == -1 && errno != ENOENT) {
+ reply_with_error ("rmdir: %m\n");
+ return -1;
+ }
+ }
+ free (fs_buf);
+ return 0;
+}
+
guestfs_int_btrfssubvolume_list *
do_btrfs_subvolume_list (const mountable_t *fs)
{
@@ -336,42 +388,10 @@ do_btrfs_subvolume_list (const mountable_t *fs)
/* Execute 'btrfs subvolume list <fs>', and split the output
into lines */
{
- CLEANUP_FREE char *fs_buf = NULL;
-
- if (fs->type == MOUNTABLE_PATH) {
- fs_buf = sysroot_path (fs->device);
- if (fs_buf == NULL) {
- reply_with_perror ("malloc");
-
- cmderror:
- if (fs->type != MOUNTABLE_PATH && fs_buf) {
- CLEANUP_FREE char *err = NULL;
- if (command (NULL, &err, str_umount, fs_buf, NULL) == -1)
- fprintf (stderr, "%s\n", err);
-
- if (rmdir (fs_buf) == -1 && errno != ENOENT)
- fprintf (stderr, "rmdir: %m\n");
- }
- return NULL;
- }
- }
-
- else {
- fs_buf = strdup ("/tmp/btrfs.XXXXXX");
- if (fs_buf == NULL) {
- reply_with_perror ("strdup");
- goto cmderror;
- }
+ char *fs_buf = mount (fs);
- if (mkdtemp (fs_buf) == NULL) {
- reply_with_perror ("mkdtemp");
- goto cmderror;
- }
-
- if (mount_vfs_nochroot ("", NULL, fs, fs_buf,
"<internal>") == -1) {
- goto cmderror;
- }
- }
+ if (!fs_buf)
+ return NULL;
ADD_ARG (argv, i, str_btrfs);
ADD_ARG (argv, i, "subvolume");
@@ -382,18 +402,8 @@ do_btrfs_subvolume_list (const mountable_t *fs)
CLEANUP_FREE char *out = NULL, *errout = NULL;
int r = commandv (&out, &errout, argv);
- if (fs->type != MOUNTABLE_PATH) {
- CLEANUP_FREE char *err = NULL;
- if (command (NULL, &err, str_umount, fs_buf, NULL) == -1) {
- reply_with_error ("%s", err ? err : "malloc");
- goto cmderror;
- }
-
- if (rmdir (fs_buf) == -1 && errno != ENOENT) {
- reply_with_error ("rmdir: %m\n");
- goto cmderror;
- }
- }
+ if (umount (fs_buf, fs) != 0)
+ return NULL;
if (r == -1) {
CLEANUP_FREE char *fs_desc = mountable_to_string (fs);
@@ -401,7 +411,7 @@ do_btrfs_subvolume_list (const mountable_t *fs)
fprintf (stderr, "malloc: %m");
}
reply_with_error ("%s: %s", fs_desc ? fs_desc :
"malloc", errout);
- goto cmderror;
+ return NULL;
}
lines = split_lines (out);
--
1.9.3
Hu Tao
2014-Dec-12 07:03 UTC
[Libguestfs] [PATCH v3 02/11] New API: btrfs_subvolume_get_default
btrfs_subvolume_get_default is for getting the default subvolume of
a btrfs filesystem.
Signed-off-by: Hu Tao <hutao@cn.fujitsu.com>
---
daemon/btrfs.c | 39 +++++++++++++++++++++++++++++++++++++++
generator/actions.ml | 18 ++++++++++++++++++
src/MAX_PROC_NR | 2 +-
3 files changed, 58 insertions(+), 1 deletion(-)
diff --git a/daemon/btrfs.c b/daemon/btrfs.c
index 514ba37..bcd7a50 100644
--- a/daemon/btrfs.c
+++ b/daemon/btrfs.c
@@ -555,6 +555,45 @@ do_btrfs_subvolume_set_default (int64_t id, const char *fs)
return 0;
}
+int64_t
+do_btrfs_subvolume_get_default (const mountable_t *fs)
+{
+ const size_t MAX_ARGS = 64;
+ const char *argv[MAX_ARGS];
+ size_t i = 0;
+ char *fs_buf = NULL;
+ CLEANUP_FREE char *err = NULL;
+ CLEANUP_FREE char *out = NULL;
+ int r;
+ int64_t ret = -1;
+
+ fs_buf = mount (fs);
+ if (fs_buf == NULL)
+ goto error;
+
+ ADD_ARG (argv, i, str_btrfs);
+ ADD_ARG (argv, i, "subvolume");
+ ADD_ARG (argv, i, "get-default");
+ ADD_ARG (argv, i, fs_buf);
+ ADD_ARG (argv, i, NULL);
+
+ r = commandv (&out, &err, argv);
+ if (r == -1) {
+ reply_with_error ("%s: %s", fs_buf, err);
+ goto error;
+ }
+ if (sscanf (out, "ID %" SCNi64, &ret) != 1) {
+ reply_with_error ("%s: could not parse subvolume id: %s.",
argv[0], out);
+ ret = -1;
+ goto error;
+ }
+
+error:
+ if (fs_buf && umount (fs_buf, fs) != 0)
+ return -1;
+ return ret;
+}
+
int
do_btrfs_filesystem_sync (const char *fs)
{
diff --git a/generator/actions.ml b/generator/actions.ml
index 4bd0788..df1be22 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -12029,6 +12029,24 @@ Set readahead (in 512-byte sectors) for the device.
This uses the L<blockdev(8)> command." };
+ { defaults with
+ name = "btrfs_subvolume_get_default";
+ style = RInt64 "id", [Mountable_or_Path "fs"], [];
+ proc_nr = Some 425;
+ optional = Some "btrfs"; camel_name =
"BTRFSSubvolumeGetDefault";
+ tests = [
+ InitPartition, Always, TestResult (
+ [["mkfs_btrfs"; "/dev/sda1"; "";
""; "NOARG"; ""; "NOARG";
"NOARG"; ""; ""];
+ ["btrfs_subvolume_get_default"; "/dev/sda1"]],
"ret > 0"), [];
+ InitPartition, Always, TestResult (
+ [["mkfs_btrfs"; "/dev/sda1"; "";
""; "NOARG"; ""; "NOARG";
"NOARG"; ""; ""];
+ ["mount"; "/dev/sda1"; "/"];
+ ["btrfs_subvolume_get_default"; "/"]], "ret
> 0"), []
+ ];
+ shortdesc = "get the default subvolume or snapshot of a
filesystem";
+ longdesc = "\
+Get the default subvolume or snapshot of a filesystem mounted at
C<mountpoint>." };
+
]
(* Non-API meta-commands available only in guestfish.
diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR
index 9524ef4..5e4a522 100644
--- a/src/MAX_PROC_NR
+++ b/src/MAX_PROC_NR
@@ -1 +1 @@
-424
+425
--
1.9.3
btrfs_subvolume_show shows the detailed information of a subvolume or
snapshot.
Signed-off-by: Hu Tao <hutao@cn.fujitsu.com>
---
daemon/btrfs.c | 194 +++++++++++++++++++++++++++++++++++++++++++++++++++
generator/actions.ml | 25 +++++++
src/MAX_PROC_NR | 2 +-
3 files changed, 220 insertions(+), 1 deletion(-)
diff --git a/daemon/btrfs.c b/daemon/btrfs.c
index bcd7a50..18722c8 100644
--- a/daemon/btrfs.c
+++ b/daemon/btrfs.c
@@ -24,11 +24,13 @@
#include <pcre.h>
#include <string.h>
#include <unistd.h>
+#include <assert.h>
#include "daemon.h"
#include "actions.h"
#include "optgroups.h"
#include "xstrtol.h"
+#include "c-ctype.h"
GUESTFSD_EXT_CMD(str_btrfs, btrfs);
GUESTFSD_EXT_CMD(str_btrfstune, btrfstune);
@@ -821,3 +823,195 @@ do_btrfs_fsck (const char *device, int64_t superblock, int
repair)
return 0;
}
+
+/* analyze_line: analyze one line contains key:value pair.
+ * returns the next position following \n.
+ */
+static char *
+analyze_line (char *line, char **key, char **value)
+{
+ char *p = line;
+ char *next = NULL;
+ char delimiter = ':';
+ char *del_pos = NULL;
+
+ if (!line || *line == '\0') {
+ *key = NULL;
+ *value = NULL;
+ return NULL;
+ }
+
+ next = strchr (p, '\n');
+ if (next) {
+ *next = '\0';
+ ++next;
+ }
+
+ /* leading spaces and tabs */
+ while (*p && c_isspace (*p))
+ ++p;
+
+ assert (key);
+ if (*p == delimiter)
+ *key = NULL;
+ else
+ *key = p;
+
+ del_pos = strchr (p, delimiter);
+ if (del_pos) {
+ *del_pos = '\0';
+
+ /* leading spaces and tabs */
+ do {
+ ++del_pos;
+ } while (*del_pos && c_isspace (*del_pos));
+ assert (value);
+ *value = del_pos;
+ } else
+ *value = NULL;
+
+ return next;
+}
+
+char **
+do_btrfs_subvolume_show (const char *subvolume)
+{
+ const size_t MAX_ARGS = 64;
+ const char *argv[MAX_ARGS];
+ size_t i = 0;
+ CLEANUP_FREE char *subvolume_buf = NULL;
+ CLEANUP_FREE char *err = NULL;
+ CLEANUP_FREE char *out = NULL;
+ char *p, *key = NULL, *value = NULL;
+ DECLARE_STRINGSBUF (ret);
+ int r;
+
+ subvolume_buf = sysroot_path (subvolume);
+ if (subvolume_buf == NULL) {
+ reply_with_perror ("malloc");
+ return NULL;
+ }
+
+ ADD_ARG (argv, i, str_btrfs);
+ ADD_ARG (argv, i, "subvolume");
+ ADD_ARG (argv, i, "show");
+ ADD_ARG (argv, i, subvolume_buf);
+ ADD_ARG (argv, i, NULL);
+
+ r = commandv (&out, &err, argv);
+ if (r == -1) {
+ reply_with_error ("%s: %s", subvolume, err);
+ return NULL;
+ }
+
+ /* If the path is the btrfs root, `btrfs subvolume show' reports:
+ * <path> is btrfs root
+ */
+ if (out && strstr (out, "is btrfs root") != NULL) {
+ reply_with_error ("%s is btrfs root", subvolume);
+ return NULL;
+ }
+
+ /* If the path is a normal directory, `btrfs subvolume show' reports:
+ * ERROR: <path> is not a subvolume
+ */
+ if (err && strstr (err, "is not a subvolume")) {
+ reply_with_error ("%s is not a subvolume", subvolume);
+ return NULL;
+ }
+
+ /* Output is:
+ *
+ * /
+ * Name: root
+ * uuid: c875169e-cf4e-a04d-9959-b667dec36234
+ * Parent uuid: -
+ * Creation time: 2014-11-13 10:13:08
+ * Object ID: 256
+ * Generation (Gen): 6579
+ * Gen at creation: 5
+ * Parent: 5
+ * Top Level: 5
+ * Flags: -
+ * Snapshot(s):
+ * snapshots/test1
+ * snapshots/test2
+ * snapshots/test3
+ *
+ */
+ p = analyze_line(out, &key, &value);
+ if (!p) {
+ reply_with_error ("truncated output: %s", out);
+ return NULL;
+ }
+
+ /* The first line is the path of the subvolume. */
+ if (key && !value) {
+ if (add_string (&ret, "path") == -1)
+ return NULL;
+ if (add_string (&ret, key) == -1)
+ return NULL;
+ } else {
+ if (add_string (&ret, key) == -1)
+ return NULL;
+ if (add_string (&ret, value) == -1)
+ return NULL;
+ }
+
+ /* Read the lines and split into "key: value". */
+ p = analyze_line(p, &key, &value);
+ while (key) {
+ /* snapshot is special, see the output above */
+ if (STREQLEN (key, "Snapshot(s)", sizeof
("Snapshot(s)") - 1)) {
+ char *ss = NULL;
+ int ss_len = 0;
+
+ if (add_string (&ret, key) == -1)
+ return NULL;
+
+ p = analyze_line(p, &key, &value);
+
+ while (key && !value) {
+ ss = realloc (ss, ss_len + strlen (key) + 1);
+ if (!ss)
+ return NULL;
+
+ if (ss_len != 0)
+ ss[ss_len++] = ',';
+
+ memcpy (ss + ss_len, key, strlen (key));
+ ss_len += strlen (key);
+ ss[ss_len] = '\0';
+
+ p = analyze_line(p, &key, &value);
+ }
+
+ if (ss) {
+ if (add_string_nodup (&ret, ss) == -1) {
+ free (ss);
+ return NULL;
+ }
+ } else {
+ if (add_string (&ret, "") == -1)
+ return NULL;
+ }
+ } else {
+ if (add_string (&ret, key ? key : "") == -1)
+ return NULL;
+ if (value && !STREQ(value, "-")) {
+ if (add_string (&ret, value) == -1)
+ return NULL;
+ } else {
+ if (add_string (&ret, "") == -1)
+ return NULL;
+ }
+
+ p = analyze_line(p, &key, &value);
+ }
+ }
+
+ if (end_stringsbuf (&ret) == -1)
+ return NULL;
+
+ return ret.argv;
+}
diff --git a/generator/actions.ml b/generator/actions.ml
index df1be22..cfd7472 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -12047,6 +12047,31 @@ This uses the L<blockdev(8)> command." };
longdesc = "\
Get the default subvolume or snapshot of a filesystem mounted at
C<mountpoint>." };
+ { defaults with
+ name = "btrfs_subvolume_show";
+ style = RHashtable "btrfssubvolumeinfo", [Pathname
"subvolume"], [];
+ proc_nr = Some 426;
+ optional = Some "btrfs"; camel_name =
"BTRFSSubvolumeShow";
+ tests = [
+ InitPartition, Always, TestLastFail (
+ [["mkfs_btrfs"; "/dev/sda1"; "";
""; "NOARG"; ""; "NOARG";
"NOARG"; ""; ""];
+ ["mount"; "/dev/sda1"; "/"];
+ ["btrfs_subvolume_show"; "/"]]), [];
+ InitPartition, Always, TestRun (
+ [["mkfs_btrfs"; "/dev/sda1"; "";
""; "NOARG"; ""; "NOARG";
"NOARG"; ""; ""];
+ ["mount"; "/dev/sda1"; "/"];
+ ["btrfs_subvolume_create"; "/sub1";
"NOARG"];
+ ["btrfs_subvolume_show"; "/sub1"]]), [];
+ InitPartition, Always, TestLastFail (
+ [["mkfs_btrfs"; "/dev/sda1"; "";
""; "NOARG"; ""; "NOARG";
"NOARG"; ""; ""];
+ ["mount"; "/dev/sda1"; "/"];
+ ["mkdir"; "/dir1"];
+ ["btrfs_subvolume_show"; "/dir1"]]), [];
+ ];
+ shortdesc = "return detailed information of the subvolume";
+ longdesc = "\
+Return detailed information of the subvolume." };
+
]
(* Non-API meta-commands available only in guestfish.
diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR
index 5e4a522..9f51d08 100644
--- a/src/MAX_PROC_NR
+++ b/src/MAX_PROC_NR
@@ -1 +1 @@
-425
+426
--
1.9.3
btrfs_quota_enable enables or disables quota for btrfs filesystems.
Signed-off-by: Hu Tao <hutao@cn.fujitsu.com>
---
daemon/btrfs.c | 36 ++++++++++++++++++++++++++++++++++++
generator/actions.ml | 25 +++++++++++++++++++++++++
src/MAX_PROC_NR | 2 +-
3 files changed, 62 insertions(+), 1 deletion(-)
diff --git a/daemon/btrfs.c b/daemon/btrfs.c
index 18722c8..ee07e7e 100644
--- a/daemon/btrfs.c
+++ b/daemon/btrfs.c
@@ -1015,3 +1015,39 @@ do_btrfs_subvolume_show (const char *subvolume)
return ret.argv;
}
+
+int
+do_btrfs_quota_enable (const mountable_t *fs, int enable)
+{
+ const size_t MAX_ARGS = 64;
+ const char *argv[MAX_ARGS];
+ size_t i = 0;
+ char *fs_buf = NULL;
+ CLEANUP_FREE char *err = NULL;
+ CLEANUP_FREE char *out = NULL;
+ int r = -1;
+
+ fs_buf = mount (fs);
+ if (fs_buf == NULL)
+ goto error;
+
+ ADD_ARG (argv, i, str_btrfs);
+ ADD_ARG (argv, i, "quota");
+ if (enable)
+ ADD_ARG (argv, i, "enable");
+ else
+ ADD_ARG (argv, i, "disable");
+ ADD_ARG (argv, i, fs_buf);
+ ADD_ARG (argv, i, NULL);
+
+ r = commandv (&out, &err, argv);
+ if (r == -1) {
+ reply_with_error ("%s: %s", fs_buf, err);
+ goto error;
+ }
+
+error:
+ if (fs_buf && umount (fs_buf, fs) != 0)
+ return -1;
+ return r;
+}
diff --git a/generator/actions.ml b/generator/actions.ml
index cfd7472..d669b59 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -12072,6 +12072,31 @@ Get the default subvolume or snapshot of a filesystem
mounted at C<mountpoint>."
longdesc = "\
Return detailed information of the subvolume." };
+ { defaults with
+ name = "btrfs_quota_enable";
+ style = RErr, [Mountable_or_Path "fs"; Bool "enable"],
[];
+ proc_nr = Some 427;
+ optional = Some "btrfs"; camel_name =
"BTRFSQuotaEnable";
+ tests = [
+ InitPartition, Always, TestRun (
+ [["mkfs_btrfs"; "/dev/sda1"; "";
""; "NOARG"; ""; "NOARG";
"NOARG"; ""; ""];
+ ["btrfs_quota_enable"; "/dev/sda1";
"true"]]), [];
+ InitPartition, Always, TestRun (
+ [["mkfs_btrfs"; "/dev/sda1"; "";
""; "NOARG"; ""; "NOARG";
"NOARG"; ""; ""];
+ ["mount"; "/dev/sda1"; "/"];
+ ["btrfs_quota_enable"; "/"; "true"]]),
[];
+ InitPartition, Always, TestRun (
+ [["mkfs_btrfs"; "/dev/sda1"; "";
""; "NOARG"; ""; "NOARG";
"NOARG"; ""; ""];
+ ["btrfs_quota_enable"; "/dev/sda1";
"false"]]), [];
+ InitPartition, Always, TestRun (
+ [["mkfs_btrfs"; "/dev/sda1"; "";
""; "NOARG"; ""; "NOARG";
"NOARG"; ""; ""];
+ ["mount"; "/dev/sda1"; "/"];
+ ["btrfs_quota_enable"; "/"; "false"]]),
[];
+ ];
+ shortdesc = "enable or disable subvolume quota support";
+ longdesc = "\
+Enable or disable subvolume quota support for filesystem which contains
C<path>." };
+
]
(* Non-API meta-commands available only in guestfish.
diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR
index 9f51d08..d2a1e59 100644
--- a/src/MAX_PROC_NR
+++ b/src/MAX_PROC_NR
@@ -1 +1 @@
-426
+427
--
1.9.3
btrfs_quota_rescan trashs all qgroup numbers and scans the metadata
again with the current config.
Signed-off-by: Hu Tao <hutao@cn.fujitsu.com>
---
daemon/btrfs.c | 33 +++++++++++++++++++++++++++++++++
generator/actions.ml | 21 +++++++++++++++++++++
src/MAX_PROC_NR | 2 +-
3 files changed, 55 insertions(+), 1 deletion(-)
diff --git a/daemon/btrfs.c b/daemon/btrfs.c
index ee07e7e..71229f1 100644
--- a/daemon/btrfs.c
+++ b/daemon/btrfs.c
@@ -1051,3 +1051,36 @@ error:
return -1;
return r;
}
+
+int
+do_btrfs_quota_rescan (const mountable_t *fs)
+{
+ const size_t MAX_ARGS = 64;
+ const char *argv[MAX_ARGS];
+ size_t i = 0;
+ char *fs_buf = NULL;
+ CLEANUP_FREE char *err = NULL;
+ CLEANUP_FREE char *out = NULL;
+ int r = -1;
+
+ fs_buf = mount (fs);
+ if (fs_buf == NULL)
+ goto error;
+
+ ADD_ARG (argv, i, str_btrfs);
+ ADD_ARG (argv, i, "quota");
+ ADD_ARG (argv, i, "rescan");
+ ADD_ARG (argv, i, fs_buf);
+ ADD_ARG (argv, i, NULL);
+
+ r = commandv (&out, &err, argv);
+ if (r == -1) {
+ reply_with_error ("%s: %s", fs_buf, err);
+ goto error;
+ }
+
+error:
+ if (fs_buf && umount (fs_buf, fs) != 0)
+ return -1;
+ return r;
+}
diff --git a/generator/actions.ml b/generator/actions.ml
index d669b59..3e5aab0 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -12097,6 +12097,27 @@ Return detailed information of the subvolume." };
longdesc = "\
Enable or disable subvolume quota support for filesystem which contains
C<path>." };
+ { defaults with
+ name = "btrfs_quota_rescan";
+ style = RErr, [Mountable_or_Path "fs"], [];
+ proc_nr = Some 428;
+ optional = Some "btrfs"; camel_name =
"BTRFSQuotaRescan";
+ tests = [
+ InitPartition, Always, TestRun (
+ [["mkfs_btrfs"; "/dev/sda1"; "";
""; "NOARG"; ""; "NOARG";
"NOARG"; ""; ""];
+ ["btrfs_quota_enable"; "/dev/sda1";
"true"];
+ ["btrfs_quota_rescan"; "/dev/sda1"]]), [];
+ InitPartition, Always, TestRun (
+ [["mkfs_btrfs"; "/dev/sda1"; "";
""; "NOARG"; ""; "NOARG";
"NOARG"; ""; ""];
+ ["mount"; "/dev/sda1"; "/"];
+ ["btrfs_quota_enable"; "/"; "true"];
+ ["btrfs_quota_rescan"; "/"]]), [];
+ ];
+
+ shortdesc = "trash all qgroup numbers and scan the metadata again with
the current config";
+ longdesc = "\
+Trash all qgroup numbers and scan the metadata again with the current
config." };
+
]
(* Non-API meta-commands available only in guestfish.
diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR
index d2a1e59..43d371a 100644
--- a/src/MAX_PROC_NR
+++ b/src/MAX_PROC_NR
@@ -1 +1 @@
-427
+428
--
1.9.3
btrfs_qgroup_limit limits the size of a qgroup.
Signed-off-by: Hu Tao <hutao@cn.fujitsu.com>
---
daemon/btrfs.c | 35 +++++++++++++++++++++++++++++++++++
generator/actions.ml | 22 ++++++++++++++++++++++
src/MAX_PROC_NR | 2 +-
3 files changed, 58 insertions(+), 1 deletion(-)
diff --git a/daemon/btrfs.c b/daemon/btrfs.c
index 71229f1..01fd0cf 100644
--- a/daemon/btrfs.c
+++ b/daemon/btrfs.c
@@ -1084,3 +1084,38 @@ error:
return -1;
return r;
}
+
+int
+do_btrfs_qgroup_limit (const char *subvolume, int64_t size)
+{
+ const size_t MAX_ARGS = 64;
+ const char *argv[MAX_ARGS];
+ size_t i = 0;
+ CLEANUP_FREE char *subvolume_buf = NULL;
+ CLEANUP_FREE char *err = NULL;
+ CLEANUP_FREE char *out = NULL;
+ char size_str[32];
+ int r;
+
+ subvolume_buf = sysroot_path (subvolume);
+ if (subvolume_buf == NULL) {
+ reply_with_perror ("malloc");
+ return -1;
+ }
+
+ ADD_ARG (argv, i, str_btrfs);
+ ADD_ARG (argv, i, "qgroup");
+ ADD_ARG (argv, i, "limit");
+ snprintf (size_str, sizeof size_str, "%" PRIi64, size);
+ ADD_ARG (argv, i, size_str);
+ ADD_ARG (argv, i, subvolume_buf);
+ ADD_ARG (argv, i, NULL);
+
+ r = commandv (&out, &err, argv);
+ if (r == -1) {
+ reply_with_error ("%s: %s", subvolume, err);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/generator/actions.ml b/generator/actions.ml
index 3e5aab0..6352851 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -12118,6 +12118,28 @@ Enable or disable subvolume quota support for
filesystem which contains C<path>.
longdesc = "\
Trash all qgroup numbers and scan the metadata again with the current
config." };
+ { defaults with
+ name = "btrfs_qgroup_limit";
+ style = RErr, [Pathname "subvolume"; Int64 "size"], [];
+ proc_nr = Some 429;
+ optional = Some "btrfs"; camel_name =
"BTRFSQgroupLimit";
+ tests = [
+ InitPartition, Always, TestRun (
+ [["mkfs_btrfs"; "/dev/sda1"; "";
""; "NOARG"; ""; "NOARG";
"NOARG"; ""; ""];
+ ["mount"; "/dev/sda1"; "/"];
+ ["btrfs_quota_enable"; "/"; "true"];
+ ["btrfs_qgroup_limit"; "/";
"10737418240"]]), [];
+ InitPartition, Always, TestLastFail (
+ [["mkfs_btrfs"; "/dev/sda1"; "";
""; "NOARG"; ""; "NOARG";
"NOARG"; ""; ""];
+ ["mount"; "/dev/sda1"; "/"];
+ ["btrfs_quota_enable"; "/"; "false"];
+ ["btrfs_qgroup_limit"; "/";
"10737418240"]]), [];
+ ];
+ shortdesc = "limit the size of a subvolume";
+ longdesc = "\
+Limit the size of a subvolume which's path is C<subvolume>.
C<size>
+can have suffix of G, M, or K. " };
+
]
(* Non-API meta-commands available only in guestfish.
diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR
index 43d371a..3560666 100644
--- a/src/MAX_PROC_NR
+++ b/src/MAX_PROC_NR
@@ -1 +1 @@
-428
+429
--
1.9.3
btrfs_qgroup_create creates a new qgroup.
Signed-off-by: Hu Tao <hutao@cn.fujitsu.com>
---
daemon/btrfs.c | 33 +++++++++++++++++++++++++++++++++
generator/actions.ml | 17 +++++++++++++++++
src/MAX_PROC_NR | 2 +-
3 files changed, 51 insertions(+), 1 deletion(-)
diff --git a/daemon/btrfs.c b/daemon/btrfs.c
index 01fd0cf..89a7ddc 100644
--- a/daemon/btrfs.c
+++ b/daemon/btrfs.c
@@ -1119,3 +1119,36 @@ do_btrfs_qgroup_limit (const char *subvolume, int64_t
size)
return 0;
}
+
+int
+do_btrfs_qgroup_create (const char *qgroupid, const char *subvolume)
+{
+ const size_t MAX_ARGS = 64;
+ const char *argv[MAX_ARGS];
+ size_t i = 0;
+ CLEANUP_FREE char *subvolume_buf = NULL;
+ CLEANUP_FREE char *err = NULL;
+ CLEANUP_FREE char *out = NULL;
+ int r;
+
+ subvolume_buf = sysroot_path (subvolume);
+ if (subvolume_buf == NULL) {
+ reply_with_perror ("malloc");
+ return -1;
+ }
+
+ ADD_ARG (argv, i, str_btrfs);
+ ADD_ARG (argv, i, "qgroup");
+ ADD_ARG (argv, i, "create");
+ ADD_ARG (argv, i, qgroupid);
+ ADD_ARG (argv, i, subvolume_buf);
+ ADD_ARG (argv, i, NULL);
+
+ r = commandv (&out, &err, argv);
+ if (r == -1) {
+ reply_with_error ("%s: %s", subvolume, err);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/generator/actions.ml b/generator/actions.ml
index 6352851..a44d939 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -12140,6 +12140,23 @@ Trash all qgroup numbers and scan the metadata again
with the current config." }
Limit the size of a subvolume which's path is C<subvolume>.
C<size>
can have suffix of G, M, or K. " };
+ { defaults with
+ name = "btrfs_qgroup_create";
+ style = RErr, [String "qgroupid"; Pathname
"subvolume"], [];
+ proc_nr = Some 430;
+ optional = Some "btrfs"; camel_name =
"BTRFSQgroupCreate";
+ tests = [
+ InitPartition, Always, TestRun (
+ [["mkfs_btrfs"; "/dev/sda1"; "";
""; "NOARG"; ""; "NOARG";
"NOARG"; ""; ""];
+ ["mount"; "/dev/sda1"; "/"];
+ ["btrfs_quota_enable"; "/"; "true"];
+ ["btrfs_subvolume_create"; "/sub1";
"NOARG"];
+ ["btrfs_qgroup_create"; "0/1000";
"/sub1"]]), [];
+ ];
+ shortdesc = "create a subvolume quota group";
+ longdesc = "\
+Create a quota group (qgroup) for subvolume at C<subvolume>." };
+
]
(* Non-API meta-commands available only in guestfish.
diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR
index 3560666..c15fb93 100644
--- a/src/MAX_PROC_NR
+++ b/src/MAX_PROC_NR
@@ -1 +1 @@
-429
+430
--
1.9.3
btrfs_qgroup_destroy destroys a qgroup.
Signed-off-by: Hu Tao <hutao@cn.fujitsu.com>
---
daemon/btrfs.c | 33 +++++++++++++++++++++++++++++++++
generator/actions.ml | 18 ++++++++++++++++++
src/MAX_PROC_NR | 2 +-
3 files changed, 52 insertions(+), 1 deletion(-)
diff --git a/daemon/btrfs.c b/daemon/btrfs.c
index 89a7ddc..c38a4b5 100644
--- a/daemon/btrfs.c
+++ b/daemon/btrfs.c
@@ -1152,3 +1152,36 @@ do_btrfs_qgroup_create (const char *qgroupid, const char
*subvolume)
return 0;
}
+
+int
+do_btrfs_qgroup_destroy (const char *qgroupid, const char *subvolume)
+{
+ const size_t MAX_ARGS = 64;
+ const char *argv[MAX_ARGS];
+ size_t i = 0;
+ CLEANUP_FREE char *subvolume_buf = NULL;
+ CLEANUP_FREE char *err = NULL;
+ CLEANUP_FREE char *out = NULL;
+ int r;
+
+ subvolume_buf = sysroot_path (subvolume);
+ if (subvolume_buf == NULL) {
+ reply_with_perror ("malloc");
+ return -1;
+ }
+
+ ADD_ARG (argv, i, str_btrfs);
+ ADD_ARG (argv, i, "qgroup");
+ ADD_ARG (argv, i, "destroy");
+ ADD_ARG (argv, i, qgroupid);
+ ADD_ARG (argv, i, subvolume_buf);
+ ADD_ARG (argv, i, NULL);
+
+ r = commandv (&out, &err, argv);
+ if (r == -1) {
+ reply_with_error ("%s: %s", subvolume, err);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/generator/actions.ml b/generator/actions.ml
index a44d939..c3294b3 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -12157,6 +12157,24 @@ can have suffix of G, M, or K. " };
longdesc = "\
Create a quota group (qgroup) for subvolume at C<subvolume>." };
+ { defaults with
+ name = "btrfs_qgroup_destroy";
+ style = RErr, [String "qgroupid"; Pathname
"subvolume"], [];
+ proc_nr = Some 431;
+ optional = Some "btrfs"; camel_name =
"BTRFSQgroupDestroy";
+ tests = [
+ InitPartition, Always, TestRun (
+ [["mkfs_btrfs"; "/dev/sda1"; "";
""; "NOARG"; ""; "NOARG";
"NOARG"; ""; ""];
+ ["mount"; "/dev/sda1"; "/"];
+ ["btrfs_quota_enable"; "/"; "true"];
+ ["btrfs_subvolume_create"; "/sub1";
"NOARG"];
+ ["btrfs_qgroup_create"; "0/1000";
"/sub1"];
+ ["btrfs_qgroup_destroy"; "0/1000";
"/sub1"]]), [];
+ ];
+ shortdesc = "destroy a subvolume quota group";
+ longdesc = "\
+Destroy a quota group." };
+
]
(* Non-API meta-commands available only in guestfish.
diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR
index c15fb93..ed4f162 100644
--- a/src/MAX_PROC_NR
+++ b/src/MAX_PROC_NR
@@ -1 +1 @@
-430
+431
--
1.9.3
btrfs_qgroup_show shows all qgroups on a btrfs filesystem.
Signed-off-by: Hu Tao <hutao@cn.fujitsu.com>
---
daemon/btrfs.c | 89 ++++++++++++++++++++++++++++++++
generator/actions.ml | 19 +++++++
generator/structs.ml | 10 ++++
gobject/Makefile.inc | 2 +
java/Makefile.inc | 1 +
java/com/redhat/et/libguestfs/.gitignore | 1 +
po/POTFILES | 1 +
src/MAX_PROC_NR | 2 +-
8 files changed, 124 insertions(+), 1 deletion(-)
diff --git a/daemon/btrfs.c b/daemon/btrfs.c
index c38a4b5..cde84fe 100644
--- a/daemon/btrfs.c
+++ b/daemon/btrfs.c
@@ -1185,3 +1185,92 @@ do_btrfs_qgroup_destroy (const char *qgroupid, const char
*subvolume)
return 0;
}
+
+guestfs_int_btrfsqgroup_list *
+do_btrfs_qgroup_show (const char *path)
+{
+ const size_t MAX_ARGS = 64;
+ const char *argv[MAX_ARGS];
+ size_t i = 0;
+ CLEANUP_FREE char *path_buf = NULL;
+ CLEANUP_FREE char *err = NULL;
+ CLEANUP_FREE char *out = NULL;
+ int r;
+ char **lines;
+
+ path_buf = sysroot_path (path);
+ if (path_buf == NULL) {
+ reply_with_perror ("malloc");
+ return NULL;
+ }
+
+ ADD_ARG (argv, i, str_btrfs);
+ ADD_ARG (argv, i, "qgroup");
+ ADD_ARG (argv, i, "show");
+ ADD_ARG (argv, i, path_buf);
+ ADD_ARG (argv, i, NULL);
+
+ r = commandv (&out, &err, argv);
+ if (r == -1) {
+ reply_with_error ("%s: %s", path, err);
+ return NULL;
+ }
+
+ lines = split_lines (out);
+ if (!lines)
+ return NULL;
+
+ /* line 0 and 1 are:
+ *
+ * qgroupid rfer excl
+ * -------- ---- ----
+ */
+ size_t nr_qgroups = count_strings (lines) - 2;
+ guestfs_int_btrfsqgroup_list *ret = NULL;
+ ret = malloc (sizeof *ret);
+ if (!ret) {
+ reply_with_perror ("malloc");
+ goto error;
+ }
+
+ ret->guestfs_int_btrfsqgroup_list_len = nr_qgroups;
+ ret->guestfs_int_btrfsqgroup_list_val + calloc (nr_qgroups, sizeof
(struct guestfs_int_btrfsqgroup));
+ if (ret->guestfs_int_btrfsqgroup_list_val == NULL) {
+ reply_with_perror ("malloc");
+ goto error;
+ }
+
+ for (i = 0; i < nr_qgroups; ++i) {
+ char *line = lines[i + 2];
+ struct guestfs_int_btrfsqgroup *this +
&ret->guestfs_int_btrfsqgroup_list_val[i];
+ uint64_t dummy1, dummy2;
+ char *p;
+
+ if (sscanf (line, "%" SCNu64 "/%" SCNu64 " %"
SCNu64 " %" SCNu64,
+ &dummy1, &dummy2, &this->btrfsqgroup_rfer,
+ &this->btrfsqgroup_excl) != 4) {
+ reply_with_perror ("sscanf");
+ goto error;
+ }
+ p = strchr(line, ' ');
+ if (!p) {
+ reply_with_error ("truncated line: %s", line);
+ goto error;
+ }
+ *p = '\0';
+ this->btrfsqgroup_id = line;
+ }
+
+ free (lines);
+ return ret;
+
+error:
+ free_stringslen (lines, nr_qgroups + 2);
+ if (ret)
+ free (ret->guestfs_int_btrfsqgroup_list_val);
+ free (ret);
+
+ return NULL;
+}
diff --git a/generator/actions.ml b/generator/actions.ml
index c3294b3..8a03000 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -12175,6 +12175,25 @@ Create a quota group (qgroup) for subvolume at
C<subvolume>." };
longdesc = "\
Destroy a quota group." };
+ { defaults with
+ name = "btrfs_qgroup_show";
+ style = RStructList ("qgroups", "btrfsqgroup"),
[Pathname "path"], [];
+ proc_nr = Some 432;
+ tests = [
+ InitPartition, Always, TestRun (
+ [["mkfs_btrfs"; "/dev/sda1"; "";
""; "NOARG"; ""; "NOARG";
"NOARG"; ""; ""];
+ ["mount"; "/dev/sda1"; "/"];
+ ["btrfs_quota_enable"; "/"; "true"];
+ ["btrfs_subvolume_create"; "/sub1";
"NOARG"];
+ ["btrfs_qgroup_create"; "0/1000";
"/sub1"];
+ ["btrfs_qgroup_show"; "/"]]), [];
+ ];
+ optional = Some "btrfs"; camel_name =
"BTRFSQgroupShow";
+ shortdesc = "show subvolume quota groups";
+ longdesc = "\
+Show all subvolume quota groups in a btrfs filesystem, inclding their
+usages." };
+
]
(* Non-API meta-commands available only in guestfish.
diff --git a/generator/structs.ml b/generator/structs.ml
index 578ebb7..df3ff47 100644
--- a/generator/structs.ml
+++ b/generator/structs.ml
@@ -330,6 +330,16 @@ let structs = [
];
s_camel_name = "BTRFSSubvolume" };
+ (* btrfs qgroup show output *)
+ { defaults with
+ s_name = "btrfsqgroup";
+ s_cols = [
+ "btrfsqgroup_id", FString;
+ "btrfsqgroup_rfer", FUInt64;
+ "btrfsqgroup_excl", FUInt64;
+ ];
+ s_camel_name = "BTRFSQgroup" };
+
(* XFS info descriptor. *)
{ defaults with
s_name = "xfsinfo";
diff --git a/gobject/Makefile.inc b/gobject/Makefile.inc
index 218eef7..91c4ea6 100644
--- a/gobject/Makefile.inc
+++ b/gobject/Makefile.inc
@@ -25,6 +25,7 @@ guestfs_gobject_headers= \
include/guestfs-gobject/tristate.h \
include/guestfs-gobject/struct-application.h \
include/guestfs-gobject/struct-application2.h \
+ include/guestfs-gobject/struct-btrfsqgroup.h \
include/guestfs-gobject/struct-btrfssubvolume.h \
include/guestfs-gobject/struct-dirent.h \
include/guestfs-gobject/struct-hivex_node.h \
@@ -106,6 +107,7 @@ guestfs_gobject_sources= \
src/tristate.c \
src/struct-application.c \
src/struct-application2.c \
+ src/struct-btrfsqgroup.c \
src/struct-btrfssubvolume.c \
src/struct-dirent.c \
src/struct-hivex_node.c \
diff --git a/java/Makefile.inc b/java/Makefile.inc
index 614caaa..34938fb 100644
--- a/java/Makefile.inc
+++ b/java/Makefile.inc
@@ -22,6 +22,7 @@
java_built_sources = \
com/redhat/et/libguestfs/Application.java \
com/redhat/et/libguestfs/Application2.java \
+ com/redhat/et/libguestfs/BTRFSQgroup.java \
com/redhat/et/libguestfs/BTRFSSubvolume.java \
com/redhat/et/libguestfs/Dirent.java \
com/redhat/et/libguestfs/HivexNode.java \
diff --git a/java/com/redhat/et/libguestfs/.gitignore
b/java/com/redhat/et/libguestfs/.gitignore
index 4882c96..1d4accc 100644
--- a/java/com/redhat/et/libguestfs/.gitignore
+++ b/java/com/redhat/et/libguestfs/.gitignore
@@ -1,5 +1,6 @@
Application.java
Application2.java
+BTRFSQgroup.java
BTRFSSubvolume.java
Dirent.java
HivexNode.java
diff --git a/po/POTFILES b/po/POTFILES
index a8e211f..57a8153 100644
--- a/po/POTFILES
+++ b/po/POTFILES
@@ -229,6 +229,7 @@ gobject/src/optargs-xfs_repair.c
gobject/src/session.c
gobject/src/struct-application.c
gobject/src/struct-application2.c
+gobject/src/struct-btrfsqgroup.c
gobject/src/struct-btrfssubvolume.c
gobject/src/struct-dirent.c
gobject/src/struct-hivex_node.c
diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR
index ed4f162..84796bf 100644
--- a/src/MAX_PROC_NR
+++ b/src/MAX_PROC_NR
@@ -1 +1 @@
-431
+432
--
1.9.3
btrfs_qgroup_assign adds a qgroup to a parent qgroup.
Signed-off-by: Hu Tao <hutao@cn.fujitsu.com>
---
daemon/btrfs.c | 34 ++++++++++++++++++++++++++++++++++
generator/actions.ml | 19 +++++++++++++++++++
src/MAX_PROC_NR | 2 +-
3 files changed, 54 insertions(+), 1 deletion(-)
diff --git a/daemon/btrfs.c b/daemon/btrfs.c
index cde84fe..7bb1ca0 100644
--- a/daemon/btrfs.c
+++ b/daemon/btrfs.c
@@ -1274,3 +1274,37 @@ error:
return NULL;
}
+
+int
+do_btrfs_qgroup_assign (const char *src, const char *dst, const char *path)
+{
+ const size_t MAX_ARGS = 64;
+ const char *argv[MAX_ARGS];
+ size_t i = 0;
+ CLEANUP_FREE char *path_buf = NULL;
+ CLEANUP_FREE char *err = NULL;
+ CLEANUP_FREE char *out = NULL;
+ int r;
+
+ path_buf = sysroot_path (path);
+ if (path_buf == NULL) {
+ reply_with_perror ("malloc");
+ return -1;
+ }
+
+ ADD_ARG (argv, i, str_btrfs);
+ ADD_ARG (argv, i, "qgroup");
+ ADD_ARG (argv, i, "assign");
+ ADD_ARG (argv, i, src);
+ ADD_ARG (argv, i, dst);
+ ADD_ARG (argv, i, path_buf);
+ ADD_ARG (argv, i, NULL);
+
+ r = commandv (&out, &err, argv);
+ if (r == -1) {
+ reply_with_error ("%s: %s", path, err);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/generator/actions.ml b/generator/actions.ml
index 8a03000..67cd7ab 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -12194,6 +12194,25 @@ Destroy a quota group." };
Show all subvolume quota groups in a btrfs filesystem, inclding their
usages." };
+ { defaults with
+ name = "btrfs_qgroup_assign";
+ style = RErr, [String "src"; String "dst"; Pathname
"path"], [];
+ proc_nr = Some 433;
+ optional = Some "btrfs"; camel_name =
"BTRFSQgroupAssign";
+ tests = [
+ InitPartition, Always, TestRun (
+ [["mkfs_btrfs"; "/dev/sda1"; "";
""; "NOARG"; ""; "NOARG";
"NOARG"; ""; ""];
+ ["mount"; "/dev/sda1"; "/"];
+ ["btrfs_quota_enable"; "/"; "true"];
+ ["btrfs_qgroup_create"; "0/1000"; "/"];
+ ["btrfs_qgroup_create"; "1/1000"; "/"];
+ ["btrfs_qgroup_assign"; "0/1000";
"1/1000"; "/"]]), [];
+ ];
+ shortdesc = "add a qgroup to a parent qgroup";
+ longdesc = "\
+Add qgroup C<src> to parent qgroup C<dst>. This command can group
+several qgroups into a parent qgroup to share common limit." };
+
]
(* Non-API meta-commands available only in guestfish.
diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR
index 84796bf..21fbd2e 100644
--- a/src/MAX_PROC_NR
+++ b/src/MAX_PROC_NR
@@ -1 +1 @@
-432
+433
--
1.9.3
btrfs_qgroup_remove removes a qgroup from its parent qgroup.
Signed-off-by: Hu Tao <hutao@cn.fujitsu.com>
---
daemon/btrfs.c | 34 ++++++++++++++++++++++++++++++++++
generator/actions.ml | 19 +++++++++++++++++++
src/MAX_PROC_NR | 2 +-
3 files changed, 54 insertions(+), 1 deletion(-)
diff --git a/daemon/btrfs.c b/daemon/btrfs.c
index 7bb1ca0..2304a72 100644
--- a/daemon/btrfs.c
+++ b/daemon/btrfs.c
@@ -1308,3 +1308,37 @@ do_btrfs_qgroup_assign (const char *src, const char *dst,
const char *path)
return 0;
}
+
+int
+do_btrfs_qgroup_remove (const char *src, const char *dst, const char *path)
+{
+ const size_t MAX_ARGS = 64;
+ const char *argv[MAX_ARGS];
+ size_t i = 0;
+ CLEANUP_FREE char *path_buf = NULL;
+ CLEANUP_FREE char *err = NULL;
+ CLEANUP_FREE char *out = NULL;
+ int r;
+
+ path_buf = sysroot_path (path);
+ if (path_buf == NULL) {
+ reply_with_perror ("malloc");
+ return -1;
+ }
+
+ ADD_ARG (argv, i, str_btrfs);
+ ADD_ARG (argv, i, "qgroup");
+ ADD_ARG (argv, i, "remove");
+ ADD_ARG (argv, i, src);
+ ADD_ARG (argv, i, dst);
+ ADD_ARG (argv, i, path_buf);
+ ADD_ARG (argv, i, NULL);
+
+ r = commandv (&out, &err, argv);
+ if (r == -1) {
+ reply_with_error ("%s: %s", path, err);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/generator/actions.ml b/generator/actions.ml
index 67cd7ab..5be9441 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -12213,6 +12213,25 @@ usages." };
Add qgroup C<src> to parent qgroup C<dst>. This command can group
several qgroups into a parent qgroup to share common limit." };
+ { defaults with
+ name = "btrfs_qgroup_remove";
+ style = RErr, [String "src"; String "dst"; Pathname
"path"], [];
+ proc_nr = Some 434;
+ optional = Some "btrfs"; camel_name =
"BTRFSQgroupRemove";
+ tests = [
+ InitPartition, Always, TestRun (
+ [["mkfs_btrfs"; "/dev/sda1"; "";
""; "NOARG"; ""; "NOARG";
"NOARG"; ""; ""];
+ ["mount"; "/dev/sda1"; "/"];
+ ["btrfs_quota_enable"; "/"; "true"];
+ ["btrfs_qgroup_create"; "0/1000"; "/"];
+ ["btrfs_qgroup_create"; "1/1000"; "/"];
+ ["btrfs_qgroup_assign"; "0/1000";
"1/1000"; "/"];
+ ["btrfs_qgroup_remove"; "0/1000";
"1/1000"; "/"]]), [];
+ ];
+ shortdesc = "remove a qgroup from its parent qgroup";
+ longdesc = "\
+Remove qgroup C<src> from the parent qgroup C<dst>." };
+
]
(* Non-API meta-commands available only in guestfish.
diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR
index 21fbd2e..e828e5d 100644
--- a/src/MAX_PROC_NR
+++ b/src/MAX_PROC_NR
@@ -1 +1 @@
-433
+434
--
1.9.3
Richard W.M. Jones
2014-Dec-12 16:41 UTC
Re: [Libguestfs] [PATCH v3 00/11] btrfs support part2: qgroup/quota commands
On Fri, Dec 12, 2014 at 03:03:22PM +0800, Hu Tao wrote:> Hi, > > This is v3 series to add support to btrfs qgroup related commands, inclduing > quota commands, and two leftover of subvolume commands.I really need to look at this in detail next week, especially the mount/umount helper functions in patch 01. However I did run the test suite, and it did pass, so that's a good sign. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com virt-df lists disk usage of guests without needing to install any software inside the virtual machine. Supports Linux and Windows. http://people.redhat.com/~rjones/virt-df/
Hu Tao
2014-Dec-15 02:17 UTC
Re: [Libguestfs] [PATCH v3 00/11] btrfs support part2: qgroup/quota commands
On Fri, Dec 12, 2014 at 04:41:44PM +0000, Richard W.M. Jones wrote:> On Fri, Dec 12, 2014 at 03:03:22PM +0800, Hu Tao wrote: > > Hi, > > > > This is v3 series to add support to btrfs qgroup related commands, inclduing > > quota commands, and two leftover of subvolume commands. > > I really need to look at this in detail next week, especially the > mount/umount helper functions in patch 01.No problem!> > However I did run the test suite, and it did pass, so that's a good sign.Good. Thanks for testing! Regards, Hu> > Rich. > > -- > Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones > Read my programming and virtualization blog: http://rwmj.wordpress.com > virt-df lists disk usage of guests without needing to install any > software inside the virtual machine. Supports Linux and Windows. > http://people.redhat.com/~rjones/virt-df/
Richard W.M. Jones
2014-Dec-15 16:46 UTC
Re: [Libguestfs] [PATCH v3 01/11] daemon: btrfs: add helper functions mount and umount
On Fri, Dec 12, 2014 at 03:03:23PM +0800, Hu Tao wrote:> Signed-off-by: Hu Tao <hutao@cn.fujitsu.com> > --- > daemon/btrfs.c | 106 +++++++++++++++++++++++++++++++-------------------------- > 1 file changed, 58 insertions(+), 48 deletions(-) > > diff --git a/daemon/btrfs.c b/daemon/btrfs.c > index 754fdcd..514ba37 100644 > --- a/daemon/btrfs.c > +++ b/daemon/btrfs.c > + if (mount_vfs_nochroot ("", NULL, fs, fs_buf, "<internal>") == -1) { > + if (rmdir (fs_buf) == -1 && errno != ENOENT) > + reply_with_error ("rmdir: %m\n");This error path calls reply_with_error twice (the first time in mount_vfs_nochroot). That's a problem because it would cause protocol desychronization. [...]> + if (command (NULL, &err, str_umount, fs_buf, NULL) == -1) { > + reply_with_error ("%s", err ? err : "malloc"); > + return -1; > + }'err' is always non-NULL here. There's no need to send an updated patch, as I'm just going to change this to an fprintf statement before I push it (very soon). Thanks, Rich.> + if (rmdir (fs_buf) == -1 && errno != ENOENT) { > + reply_with_error ("rmdir: %m\n"); > + return -1; > + } > + } > + free (fs_buf); > + return 0; > +} > + > guestfs_int_btrfssubvolume_list * > do_btrfs_subvolume_list (const mountable_t *fs) > { > @@ -336,42 +388,10 @@ do_btrfs_subvolume_list (const mountable_t *fs) > > /* Execute 'btrfs subvolume list <fs>', and split the output into lines */ > { > - CLEANUP_FREE char *fs_buf = NULL; > - > - if (fs->type == MOUNTABLE_PATH) { > - fs_buf = sysroot_path (fs->device); > - if (fs_buf == NULL) { > - reply_with_perror ("malloc"); > - > - cmderror: > - if (fs->type != MOUNTABLE_PATH && fs_buf) { > - CLEANUP_FREE char *err = NULL; > - if (command (NULL, &err, str_umount, fs_buf, NULL) == -1) > - fprintf (stderr, "%s\n", err); > - > - if (rmdir (fs_buf) == -1 && errno != ENOENT) > - fprintf (stderr, "rmdir: %m\n"); > - } > - return NULL; > - } > - } > - > - else { > - fs_buf = strdup ("/tmp/btrfs.XXXXXX"); > - if (fs_buf == NULL) { > - reply_with_perror ("strdup"); > - goto cmderror; > - } > + char *fs_buf = mount (fs); > > - if (mkdtemp (fs_buf) == NULL) { > - reply_with_perror ("mkdtemp"); > - goto cmderror; > - } > - > - if (mount_vfs_nochroot ("", NULL, fs, fs_buf, "<internal>") == -1) { > - goto cmderror; > - } > - } > + if (!fs_buf) > + return NULL; > > ADD_ARG (argv, i, str_btrfs); > ADD_ARG (argv, i, "subvolume"); > @@ -382,18 +402,8 @@ do_btrfs_subvolume_list (const mountable_t *fs) > CLEANUP_FREE char *out = NULL, *errout = NULL; > int r = commandv (&out, &errout, argv); > > - if (fs->type != MOUNTABLE_PATH) { > - CLEANUP_FREE char *err = NULL; > - if (command (NULL, &err, str_umount, fs_buf, NULL) == -1) { > - reply_with_error ("%s", err ? err : "malloc"); > - goto cmderror; > - } > - > - if (rmdir (fs_buf) == -1 && errno != ENOENT) { > - reply_with_error ("rmdir: %m\n"); > - goto cmderror; > - } > - } > + if (umount (fs_buf, fs) != 0) > + return NULL; > > if (r == -1) { > CLEANUP_FREE char *fs_desc = mountable_to_string (fs); > @@ -401,7 +411,7 @@ do_btrfs_subvolume_list (const mountable_t *fs) > fprintf (stderr, "malloc: %m"); > } > reply_with_error ("%s: %s", fs_desc ? fs_desc : "malloc", errout); > - goto cmderror; > + return NULL; > } > > lines = split_lines (out); > -- > 1.9.3 > > _______________________________________________ > Libguestfs mailing list > Libguestfs@redhat.com > https://www.redhat.com/mailman/listinfo/libguestfs-- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com Fedora Windows cross-compiler. Compile Windows programs, test, and build Windows installers. Over 100 libraries supported. http://fedoraproject.org/wiki/MinGW
Pino Toscano
2014-Dec-16 13:20 UTC
Re: [Libguestfs] [PATCH v3 01/11] daemon: btrfs: add helper functions mount and umount
In data venerdì 12 dicembre 2014 15:03:23, Hu Tao ha scritto:> +static int > +umount (char *fs_buf, const mountable_t *fs) > +{ > + if (fs->type != MOUNTABLE_PATH) { > + CLEANUP_FREE char *err = NULL; > + if (command (NULL, &err, str_umount, fs_buf, NULL) == -1) { > + reply_with_error ("%s", err ? err : "malloc"); > + return -1; > + } > + > + if (rmdir (fs_buf) == -1 && errno != ENOENT) { > + reply_with_error ("rmdir: %m\n"); > + return -1; > + } > + } > + free (fs_buf); > + return 0; > +}The only issue with umount is that it does not free fs_buf properly in all the return paths (e.g. when command or rmdir fail). IMHO it'd be better to leave the ownership of that buffer to whatever calls umount (using CLEANUP_FREE to ease that). -- Pino Toscano
Reasonably Related Threads
- [PATCH v2 00/11] btrfs support part2: qgroup/quota commands
- [PATCH 0/6] btrfs support part1: subvolume commands
- [PATCH v2 0/5] btrfs support part1: subvolume commands
- [PATCH 0/8] btrfs support part2: qgroup commands
- [PATCH 00/16] btrfs: add support to btrfs scrub, balance, rescue and inspect