diff options
| author | Richard W.M. Jones <rjones@redhat.com> | 2012-04-25 16:35:12 +0100 |
|---|---|---|
| committer | Richard W.M. Jones <rjones@redhat.com> | 2012-04-25 17:32:30 +0100 |
| commit | 87ea7a04094d5ed40f3f047ff2b7a613d4d530d4 (patch) | |
| tree | 458b3713c313d124c37b8de11e45d0b081f3fde6 | |
| parent | 3cc9703f901e85a589692b9d0bf5ef7cbf72ed73 (diff) | |
| download | libguestfs-87ea7a04094d5ed40f3f047ff2b7a613d4d530d4.tar.gz libguestfs-87ea7a04094d5ed40f3f047ff2b7a613d4d530d4.tar.xz libguestfs-87ea7a04094d5ed40f3f047ff2b7a613d4d530d4.zip | |
New btrfs APIs.
Bind the easy parts of the 'btrfs' program.
The new APIs are:
btrfs-device-add: add devices to a btrfs filesystem
btrfs-device-delete: remove devices from a btrfs filesystem
btrfs-filesystem-sync: sync a btrfs filesystem
btrfs-filesystem-balance: balance a btrfs filesystem
btrfs-subvolume-create: create a btrfs snapshot
btrfs-subvolume-delete: delete a btrfs snapshot
btrfs-subvolume-list: list btrfs snapshots and subvolumes
btrfs-subvolume-set-default: set default btrfs subvolume
btrfs-subvolume-snapshot: create a writable btrfs snapshot
| -rw-r--r-- | Makefile.am | 1 | ||||
| -rw-r--r-- | configure.ac | 1 | ||||
| -rw-r--r-- | daemon/btrfs.c | 396 | ||||
| -rw-r--r-- | generator/generator_actions.ml | 83 | ||||
| -rw-r--r-- | generator/generator_structs.ml | 8 | ||||
| -rw-r--r-- | gobject/Makefile.inc | 2 | ||||
| -rw-r--r-- | java/Makefile.inc | 1 | ||||
| -rw-r--r-- | java/com/redhat/et/libguestfs/.gitignore | 1 | ||||
| -rw-r--r-- | po/POTFILES.in | 1 | ||||
| -rw-r--r-- | src/MAX_PROC_NR | 2 | ||||
| -rw-r--r-- | tests/btrfs/Makefile.am | 31 | ||||
| -rwxr-xr-x | tests/btrfs/test-btrfs-devices.sh | 57 | ||||
| -rwxr-xr-x | tests/btrfs/test-btrfs-subvolume-default.pl | 95 |
13 files changed, 678 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am index 32999808..ae0ea3ff 100644 --- a/Makefile.am +++ b/Makefile.am @@ -42,6 +42,7 @@ SUBDIRS += tests/lvm SUBDIRS += tests/luks SUBDIRS += tests/md SUBDIRS += tests/ntfsclone +SUBDIRS += tests/btrfs SUBDIRS += tests/regressions endif diff --git a/configure.ac b/configure.ac index e16d6c8c..fe603717 100644 --- a/configure.ac +++ b/configure.ac @@ -1229,6 +1229,7 @@ AC_CONFIG_FILES([Makefile src/Makefile sysprep/Makefile test-tool/Makefile + tests/btrfs/Makefile tests/c-api/Makefile tests/data/Makefile tests/extra/Makefile diff --git a/daemon/btrfs.c b/daemon/btrfs.c index 60c863a4..8569173e 100644 --- a/daemon/btrfs.c +++ b/daemon/btrfs.c @@ -202,3 +202,399 @@ do_mkfs_btrfs (char *const *devices, free (err); return 0; } + +int +do_btrfs_subvolume_snapshot (const char *source, const char *dest) +{ + const size_t MAX_ARGS = 64; + const char *argv[MAX_ARGS]; + size_t i = 0; + char *source_buf, *dest_buf; + char *err; + int r; + + source_buf = sysroot_path (source); + if (source_buf == NULL) { + reply_with_perror ("malloc"); + return -1; + } + dest_buf = sysroot_path (dest); + if (dest_buf == NULL) { + reply_with_perror ("malloc"); + free (source_buf); + return -1; + } + + ADD_ARG (argv, i, "btrfs"); + ADD_ARG (argv, i, "subvolume"); + ADD_ARG (argv, i, "snapshot"); + ADD_ARG (argv, i, source_buf); + ADD_ARG (argv, i, dest_buf); + ADD_ARG (argv, i, NULL); + + r = commandv (NULL, &err, argv); + free (source_buf); + free (dest_buf); + if (r == -1) { + reply_with_error ("%s: %s: %s", source, dest, err); + free (err); + return -1; + } + free (err); + + return 0; +} + +int +do_btrfs_subvolume_delete (const char *subvolume) +{ + const size_t MAX_ARGS = 64; + const char *argv[MAX_ARGS]; + size_t i = 0; + char *subvolume_buf; + char *err; + int r; + + subvolume_buf = sysroot_path (subvolume); + if (subvolume_buf == NULL) { + reply_with_perror ("malloc"); + return -1; + } + + ADD_ARG (argv, i, "btrfs"); + ADD_ARG (argv, i, "subvolume"); + ADD_ARG (argv, i, "delete"); + ADD_ARG (argv, i, subvolume_buf); + ADD_ARG (argv, i, NULL); + + r = commandv (NULL, &err, argv); + free (subvolume_buf); + if (r == -1) { + reply_with_error ("%s: %s", subvolume, err); + free (err); + return -1; + } + free (err); + + return 0; +} + +int +do_btrfs_subvolume_create (const char *dest) +{ + const size_t MAX_ARGS = 64; + const char *argv[MAX_ARGS]; + size_t i = 0; + char *dest_buf; + char *err; + int r; + + dest_buf = sysroot_path (dest); + if (dest_buf == NULL) { + reply_with_perror ("malloc"); + return -1; + } + + ADD_ARG (argv, i, "btrfs"); + ADD_ARG (argv, i, "subvolume"); + ADD_ARG (argv, i, "create"); + ADD_ARG (argv, i, dest_buf); + ADD_ARG (argv, i, NULL); + + r = commandv (NULL, &err, argv); + free (dest_buf); + if (r == -1) { + reply_with_error ("%s: %s", dest, err); + free (err); + return -1; + } + free (err); + + return 0; +} + +guestfs_int_btrfssubvolume_list * +do_btrfs_subvolume_list (const char *fs) +{ + const size_t MAX_ARGS = 64; + guestfs_int_btrfssubvolume_list *ret; + char *fs_buf; + const char *argv[MAX_ARGS]; + size_t i = 0; + char *out, *err, **lines, *pos; + size_t nr_subvolumes; + int r; + + fs_buf = sysroot_path (fs); + if (fs_buf == NULL) { + reply_with_perror ("malloc"); + return NULL; + } + + ADD_ARG (argv, i, "btrfs"); + ADD_ARG (argv, i, "subvolume"); + ADD_ARG (argv, i, "list"); + ADD_ARG (argv, i, fs_buf); + ADD_ARG (argv, i, NULL); + + r = commandv (&out, &err, argv); + free (fs_buf); + if (r == -1) { + reply_with_error ("%s: %s", fs, err); + free (err); + return NULL; + } + free (err); + + lines = split_lines (out); + free (out); + if (!lines) + return NULL; + + /* Output is: + * + * ID 256 top level 5 path test1 + * ID 257 top level 5 path dir/test2 + * ID 258 top level 5 path test3 + * + * "ID <n>" is the subvolume ID. "top level <n>" is the top level + * subvolume ID. "path <str>" is the subvolume path, relative to + * the top of the filesystem. + */ + nr_subvolumes = count_strings (lines); + + ret = malloc (sizeof *ret); + if (!ret) { + reply_with_perror ("malloc"); + free_stringslen (lines, nr_subvolumes); + return NULL; + } + ret->guestfs_int_btrfssubvolume_list_len = nr_subvolumes; + ret->guestfs_int_btrfssubvolume_list_val = + calloc (nr_subvolumes, sizeof (struct guestfs_int_btrfssubvolume)); + if (ret->guestfs_int_btrfssubvolume_list_val == NULL) { + reply_with_perror ("malloc"); + free (ret); + free_stringslen (lines, nr_subvolumes); + return NULL; + } + + for (i = 0; i < nr_subvolumes; ++i) { + /* To avoid allocations, reuse the 'line' buffer to store the + * path. Thus we don't need to free 'line', since it will be + * freed by the calling (XDR) code. + */ + char *line = lines[i]; + + if (sscanf (line, "ID %" SCNu64 " top level %" SCNu64 " path ", + &ret->guestfs_int_btrfssubvolume_list_val[i].btrfssubvolume_id, + &ret->guestfs_int_btrfssubvolume_list_val[i].btrfssubvolume_top_level_id) != 2) { + unexpected_output: + reply_with_error ("unexpected output from 'btrfs subvolume list' command: %s", line); + free_stringslen (lines, nr_subvolumes); + free (ret->guestfs_int_btrfssubvolume_list_val); + free (ret); + return NULL; + } + + pos = strstr (line, " path "); + if (pos == NULL) + goto unexpected_output; + pos += 6; + + memmove (line, pos, strlen (pos) + 1); + ret->guestfs_int_btrfssubvolume_list_val[i].btrfssubvolume_path = line; + } + + return ret; +} + +int +do_btrfs_subvolume_set_default (int64_t id, const char *fs) +{ + const size_t MAX_ARGS = 64; + const char *argv[MAX_ARGS]; + size_t i = 0; + char *fs_buf; + char buf[64]; + char *err; + int r; + + snprintf (buf, sizeof buf, "%" PRIi64, id); + + fs_buf = sysroot_path (fs); + if (fs_buf == NULL) { + reply_with_perror ("malloc"); + return -1; + } + + ADD_ARG (argv, i, "btrfs"); + ADD_ARG (argv, i, "subvolume"); + ADD_ARG (argv, i, "set-default"); + ADD_ARG (argv, i, buf); + ADD_ARG (argv, i, fs_buf); + ADD_ARG (argv, i, NULL); + + r = commandv (NULL, &err, argv); + free (fs_buf); + if (r == -1) { + reply_with_error ("%s: %s", fs, err); + free (err); + return -1; + } + free (err); + + return 0; +} + +int +do_btrfs_filesystem_sync (const char *fs) +{ + const size_t MAX_ARGS = 64; + const char *argv[MAX_ARGS]; + size_t i = 0; + char *fs_buf; + char *err; + int r; + + fs_buf = sysroot_path (fs); + if (fs_buf == NULL) { + reply_with_perror ("malloc"); + return -1; + } + + ADD_ARG (argv, i, "btrfs"); + ADD_ARG (argv, i, "filesystem"); + ADD_ARG (argv, i, "sync"); + ADD_ARG (argv, i, fs_buf); + ADD_ARG (argv, i, NULL); + + r = commandv (NULL, &err, argv); + free (fs_buf); + if (r == -1) { + reply_with_error ("%s: %s", fs, err); + free (err); + return -1; + } + free (err); + + return 0; +} + +int +do_btrfs_filesystem_balance (const char *fs) +{ + const size_t MAX_ARGS = 64; + const char *argv[MAX_ARGS]; + size_t i = 0; + char *fs_buf; + char *err; + int r; + + fs_buf = sysroot_path (fs); + if (fs_buf == NULL) { + reply_with_perror ("malloc"); + return -1; + } + + ADD_ARG (argv, i, "btrfs"); + ADD_ARG (argv, i, "filesystem"); + ADD_ARG (argv, i, "balance"); + ADD_ARG (argv, i, fs_buf); + ADD_ARG (argv, i, NULL); + + r = commandv (NULL, &err, argv); + free (fs_buf); + if (r == -1) { + reply_with_error ("%s: %s", fs, err); + free (err); + return -1; + } + free (err); + + return 0; +} + +int +do_btrfs_device_add (char *const *devices, const char *fs) +{ + size_t nr_devices = count_strings (devices); + + if (nr_devices == 0) + return 0; + + size_t MAX_ARGS = nr_devices + 8; + const char *argv[MAX_ARGS]; + size_t i = 0, j; + char *fs_buf; + char *err; + int r; + + fs_buf = sysroot_path (fs); + if (fs_buf == NULL) { + reply_with_perror ("malloc"); + return -1; + } + + ADD_ARG (argv, i, "btrfs"); + ADD_ARG (argv, i, "device"); + ADD_ARG (argv, i, "add"); + + for (j = 0; j < nr_devices; ++j) + ADD_ARG (argv, i, devices[j]); + + ADD_ARG (argv, i, fs_buf); + ADD_ARG (argv, i, NULL); + + r = commandv (NULL, &err, argv); + free (fs_buf); + if (r == -1) { + reply_with_error ("%s: %s", fs, err); + free (err); + return -1; + } + free (err); + + return 0; +} + +int +do_btrfs_device_delete (char *const *devices, const char *fs) +{ + size_t nr_devices = count_strings (devices); + + if (nr_devices == 0) + return 0; + + size_t MAX_ARGS = nr_devices + 8; + const char *argv[MAX_ARGS]; + size_t i = 0, j; + char *fs_buf; + char *err; + int r; + + fs_buf = sysroot_path (fs); + if (fs_buf == NULL) { + reply_with_perror ("malloc"); + return -1; + } + + ADD_ARG (argv, i, "btrfs"); + ADD_ARG (argv, i, "device"); + ADD_ARG (argv, i, "delete"); + for (j = 0; j < nr_devices; ++j) + ADD_ARG (argv, i, devices[j]); + ADD_ARG (argv, i, fs); + ADD_ARG (argv, i, NULL); + + r = commandv (NULL, &err, argv); + free (fs_buf); + if (r == -1) { + reply_with_error ("%s: %s", fs, err); + free (err); + return -1; + } + free (err); + + return 0; +} diff --git a/generator/generator_actions.ml b/generator/generator_actions.ml index 56af327a..c237061a 100644 --- a/generator/generator_actions.ml +++ b/generator/generator_actions.ml @@ -7136,6 +7136,89 @@ This sets the ext2 file generation of a file. See C<guestfs_get_e2generation>."); + ("btrfs_subvolume_snapshot", (RErr, [Pathname "source"; Pathname "dest"], []), 322, [Optional "btrfs"; CamelName "BTRFSSubvolumeSnapshot"], + [InitPartition, IfAvailable "btrfs", TestRun ( + [["mkfs_btrfs"; "/dev/sda1"; ""; ""; "NOARG"; ""; "NOARG"; "NOARG"; ""; ""]; + ["mount"; "/dev/sda1"; "/"]; + ["mkdir"; "/dir"]; + ["btrfs_subvolume_create"; "/test1"]; + ["btrfs_subvolume_create"; "/test2"]; + ["btrfs_subvolume_create"; "/dir/test3"]; + ["btrfs_subvolume_snapshot"; "/dir/test3"; "/dir/test4"]])], + "create a writable btrfs snapshot", + "\ +Create a writable snapshot of the btrfs subvolume C<source>. +The C<dest> argument is the destination directory and the name +of the snapshot, in the form C</path/to/dest/name>."); + + ("btrfs_subvolume_delete", (RErr, [Pathname "subvolume"], []), 323, [Optional "btrfs"; CamelName "BTRFSSubvolumeDelete"], + [InitPartition, IfAvailable "btrfs", TestRun ( + [["mkfs_btrfs"; "/dev/sda1"; ""; ""; "NOARG"; ""; "NOARG"; "NOARG"; ""; ""]; + ["mount"; "/dev/sda1"; "/"]; + ["btrfs_subvolume_create"; "/test1"]; + ["btrfs_subvolume_delete"; "/test1"]])], + "delete a btrfs snapshot", + "\ +Delete the named btrfs subvolume."); + + ("btrfs_subvolume_create", (RErr, [Pathname "dest"], []), 324, [Optional "btrfs"; CamelName "BTRFSSubvolumeCreate"], + [], (* tested above *) + "create a btrfs snapshot", + "\ +Create a btrfs subvolume. The C<dest> argument is the destination +directory and the name of the snapshot, in the form C</path/to/dest/name>."); + + ("btrfs_subvolume_list", (RStructList ("subvolumes", "btrfssubvolume"), [Pathname "fs"], []), 325, [Optional "btrfs"; CamelName "BTRFSSubvolumeList"], + [], (* tested in tests/btrfs *) + "list btrfs snapshots and subvolumes", + "\ +List the btrfs snapshots and subvolumes of the btrfs filesystem +which is mounted at C<fs>."); + + ("btrfs_subvolume_set_default", (RErr, [Int64 "id"; Pathname "fs"], []), 326, [Optional "btrfs"; CamelName "BTRFSSubvolumeSetDefault"], + [], (* tested in tests/btrfs *) + "set default btrfs subvolume", + "\ +Set the subvolume of the btrfs filesystem C<fs> which will +be mounted by default. See <guestfs_btrfs_subvolume_list> to +get a list of subvolumes."); + + ("btrfs_filesystem_sync", (RErr, [Pathname "fs"], []), 327, [Optional "btrfs"; CamelName "BTRFSFilesystemSync"], + [InitPartition, IfAvailable "btrfs", TestRun ( + [["mkfs_btrfs"; "/dev/sda1"; ""; ""; "NOARG"; ""; "NOARG"; "NOARG"; ""; ""]; + ["mount"; "/dev/sda1"; "/"]; + ["btrfs_subvolume_create"; "/test1"]; + ["btrfs_filesystem_sync"; "/test1"]; + ["btrfs_filesystem_balance"; "/test1"]])], + "sync a btrfs filesystem", + "\ +Force sync on the btrfs filesystem mounted at C<fs>."); + + ("btrfs_filesystem_balance", (RErr, [Pathname "fs"], []), 328, [Optional "btrfs"; CamelName "BTRFSFilesystemBalance"], + [], (* tested above *) + "balance a btrfs filesystem", + "\ +Balance the chunks in the btrfs filesystem mounted at C<fs> +across the underlying devices."); + + ("btrfs_device_add", (RErr, [DeviceList "devices"; Pathname "fs"], []), 329, [Optional "btrfs"; CamelName "BTRFSDeviceAdd"], + [], (* test disk isn't large enough to test this thoroughly, so there + * is an external test in 'tests/btrfs' directory. + *) + "add devices to a btrfs filesystem", + "\ +Add the list of device(s) in C<devices> to the btrfs filesystem +mounted at C<fs>. If C<devices> is an empty list, this does nothing."); + + ("btrfs_device_delete", (RErr, [DeviceList "devices"; Pathname "fs"], []), 330, [Optional "btrfs"; CamelName "BTRFSDeviceDelete"], + [], (* test disk isn't large enough to test this thoroughly, so there + * is an external test in 'tests/btrfs' directory. + *) + "remove devices from a btrfs filesystem", + "\ +Remove the C<devices> from the btrfs filesystem mounted at C<fs>. +If C<devices> is an empty list, this does nothing."); + ] let all_functions = non_daemon_functions @ daemon_functions diff --git a/generator/generator_structs.ml b/generator/generator_structs.ml index 8c862ae3..024bb3cd 100644 --- a/generator/generator_structs.ml +++ b/generator/generator_structs.ml @@ -219,6 +219,13 @@ let structs = [ "mdstat_index", FInt32; "mdstat_flags", FString; ]; + + (* btrfs subvolume list output *) + "btrfssubvolume", [ + "btrfssubvolume_id", FUInt64; + "btrfssubvolume_top_level_id", FUInt64; + "btrfssubvolume_path", FString; + ]; ] (* end of structs *) (* For bindings which want camel case *) @@ -237,6 +244,7 @@ let camel_structs = [ "application", "Application"; "isoinfo", "ISOInfo"; "mdstat", "MDStat"; + "btrfssubvolume", "BTRFSSubvolume"; ] let camel_structs = List.sort (fun (_,a) (_,b) -> compare a b) camel_structs diff --git a/gobject/Makefile.inc b/gobject/Makefile.inc index ac65cd37..69bb44bb 100644 --- a/gobject/Makefile.inc +++ b/gobject/Makefile.inc @@ -37,6 +37,7 @@ guestfs_gobject_headers=\ guestfs-gobject-struct-application.h \ guestfs-gobject-struct-isoinfo.h \ guestfs-gobject-struct-mdstat.h \ + guestfs-gobject-struct-btrfssubvolume.h \ guestfs-gobject-optargs-test0.h \ guestfs-gobject-optargs-add_drive_opts.h \ guestfs-gobject-optargs-add_domain.h \ @@ -78,6 +79,7 @@ guestfs_gobject_sources=\ guestfs-gobject-struct-application.c \ guestfs-gobject-struct-isoinfo.c \ guestfs-gobject-struct-mdstat.c \ + guestfs-gobject-struct-btrfssubvolume.c \ guestfs-gobject-optargs-test0.c \ guestfs-gobject-optargs-add_drive_opts.c \ guestfs-gobject-optargs-add_domain.c \ diff --git a/java/Makefile.inc b/java/Makefile.inc index 64c6dcc2..efad2a0c 100644 --- a/java/Makefile.inc +++ b/java/Makefile.inc @@ -21,6 +21,7 @@ java_built_sources = \ com/redhat/et/libguestfs/Application.java \ + com/redhat/et/libguestfs/BTRFSSubvolume.java \ com/redhat/et/libguestfs/Dirent.java \ com/redhat/et/libguestfs/INotifyEvent.java \ com/redhat/et/libguestfs/ISOInfo.java \ diff --git a/java/com/redhat/et/libguestfs/.gitignore b/java/com/redhat/et/libguestfs/.gitignore index c7cc3020..9556d816 100644 --- a/java/com/redhat/et/libguestfs/.gitignore +++ b/java/com/redhat/et/libguestfs/.gitignore @@ -1,4 +1,5 @@ Application.java +BTRFSSubvolume.java Dirent.java INotifyEvent.java ISOInfo.java diff --git a/po/POTFILES.in b/po/POTFILES.in index 01d260ab..c5a87e5d 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -156,6 +156,7 @@ gobject/guestfs-gobject-optargs-tune2fs.c gobject/guestfs-gobject-optargs-umount_local.c gobject/guestfs-gobject-session.c gobject/guestfs-gobject-struct-application.c +gobject/guestfs-gobject-struct-btrfssubvolume.c gobject/guestfs-gobject-struct-dirent.c gobject/guestfs-gobject-struct-inotify_event.c gobject/guestfs-gobject-struct-int_bool.c diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR index 3ae0b938..db2cef56 100644 --- a/src/MAX_PROC_NR +++ b/src/MAX_PROC_NR @@ -1 +1 @@ -321 +330 diff --git a/tests/btrfs/Makefile.am b/tests/btrfs/Makefile.am new file mode 100644 index 00000000..6d789ba7 --- /dev/null +++ b/tests/btrfs/Makefile.am @@ -0,0 +1,31 @@ +# libguestfs +# Copyright (C) 2009-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 $(top_srcdir)/subdir-rules.mk + +TESTS = \ + test-btrfs-devices.sh \ + test-btrfs-subvolume-default.pl + +random_val := $(shell awk 'BEGIN{srand(); print 1+int(255*rand())}' < /dev/null) + +TESTS_ENVIRONMENT = \ + MALLOC_PERTURB_=$(random_val) \ + $(top_builddir)/run + +EXTRA_DIST = \ + $(TESTS) diff --git a/tests/btrfs/test-btrfs-devices.sh b/tests/btrfs/test-btrfs-devices.sh new file mode 100755 index 00000000..546ce7c5 --- /dev/null +++ b/tests/btrfs/test-btrfs-devices.sh @@ -0,0 +1,57 @@ +#!/bin/bash - +# libguestfs +# 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. + +# Test btrfs adding/removing devices. + +set -e + +# XXX Not a very good test. +if ! btrfs --help >/dev/null 2>&1; then + echo "$0: test skipped because no 'btrfs' utility" + exit 0 +fi + +rm -f test[1234].img + +../../fish/guestfish <<EOF +# Add four empty disks +sparse test1.img 1G +sparse test2.img 1G +sparse test3.img 1G +sparse test4.img 1G +run + +part-disk /dev/sda mbr +part-disk /dev/sdb mbr +part-disk /dev/sdc mbr +part-disk /dev/sdd mbr + +mkfs-btrfs "/dev/sda1 /dev/sdb1" +mount /dev/sda1 / + +mkdir /foo +touch /foo/bar + +btrfs-device-add "/dev/sdc1 /dev/sdd1" / + +# I cannot get this to work, seems to be a btrfs bug: +#btrfs-device-delete "/dev/sda1 /dev/sdb1" / + +EOF + +rm -f test[1234].img diff --git a/tests/btrfs/test-btrfs-subvolume-default.pl b/tests/btrfs/test-btrfs-subvolume-default.pl new file mode 100755 index 00000000..013291ba --- /dev/null +++ b/tests/btrfs/test-btrfs-subvolume-default.pl @@ -0,0 +1,95 @@ +#!/usr/bin/perl +# libguestfs +# 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. + +# Test btrfs subvolume list and btrfs subvolume default-id. + +use strict; +use warnings; + +use Sys::Guestfs; +use Sys::Guestfs::Lib qw(feature_available); + +my $testimg = "test1.img"; + +unlink $testimg; +open FILE, ">$testimg" or die "$testimg: $!"; +truncate FILE, 1024*1024*1024 or die "$testimg: truncate: $!"; +close FILE or die "$testimg: $!"; + +my $g = Sys::Guestfs->new (); + +$g->add_drive_opts ($testimg, format => "raw"); +$g->launch (); + +# If btrfs is not available, bail. +unless (feature_available ($g, "btrfs")) { + warn "$0: skipping test because btrfs is not available\n"; + exit 0; +} + +$g->part_disk ("/dev/sda", "mbr"); + +$g->mkfs_btrfs (["/dev/sda1"]); +$g->mount ("/dev/sda1", "/"); + +$g->btrfs_subvolume_create ("/test1"); +$g->mkdir ("/test1/foo"); +$g->btrfs_subvolume_create ("/test2"); + +my @vols = $g->btrfs_subvolume_list ("/"); + +# Check the subvolume list, and extract the subvolume ID of path 'test1', +# and the top level ID (which should be the same for both subvolumes). +die ("expected 2 subvolumes, but got ", 0+@vols, " instead") unless @vols == 2; + +my %ids; +my $top_level_id; +foreach (@vols) { + my $path = $_->{btrfssubvolume_path}; + my $id = $_->{btrfssubvolume_id}; + my $top = $_->{btrfssubvolume_top_level_id}; + + if (!defined $top_level_id) { + $top_level_id = $top; + } elsif ($top_level_id != $top) { + die "top_level_id fields are not all the same"; + } + + $ids{$path} = $id; +} + +die "no subvolume path 'test1' found" unless exists $ids{test1}; + +my $test1_id = $ids{test1}; + +$g->btrfs_subvolume_set_default ($test1_id, "/"); +$g->umount ("/"); +$g->mount ("/dev/sda1", "/"); +# This was originally /test1/foo, but now that we changed the +# default ID to 'test1', /test1 is mounted as /, so: +$g->mkdir ("/foo/bar"); + +$g->btrfs_subvolume_set_default ($top_level_id, "/"); +$g->umount ("/"); +$g->mount ("/dev/sda1", "/"); +# Now we're back to the original default volume, so this should work: +$g->mkdir ("/test1/foo/bar/baz"); + +$g->close (); + +unlink $testimg or die "$testimg: unlink: $!"; |
