[PATCH 0/7] Better testing of the guestfsd daemon.
by Richard W.M. Jones
Currently we are unable to properly run guestfsd (the daemon) under
valgrind. Attempts to run valgrind inside the appliance have not been
successful (see patch 1/7).
However we desperately need better valgrind coverage of the daemon,
particularly because it is doing a lot of complex parsing of program
output. This has been a problem for a long time.
A better way to attack this problem is to run the daemon as a regular
host process and connect libguestfs directly to it. Because of
'libguestfs live' functionality this is quite simple: we are able to
connect the library to any Unix domain socket and talk directly to the
daemon.
This patch series modified the daemon so it can be run as a standalone
process listening on a Unix domain socket, adds new tests which run
the daemon as a host process, and a simple framework to run the daemon
under valgrind.
Rich.
9 years, 5 months
[PATCH 0/5] uuid: add btrfs uuid change support and some rework
by Chen Hanxiao
- Btrfs-progs v4.1 introduced new feature of changing
uuid of btrfs partition.
This patch add support of this.
- uuids.c did a lot of deplicated work for changing uuid
of fs. Use existed functions.
-- Introduce new API: btrfstune_set_uuid_random
Chen Hanxiao (5):
uuid: add support to change uuid of btrfs partition
uuid: use existed function of ext2
uuid: use newly introduced do_xfs_admin_uuid of xfs
uuid: use existed do_mkswap_U
New API: btrfstune_set_uuid_random
daemon/btrfs.c | 81 ++++++++++++++++++++++++++++++++++++++++++
daemon/daemon.h | 6 ++++
daemon/uuids.c | 44 +++++------------------
daemon/xfs.c | 7 ++++
generator/actions.ml | 18 ++++++++++
src/MAX_PROC_NR | 2 +-
tests/btrfs/test-btrfs-misc.pl | 6 ++++
7 files changed, 128 insertions(+), 36 deletions(-)
--
2.1.0
9 years, 5 months
[PATCH v5 1/2] do_btrfs_qgroup_show: fix a bad return value
by Chen Hanxiao
We should not use temporary lines buffer as return value,
for lines buffer will be freed.
Signed-off-by: Chen Hanxiao <chenhanxiao(a)cn.fujitsu.com>
---
v5: modify according to Pino's comments
v4: take advantage of sscanf's '%m'.
v3: fix test case failure
daemon/btrfs.c | 34 ++++++++++++++--------------------
1 file changed, 14 insertions(+), 20 deletions(-)
diff --git a/daemon/btrfs.c b/daemon/btrfs.c
index 2f875ae..715d7d2 100644
--- a/daemon/btrfs.c
+++ b/daemon/btrfs.c
@@ -1249,7 +1249,7 @@ do_btrfs_qgroup_show (const char *path)
CLEANUP_FREE char *err = NULL;
CLEANUP_FREE char *out = NULL;
int r;
- char **lines;
+ CLEANUP_FREE_STRING_LIST char **lines = NULL;
path_buf = sysroot_path (path);
if (path_buf == NULL) {
@@ -1275,17 +1275,19 @@ do_btrfs_qgroup_show (const char *path)
if (!lines)
return NULL;
- /* line 0 and 1 are:
+ /* Output of `btrfs qgroup show' is like:
+ *
+ * qgroupid rfer excl
+ * -------- ---- ----
+ * 0/5 9249849344 9249849344
*
- * 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;
+ return NULL;
}
ret->guestfs_int_btrfsqgroup_list_len = nr_qgroups;
@@ -1300,31 +1302,23 @@ do_btrfs_qgroup_show (const char *path)
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) {
+ if (sscanf (line, "%m[0-9/] %" SCNu64 " %" SCNu64,
+ &this->btrfsqgroup_id, &this->btrfsqgroup_rfer,
+ &this->btrfsqgroup_excl) != 3) {
reply_with_error ("cannot parse output of qgroup show command: %s", line);
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)
+ if (ret->guestfs_int_btrfsqgroup_list_val) {
+ for (i = 0; i < nr_qgroups; ++i)
+ free (ret->guestfs_int_btrfsqgroup_list_val[i].btrfsqgroup_id);
free (ret->guestfs_int_btrfsqgroup_list_val);
+ }
free (ret);
return NULL;
--
2.1.0
9 years, 5 months
Conditional statements in libguestfs
by Priyanka Ranjan
Hi Experts,
I am writing a guestfish script . I want to implement conditional logic
inside guestfish script. For example , if state.tgz exists in image do
something else if onetime.tgz exists in the image do someotherthing .
Is it possible to do this within guestfish script. I tried to search a
solution for this in guestfish doucmentation but couldn't find anything
useful.
Thanks in advance for your help.
9 years, 5 months
[PATCH] New API: btrfs_replace
by Cao jin
Signed-off-by: Cao jin <caoj.fnst(a)cn.fujitsu.com>
---
daemon/btrfs.c | 36 +++++++++++++++++++++
generator/actions.ml | 16 ++++++++++
tests/btrfs/Makefile.am | 3 +-
tests/btrfs/test-btrfs-replace.sh | 66 +++++++++++++++++++++++++++++++++++++++
4 files changed, 120 insertions(+), 1 deletion(-)
create mode 100755 tests/btrfs/test-btrfs-replace.sh
diff --git a/daemon/btrfs.c b/daemon/btrfs.c
index 20e5e6b..509a323 100644
--- a/daemon/btrfs.c
+++ b/daemon/btrfs.c
@@ -2060,3 +2060,39 @@ do_btrfs_image (char *const *sources, const char *image,
return 0;
}
+
+int
+do_btrfs_replace (const char *srcdev, const char *targetdev,
+ const char* mntpoint)
+{
+ const size_t MAX_ARGS = 64;
+ const char *argv[MAX_ARGS];
+ size_t i = 0;
+ CLEANUP_FREE char *err = NULL;
+ CLEANUP_FREE char *path_buf = NULL;
+ int r;
+
+ path_buf = sysroot_path (mntpoint);
+ if (path_buf == NULL) {
+ reply_with_perror ("malloc");
+ return -1;
+ }
+
+ ADD_ARG (argv, i, str_btrfs);
+ ADD_ARG (argv, i, "replace");
+ ADD_ARG (argv, i, "start");
+ ADD_ARG (argv, i, srcdev);
+ ADD_ARG (argv, i, targetdev);
+ ADD_ARG (argv, i, path_buf);
+ ADD_ARG (argv, i, "-B");
+ ADD_ARG (argv, i, "-f");
+ ADD_ARG (argv, i, NULL);
+
+ r = commandv (NULL, &err, argv);
+ if (r == -1) {
+ reply_with_error ("%s: %s", mntpoint, err);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/generator/actions.ml b/generator/actions.ml
index d5e5ccf..442f49c 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -12593,6 +12593,22 @@ numbered C<partnum> on device C<device>.
It returns C<primary>, C<logical>, or C<extended>." };
+ { defaults with
+ name = "btrfs_replace"; added = (1, 29, 48);
+ style = RErr, [Device "srcdev"; Device "targetdev"; Pathname "mntpoint"], [];
+ proc_nr = Some 455;
+ optional = Some "btrfs"; camel_name = "BTRFSReplace";
+ test_excuse = "put the test in 'tests/btrfs' directory";
+ shortdesc = "replace a btrfs managed device with another device";
+ longdesc = "\
+Replace device of a btrfs filesystem. On a live filesystem, duplicate the data
+to the target device which is currently stored on the source device.
+After completion of the operation, the source device is wiped out and
+removed from the filesystem.
+
+The C<targetdev> needs to be same size or larger than the C<srcdev>. Devices
+which are currently mounted are never allowed to be used as the C<targetdev>." };
+
]
(* Non-API meta-commands available only in guestfish.
diff --git a/tests/btrfs/Makefile.am b/tests/btrfs/Makefile.am
index bf4d7ae..b6ef794 100644
--- a/tests/btrfs/Makefile.am
+++ b/tests/btrfs/Makefile.am
@@ -20,7 +20,8 @@ include $(top_srcdir)/subdir-rules.mk
TESTS = \
test-btrfs-misc.pl \
test-btrfs-devices.sh \
- test-btrfs-subvolume-default.pl
+ test-btrfs-subvolume-default.pl \
+ test-btrfs-replace.sh
TESTS_ENVIRONMENT = $(top_builddir)/run --test
diff --git a/tests/btrfs/test-btrfs-replace.sh b/tests/btrfs/test-btrfs-replace.sh
new file mode 100755
index 0000000..2bf6d6d
--- /dev/null
+++ b/tests/btrfs/test-btrfs-replace.sh
@@ -0,0 +1,66 @@
+#!/bin/bash -
+# libguestfs
+# Copyright (C) 2015 Fujitsu 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.
+
+# Test btrfs replace devices.
+
+set -e
+
+# Allow the test to be skipped since btrfs is often broken.
+if [ -n "$SKIP_TEST_BTRFS_REPLACE_SH" ]; then
+ echo "$0: skipping test because environment variable is set."
+ exit 77
+fi
+
+# If btrfs is not available, bail.
+if ! guestfish -a /dev/null run : available btrfs; then
+ echo "$0: skipping test because btrfs is not available"
+ exit 77
+fi
+
+rm -f test-btrfs-devices-{1,2}.img replace.output
+
+guestfish <<EOF > replace.output
+# Add 2 empty disks
+sparse test-btrfs-devices-1.img 1G
+sparse test-btrfs-devices-2.img 1G
+run
+
+mkfs-btrfs /dev/sda
+mount /dev/sda /
+
+mkdir /data
+copy-in $srcdir/../data/filesanddirs-10M.tar.xz /data
+
+# now, sda is btrfs while sdb is blank.
+btrfs-replace /dev/sda /dev/sdb /
+
+# after replace: sda is wiped out, while sdb has btrfs with data
+list-filesystems
+ls /data/
+
+EOF
+
+if [ "$(cat replace.output)" != "/dev/sda: unknown
+/dev/sdb: btrfs
+filesanddirs-10M.tar.xz" ]; then
+ echo "btrfs-repalce fail!"
+ cat replace.output
+ exit 1
+fi
+
+rm test-btrfs-devices-{1,2}.img replace.output
--
2.1.0
9 years, 5 months
[PATCH] lib: Add optional 'append' parameter to copy-(device|file)-to-file APIs.
by Richard W.M. Jones
This allows you to append one file to another:
copy-file-to-file /input.txt /output.txt append:true
will append the contents of /input.txt to /output.txt.
---
daemon/copy.c | 38 +++++++++++++++++++++++++++++++-------
generator/actions.ml | 29 +++++++++++++++++++++--------
2 files changed, 52 insertions(+), 15 deletions(-)
diff --git a/daemon/copy.c b/daemon/copy.c
index bab00fe..6f3e844 100644
--- a/daemon/copy.c
+++ b/daemon/copy.c
@@ -30,7 +30,6 @@
#include "actions.h"
/* wrflags */
-#define DEST_FILE_FLAGS O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY|O_CLOEXEC, 0666
#define DEST_DEVICE_FLAGS O_WRONLY|O_CLOEXEC, 0
/* flags */
@@ -210,8 +209,13 @@ copy (const char *src, const char *src_display,
int
do_copy_device_to_device (const char *src, const char *dest,
int64_t srcoffset, int64_t destoffset, int64_t size,
- int sparse)
+ int sparse, int append)
{
+ if ((optargs_bitmask & GUESTFS_COPY_DEVICE_TO_DEVICE_APPEND_BITMASK) &&
+ append) {
+ reply_with_error ("the append flag cannot be set for this call");
+ return -1;
+ }
return copy (src, src, dest, dest, DEST_DEVICE_FLAGS, 0,
srcoffset, destoffset, size, sparse);
}
@@ -219,23 +223,30 @@ do_copy_device_to_device (const char *src, const char *dest,
int
do_copy_device_to_file (const char *src, const char *dest,
int64_t srcoffset, int64_t destoffset, int64_t size,
- int sparse)
+ int sparse, int append)
{
CLEANUP_FREE char *dest_buf = sysroot_path (dest);
+ int wrflags = O_WRONLY|O_CREAT|O_NOCTTY|O_CLOEXEC;
if (!dest_buf) {
reply_with_perror ("malloc");
return -1;
}
- return copy (src, src, dest_buf, dest, DEST_FILE_FLAGS, 0,
+ if ((optargs_bitmask & GUESTFS_COPY_DEVICE_TO_FILE_APPEND_BITMASK) &&
+ append)
+ wrflags |= O_APPEND;
+ else
+ wrflags |= O_TRUNC;
+
+ return copy (src, src, dest_buf, dest, wrflags, 0666, 0,
srcoffset, destoffset, size, sparse);
}
int
do_copy_file_to_device (const char *src, const char *dest,
int64_t srcoffset, int64_t destoffset, int64_t size,
- int sparse)
+ int sparse, int append)
{
CLEANUP_FREE char *src_buf = sysroot_path (src);
@@ -244,6 +255,12 @@ do_copy_file_to_device (const char *src, const char *dest,
return -1;
}
+ if ((optargs_bitmask & GUESTFS_COPY_FILE_TO_DEVICE_APPEND_BITMASK) &&
+ append) {
+ reply_with_error ("the append flag cannot be set for this call");
+ return -1;
+ }
+
return copy (src_buf, src, dest, dest, DEST_DEVICE_FLAGS, 0,
srcoffset, destoffset, size, sparse);
}
@@ -251,9 +268,10 @@ do_copy_file_to_device (const char *src, const char *dest,
int
do_copy_file_to_file (const char *src, const char *dest,
int64_t srcoffset, int64_t destoffset, int64_t size,
- int sparse)
+ int sparse, int append)
{
CLEANUP_FREE char *src_buf = NULL, *dest_buf = NULL;
+ int wrflags = O_WRONLY|O_CREAT|O_NOCTTY|O_CLOEXEC;
src_buf = sysroot_path (src);
if (!src_buf) {
@@ -267,7 +285,13 @@ do_copy_file_to_file (const char *src, const char *dest,
return -1;
}
- return copy (src_buf, src, dest_buf, dest, DEST_FILE_FLAGS,
+ if ((optargs_bitmask & GUESTFS_COPY_FILE_TO_FILE_APPEND_BITMASK) &&
+ append)
+ wrflags |= O_APPEND;
+ else
+ wrflags |= O_TRUNC;
+
+ return copy (src_buf, src, dest_buf, dest, wrflags, 0666,
COPY_UNLINK_DEST_ON_FAILURE,
srcoffset, destoffset, size, sparse);
}
diff --git a/generator/actions.ml b/generator/actions.ml
index d5e5ccf..11b8652 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -9424,7 +9424,7 @@ See also C<guestfs_part_to_dev>." };
{ defaults with
name = "copy_device_to_device"; added = (1, 13, 25);
- style = RErr, [Device "src"; Device "dest"], [OInt64 "srcoffset"; OInt64 "destoffset"; OInt64 "size"; OBool "sparse"];
+ style = RErr, [Device "src"; Device "dest"], [OInt64 "srcoffset"; OInt64 "destoffset"; OInt64 "size"; OBool "sparse"; OBool "append"];
proc_nr = Some 294;
progress = true;
shortdesc = "copy from source device to destination device";
@@ -9448,6 +9448,11 @@ overlapping regions may not be copied correctly.
If the destination is a file, it is created if required. If
the destination file is not large enough, it is extended.
+If the destination is a file and the C<append> flag is not set,
+then the destination file is truncated. If the C<append> flag is
+set, then the copy appends to the destination file. The C<append>
+flag currently cannot be set for devices.
+
If the C<sparse> flag is true then the call avoids writing
blocks that contain only zeroes, which can help in some situations
where the backing disk is thin-provisioned. Note that unless
@@ -9456,7 +9461,7 @@ in incorrect copying." };
{ defaults with
name = "copy_device_to_file"; added = (1, 13, 25);
- style = RErr, [Device "src"; Pathname "dest"], [OInt64 "srcoffset"; OInt64 "destoffset"; OInt64 "size"; OBool "sparse"];
+ style = RErr, [Device "src"; Pathname "dest"], [OInt64 "srcoffset"; OInt64 "destoffset"; OInt64 "size"; OBool "sparse"; OBool "append"];
proc_nr = Some 295;
progress = true;
shortdesc = "copy from source device to destination file";
@@ -9466,7 +9471,7 @@ of this call." };
{ defaults with
name = "copy_file_to_device"; added = (1, 13, 25);
- style = RErr, [Pathname "src"; Device "dest"], [OInt64 "srcoffset"; OInt64 "destoffset"; OInt64 "size"; OBool "sparse"];
+ style = RErr, [Pathname "src"; Device "dest"], [OInt64 "srcoffset"; OInt64 "destoffset"; OInt64 "size"; OBool "sparse"; OBool "append"];
proc_nr = Some 296;
progress = true;
shortdesc = "copy from source file to destination device";
@@ -9476,24 +9481,32 @@ of this call." };
{ defaults with
name = "copy_file_to_file"; added = (1, 13, 25);
- style = RErr, [Pathname "src"; Pathname "dest"], [OInt64 "srcoffset"; OInt64 "destoffset"; OInt64 "size"; OBool "sparse"];
+ style = RErr, [Pathname "src"; Pathname "dest"], [OInt64 "srcoffset"; OInt64 "destoffset"; OInt64 "size"; OBool "sparse"; OBool "append"];
proc_nr = Some 297;
progress = true;
tests = [
InitScratchFS, Always, TestResult (
[["mkdir"; "/copyff"];
["write"; "/copyff/src"; "hello, world"];
- ["copy_file_to_file"; "/copyff/src"; "/copyff/dest"; ""; ""; ""; ""];
+ ["copy_file_to_file"; "/copyff/src"; "/copyff/dest"; ""; ""; ""; ""; "false"];
["read_file"; "/copyff/dest"]],
"compare_buffers (ret, size, \"hello, world\", 12) == 0"), [];
- let size = 1024 * 1024 in
InitScratchFS, Always, TestResultTrue (
+ let size = 1024 * 1024 in
[["mkdir"; "/copyff2"];
["fill"; "0"; string_of_int size; "/copyff2/src"];
["touch"; "/copyff2/dest"];
["truncate_size"; "/copyff2/dest"; string_of_int size];
- ["copy_file_to_file"; "/copyff2/src"; "/copyff2/dest"; ""; ""; ""; "true"];
- ["is_zero"; "/copyff2/dest"]]), []
+ ["copy_file_to_file"; "/copyff2/src"; "/copyff2/dest"; ""; ""; ""; "true"; "false"];
+ ["is_zero"; "/copyff2/dest"]]), [];
+ InitScratchFS, Always, TestResult (
+ [["mkdir"; "/copyff3"];
+ ["write"; "/copyff3/src"; "hello, world"];
+ ["copy_file_to_file"; "/copyff3/src"; "/copyff3/dest"; ""; ""; ""; ""; "true"];
+ ["copy_file_to_file"; "/copyff3/src"; "/copyff3/dest"; ""; ""; ""; ""; "true"];
+ ["copy_file_to_file"; "/copyff3/src"; "/copyff3/dest"; ""; ""; ""; ""; "true"];
+ ["read_file"; "/copyff3/dest"]],
+ "compare_buffers (ret, size, \"hello, worldhello, worldhello, world\", 12*3) == 0"), [];
];
shortdesc = "copy from source file to destination file";
longdesc = "\
--
2.3.1
9 years, 5 months
[PATCH] daemon: Rewrite prog_exists so it uses the actual PATH, not hard-coded list.
by Richard W.M. Jones
---
daemon/guestfsd.c | 37 +++++++++++++++++++++++--------------
1 file changed, 23 insertions(+), 14 deletions(-)
diff --git a/daemon/guestfsd.c b/daemon/guestfsd.c
index 21b3600..c9cc8c5 100644
--- a/daemon/guestfsd.c
+++ b/daemon/guestfsd.c
@@ -243,9 +243,6 @@ main (int argc, char *argv[])
/* Set up a basic environment. After we are called by /init the
* environment is essentially empty.
* https://bugzilla.redhat.com/show_bug.cgi?id=502074#c5
- *
- * NOTE: if you change $PATH, you must also change 'prog_exists'
- * function below.
*/
setenv ("PATH", "/sbin:/usr/sbin:/bin:/usr/bin", 1);
setenv ("SHELL", "/bin/sh", 1);
@@ -1440,22 +1437,34 @@ mountable_to_string (const mountable_t *mountable)
}
}
-/* Check program exists and is executable on $PATH. Actually, we
- * just assume PATH contains the default entries (see main() above).
- */
+/* Check program exists and is executable on $PATH. */
int
prog_exists (const char *prog)
{
- static const char * const dirs[] =
- { "/sbin", "/usr/sbin", "/bin", "/usr/bin" };
- size_t i;
- char buf[1024];
-
- for (i = 0; i < sizeof dirs / sizeof dirs[0]; ++i) {
- snprintf (buf, sizeof buf, "%s/%s", dirs[i], prog);
- if (access (buf, X_OK) == 0)
+ const char *pathc = getenv ("PATH");
+
+ if (!pathc)
+ return 0;
+
+ const char *elem;
+ char *saveptr;
+ size_t len = strlen (pathc) + 1;
+ char path[len];
+ strcpy (path, pathc);
+
+ elem = strtok_r (path, ":", &saveptr);
+ while (elem) {
+ size_t n = strlen (elem) + strlen (prog) + 2;
+ char testprog[n];
+
+ snprintf (testprog, n, "%s/%s", elem, prog);
+ if (access (testprog, X_OK) == 0)
return 1;
+
+ elem = strtok_r (NULL, ":", &saveptr);
}
+
+ /* Not found. */
return 0;
}
--
2.3.1
9 years, 5 months
[PATCH] New API: btrfs_device_stats
by Cao jin
Also modified a public function: analyze_line, make it more flexible
Signed-off-by: Cao jin <caoj.fnst(a)cn.fujitsu.com>
---
daemon/btrfs.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++-----
generator/actions.ml | 12 ++++++++
2 files changed, 88 insertions(+), 7 deletions(-)
diff --git a/daemon/btrfs.c b/daemon/btrfs.c
index 39392f7..f913f66 100644
--- a/daemon/btrfs.c
+++ b/daemon/btrfs.c
@@ -853,11 +853,11 @@ do_btrfs_fsck (const char *device, int64_t superblock, int repair)
* returns the next position following \n.
*/
static char *
-analyze_line (char *line, char **key, char **value)
+analyze_line (char *line, char **key, char **value, char delim)
{
char *p = line;
char *next = NULL;
- char delimiter = ':';
+ char delimiter = delim;
char *del_pos = NULL;
if (!line || *line == '\0') {
@@ -964,7 +964,7 @@ do_btrfs_subvolume_show (const char *subvolume)
* snapshots/test3
*
*/
- p = analyze_line(out, &key, &value);
+ p = analyze_line(out, &key, &value, ':');
if (!p) {
reply_with_error ("truncated output: %s", out);
return NULL;
@@ -984,7 +984,7 @@ do_btrfs_subvolume_show (const char *subvolume)
}
/* Read the lines and split into "key: value". */
- p = analyze_line(p, &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)) {
@@ -994,7 +994,7 @@ do_btrfs_subvolume_show (const char *subvolume)
if (add_string (&ret, key) == -1)
return NULL;
- p = analyze_line(p, &key, &value);
+ p = analyze_line(p, &key, &value, ':');
while (key && !value) {
ss = realloc (ss, ss_len + strlen (key) + 1);
@@ -1008,7 +1008,7 @@ do_btrfs_subvolume_show (const char *subvolume)
ss_len += strlen (key);
ss[ss_len] = '\0';
- p = analyze_line(p, &key, &value);
+ p = analyze_line(p, &key, &value, ':');
}
if (ss) {
@@ -1031,7 +1031,7 @@ do_btrfs_subvolume_show (const char *subvolume)
return NULL;
}
- p = analyze_line(p, &key, &value);
+ p = analyze_line(p, &key, &value, ':');
}
}
@@ -2083,3 +2083,72 @@ do_btrfs_image (char *const *sources, const char *image,
return 0;
}
+
+char **
+do_btrfs_device_stats (const char *path, int zero)
+{
+ const size_t MAX_ARGS = 64;
+ const char *argv[MAX_ARGS];
+ size_t i = 0;
+ CLEANUP_FREE char *buf = NULL;
+ CLEANUP_FREE char *err = NULL;
+ CLEANUP_FREE char *out = NULL;
+ char *p, *key = NULL, *value = NULL;
+ DECLARE_STRINGSBUF (ret);
+ int r;
+ int is_dev;
+
+ is_dev = STREQLEN (path, "/dev/", 5);
+ buf = is_dev ? strdup (path) : sysroot_path (path);
+ if (buf == NULL) {
+ reply_with_perror ("malloc");
+ return NULL;
+ }
+
+
+ ADD_ARG (argv, i, str_btrfs);
+ ADD_ARG (argv, i, "device");
+ ADD_ARG (argv, i, "stats");
+ ADD_ARG (argv, i, buf);
+
+ if ((optargs_bitmask & GUESTFS_BTRFS_DEVICE_STATS_ZERO_BITMASK) && zero) {
+ ADD_ARG (argv, i, "-z");
+ }
+
+ ADD_ARG (argv, i, NULL);
+
+ r = commandv (&out, &err, argv);
+ if (r == -1) {
+ reply_with_error ("%s: %s", path, err);
+ return NULL;
+ }
+
+ /* Output pattern is:
+ *
+ * [/dev/sda].write_io_errs 0
+ * [/dev/sda].read_io_errs 0
+ * [/dev/sda].flush_io_errs 0
+ * [/dev/sda].corruption_errs 0
+ * [/dev/sda].generation_errs 0
+ *
+ */
+
+ /* Read the lines and split into "key: value". */
+ p = analyze_line(out, &key, &value, ' ');
+ while(key)
+ {
+ if (add_string (&ret, key) == -1)
+ return NULL;
+
+ if (add_string (&ret, value) == -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 d5e5ccf..dfb42b5 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -12593,6 +12593,18 @@ numbered C<partnum> on device C<device>.
It returns C<primary>, C<logical>, or C<extended>." };
+ { defaults with
+ name = "btrfs_device_stats"; added = (1, 29, 46);
+ style = RHashtable "devicestats", [Dev_or_Path "path"], [OBool "zero"];
+ proc_nr = Some 456;
+ optional = Some "btrfs"; camel_name = "BTRFSDeviceStats";
+ shortdesc = "read and print the device IO stats for mounted btrfs device";
+ longdesc = "\
+Read and print the device IO stats for all mounted devices of the filesystem
+identified by C<path>, or for a single device identified by C<path>.
+
+If you want to reset stats to zero after reading them, use option: zero:true." };
+
]
(* Non-API meta-commands available only in guestfish.
--
2.1.0
9 years, 5 months
[PATCH v2] New API: btrfs_replace
by Cao jin
Signed-off-by: Cao jin <caoj.fnst(a)cn.fujitsu.com>
---
daemon/btrfs.c | 37 ++++++++++++++++++
generator/actions.ml | 16 ++++++++
tests/btrfs/Makefile.am | 3 +-
tests/btrfs/test-btrfs-replace.sh | 82 +++++++++++++++++++++++++++++++++++++++
4 files changed, 137 insertions(+), 1 deletion(-)
create mode 100755 tests/btrfs/test-btrfs-replace.sh
diff --git a/daemon/btrfs.c b/daemon/btrfs.c
index 39392f7..eba336b 100644
--- a/daemon/btrfs.c
+++ b/daemon/btrfs.c
@@ -2083,3 +2083,40 @@ do_btrfs_image (char *const *sources, const char *image,
return 0;
}
+
+int
+do_btrfs_replace (const char *srcdev, const char *targetdev,
+ const char* mntpoint)
+{
+ const size_t MAX_ARGS = 64;
+ const char *argv[MAX_ARGS];
+ size_t i = 0;
+ CLEANUP_FREE char *err = NULL;
+ CLEANUP_FREE char *path_buf = NULL;
+ int r;
+
+ path_buf = sysroot_path (mntpoint);
+ if (path_buf == NULL) {
+ reply_with_perror ("malloc");
+ return -1;
+ }
+
+ ADD_ARG (argv, i, str_btrfs);
+ ADD_ARG (argv, i, "replace");
+ ADD_ARG (argv, i, "start");
+ ADD_ARG (argv, i, srcdev);
+ ADD_ARG (argv, i, targetdev);
+ ADD_ARG (argv, i, path_buf);
+ ADD_ARG (argv, i, "-B");
+ ADD_ARG (argv, i, "-f");
+ ADD_ARG (argv, i, NULL);
+
+ r = commandv (NULL, &err, argv);
+ if (r == -1) {
+ reply_with_error ("%s: %s", mntpoint, err);
+ return -1;
+ }
+
+ return 0;
+}
+
diff --git a/generator/actions.ml b/generator/actions.ml
index 7252295..ffc2bbf 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -12593,6 +12593,22 @@ numbered C<partnum> on device C<device>.
It returns C<primary>, C<logical>, or C<extended>." };
+ { defaults with
+ name = "btrfs_replace"; added = (1, 29, 46);
+ style = RErr, [Device "srcdev"; Device "targetdev"; Pathname "mntpoint"], [];
+ proc_nr = Some 455;
+ optional = Some "btrfs"; camel_name = "BTRFSReplace";
+ test_excuse = "put the test in 'tests/btrfs' directory";
+ shortdesc = "replace a btrfs managed device with another device";
+ longdesc = "\
+Replace device of a btrfs filesystem. On a live filesystem, duplicate the data
+to the target device which is currently stored on the source device.
+After completion of the operation, the source device is wiped out and
+removed from the filesystem.
+
+The <targetdev> needs to be same size or larger than the <srcdev>. Devices
+which are currently mounted are never allowed to be used as the <targetdev>." };
+
]
(* Non-API meta-commands available only in guestfish.
diff --git a/tests/btrfs/Makefile.am b/tests/btrfs/Makefile.am
index bf4d7ae..b6ef794 100644
--- a/tests/btrfs/Makefile.am
+++ b/tests/btrfs/Makefile.am
@@ -20,7 +20,8 @@ include $(top_srcdir)/subdir-rules.mk
TESTS = \
test-btrfs-misc.pl \
test-btrfs-devices.sh \
- test-btrfs-subvolume-default.pl
+ test-btrfs-subvolume-default.pl \
+ test-btrfs-replace.sh
TESTS_ENVIRONMENT = $(top_builddir)/run --test
diff --git a/tests/btrfs/test-btrfs-replace.sh b/tests/btrfs/test-btrfs-replace.sh
new file mode 100755
index 0000000..c095e0b
--- /dev/null
+++ b/tests/btrfs/test-btrfs-replace.sh
@@ -0,0 +1,82 @@
+#!/bin/bash -
+# libguestfs
+# Copyright (C) 2015 Fujitsu 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.
+
+# Test btrfs replace devices.
+
+set -e
+
+# Allow the test to be skipped since btrfs is often broken.
+if [ -n "$SKIP_TEST_BTRFS_REPLACE_SH" ]; then
+ echo "$0: skipping test because environment variable is set."
+ exit 77
+fi
+
+# If btrfs is not available, bail.
+if ! guestfish -a /dev/null run : available btrfs; then
+ echo "$0: skipping test because btrfs is not available"
+ exit 77
+fi
+
+rm -f test-btrfs-devices-{1,2}.img replace.output
+
+guestfish <<EOF > replace.output
+# Add 2 empty disks
+sparse test-btrfs-devices-1.img 1G
+sparse test-btrfs-devices-2.img 1G
+run
+
+mkfs-btrfs /dev/sda
+mount /dev/sda /
+
+mkdir /data
+copy-in $srcdir/../data/filesanddirs-10M.tar.xz /data
+
+# now, sda is btrfs while sdb is blank.
+btrfs-replace /dev/sda /dev/sdb /
+
+# after replace: sda is wiped out, while sdb has btrfs with data
+list-filesystems
+
+EOF
+
+if [ "$(cat replace.output)" != "/dev/sda: unknown
+/dev/sdb: btrfs" ]; then
+ echo "btrfs-repalce fail!"
+ cat replace.output
+ exit 1
+fi
+
+rm -f replace.output
+
+#now, we do switch, replace the device back.
+guestfish -a test-btrfs-devices-1.img -a test-btrfs-devices-2.img <<EOF > replace.output
+run
+mount /dev/sdb /
+btrfs-replace /dev/sdb /dev/sda /
+list-filesystems
+
+EOF
+
+if [ "$(cat replace.output)" != "/dev/sda: btrfs
+/dev/sdb: unknown" ]; then
+ echo "btrfs-repalce back fail!"
+ cat replace.output
+ exit 2
+fi
+
+rm test-btrfs-devices-{1,2}.img replace.output
--
2.1.0
9 years, 5 months
[PATCH] Modify the function: analyze_line, make it more flexible
by Cao jin
Modify the function from a fixed delimiter to a variable. So,
it can be used in more APIs later. Also modified the existing
callers
Signed-off-by: Cao jin <caoj.fnst(a)cn.fujitsu.com>
---
daemon/btrfs.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/daemon/btrfs.c b/daemon/btrfs.c
index 8b5779a..afbd6e6 100644
--- a/daemon/btrfs.c
+++ b/daemon/btrfs.c
@@ -853,11 +853,10 @@ do_btrfs_fsck (const char *device, int64_t superblock, int repair)
* returns the next position following \n.
*/
static char *
-analyze_line (char *line, char **key, char **value)
+analyze_line (char *line, char **key, char **value, char delimiter)
{
char *p = line;
char *next = NULL;
- char delimiter = ':';
char *del_pos = NULL;
if (!line || *line == '\0') {
@@ -964,7 +963,7 @@ do_btrfs_subvolume_show (const char *subvolume)
* snapshots/test3
*
*/
- p = analyze_line(out, &key, &value);
+ p = analyze_line(out, &key, &value, ':');
if (!p) {
reply_with_error ("truncated output: %s", out);
return NULL;
@@ -984,7 +983,7 @@ do_btrfs_subvolume_show (const char *subvolume)
}
/* Read the lines and split into "key: value". */
- p = analyze_line(p, &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)) {
@@ -994,7 +993,7 @@ do_btrfs_subvolume_show (const char *subvolume)
if (add_string (&ret, key) == -1)
return NULL;
- p = analyze_line(p, &key, &value);
+ p = analyze_line(p, &key, &value, ':');
while (key && !value) {
ss = realloc (ss, ss_len + strlen (key) + 1);
@@ -1008,7 +1007,7 @@ do_btrfs_subvolume_show (const char *subvolume)
ss_len += strlen (key);
ss[ss_len] = '\0';
- p = analyze_line(p, &key, &value);
+ p = analyze_line(p, &key, &value, ':');
}
if (ss) {
@@ -1031,7 +1030,7 @@ do_btrfs_subvolume_show (const char *subvolume)
return NULL;
}
- p = analyze_line(p, &key, &value);
+ p = analyze_line(p, &key, &value, ':');
}
}
@@ -2061,3 +2060,4 @@ do_btrfs_image (char *const *sources, const char *image,
return 0;
}
--
2.1.0
9 years, 5 months