From c11a92751e003b3d4bc3584b598afc9bd9d9e703 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Fri, 11 Nov 2011 11:01:46 +0000 Subject: [PATCH] New API: mdadm-create for creating MD devices. --- daemon/Makefile.am | 1 + daemon/md.c | 170 +++++++++++++++++++++++++++++++++++++++++ generator/generator_actions.ml | 58 ++++++++++++++ po/POTFILES.in | 1 + regressions/Makefile.am | 1 + regressions/test-mdadm.sh | 95 +++++++++++++++++++++++ src/MAX_PROC_NR | 2 +- 7 files changed, 327 insertions(+), 1 deletion(-) create mode 100644 daemon/md.c create mode 100755 regressions/test-mdadm.sh diff --git a/daemon/Makefile.am b/daemon/Makefile.am index 7757067..c4a30bc 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -129,6 +129,7 @@ guestfsd_SOURCES = \ luks.c \ lvm.c \ lvm-filter.c \ + md.c \ mkfs.c \ mknod.c \ modprobe.c \ diff --git a/daemon/md.c b/daemon/md.c new file mode 100644 index 0000000..1adb4ac --- /dev/null +++ b/daemon/md.c @@ -0,0 +1,170 @@ +/* libguestfs - the guestfsd daemon + * Copyright (C) 2011 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 + +#include +#include +#include +#include +#include + +#include "daemon.h" +#include "actions.h" +#include "optgroups.h" + +int +optgroup_mdadm_available (void) +{ + return prog_exists ("mdadm"); +} + +static size_t +count_bits (uint64_t bitmap) +{ + size_t c; + + if (bitmap == 0) + return 0; + + c = bitmap & 1 ? 1 : 0; + bitmap >>= 1; + return c + count_bits (bitmap); +} + +/* Takes optional arguments, consult optargs_bitmask. */ +int +do_mdadm_create (const char *name, char *const *devices, + int64_t missingbitmap, int nrdevices, int spare, + int64_t chunk, const char *level) +{ + char nrdevices_s[32]; + char spare_s[32]; + char chunk_s[32]; + size_t j; + int r; + char *err; + uint64_t umissingbitmap = (uint64_t) missingbitmap; + + /* Check the optional parameters and set defaults where appropriate. */ + if (!(optargs_bitmask & GUESTFS_MDADM_CREATE_MISSINGBITMAP_BITMASK)) + umissingbitmap = 0; + + if (optargs_bitmask & GUESTFS_MDADM_CREATE_SPARE_BITMASK) { + if (spare < 0) { + reply_with_error ("spare must not be negative"); + return -1; + } + } + else + spare = 0; + + if (optargs_bitmask & GUESTFS_MDADM_CREATE_NRDEVICES_BITMASK) { + if (nrdevices < 2) { + reply_with_error ("nrdevices is less than 2"); + return -1; + } + } + else + nrdevices = count_strings (devices) + count_bits (umissingbitmap); + + if (optargs_bitmask & GUESTFS_MDADM_CREATE_LEVEL_BITMASK) { + if (STRNEQ (level, "linear") && STRNEQ (level, "raid0") && + STRNEQ (level, "0") && STRNEQ (level, "stripe") && + STRNEQ (level, "raid1") && STRNEQ (level, "1") && + STRNEQ (level, "mirror") && + STRNEQ (level, "raid4") && STRNEQ (level, "4") && + STRNEQ (level, "raid5") && STRNEQ (level, "5") && + STRNEQ (level, "raid6") && STRNEQ (level, "6") && + STRNEQ (level, "raid10") && STRNEQ (level, "10")) { + reply_with_error ("unknown level parameter: %s", level); + return -1; + } + } + else + level = "raid1"; + + if (optargs_bitmask & GUESTFS_MDADM_CREATE_CHUNK_BITMASK) { + /* chunk is bytes in the libguestfs API, but K when we pass it to mdadm */ + if ((chunk & 1023) != 0) { + reply_with_error ("chunk size must be a multiple of 1024 bytes"); + return -1; + } + } + + /* Check invariant. */ + if (count_strings (devices) + count_bits (umissingbitmap) != + (size_t) (nrdevices + spare)) { + reply_with_error ("devices (%zu) + bits set in missingbitmap (%zu) is not equal to nrdevices (%d) + spare (%d)", + count_strings (devices), count_bits (umissingbitmap), + nrdevices, spare); + return -1; + } + + size_t MAX_ARGS = nrdevices + 16; + const char *argv[MAX_ARGS]; + size_t i = 0; + + ADD_ARG (argv, i, "mdadm"); + ADD_ARG (argv, i, "--create"); + /* --run suppresses "Continue creating array" question */ + ADD_ARG (argv, i, "--run"); + ADD_ARG (argv, i, name); + ADD_ARG (argv, i, "--level"); + ADD_ARG (argv, i, level); + ADD_ARG (argv, i, "--raid-devices"); + snprintf (nrdevices_s, sizeof nrdevices_s, "%d", nrdevices); + ADD_ARG (argv, i, nrdevices_s); + if (optargs_bitmask & GUESTFS_MDADM_CREATE_SPARE_BITMASK) { + ADD_ARG (argv, i, "--spare-devices"); + snprintf (spare_s, sizeof spare_s, "%d", spare); + ADD_ARG (argv, i, spare_s); + } + if (optargs_bitmask & GUESTFS_MDADM_CREATE_CHUNK_BITMASK) { + ADD_ARG (argv, i, "--chunk"); + snprintf (chunk_s, sizeof chunk_s, "%" PRIi64, chunk / 1024); + ADD_ARG (argv, i, chunk_s); + } + + /* Add devices and "missing". */ + j = 0; + while (devices[j] != NULL || umissingbitmap != 0) { + if (umissingbitmap & 1) + ADD_ARG (argv, i, "missing"); + else { + ADD_ARG (argv, i, devices[j]); + j++; + } + umissingbitmap >>= 1; + } + + ADD_ARG (argv, i, NULL); + + r = commandv (NULL, &err, argv); + if (r == -1) { + reply_with_error ("mdadm: %s: %s", name, err); + free (err); + return -1; + } + + free (err); + + udev_settle (); + + return 0; +} diff --git a/generator/generator_actions.ml b/generator/generator_actions.ml index fe40fbf..dff8480 100644 --- a/generator/generator_actions.ml +++ b/generator/generator_actions.ml @@ -6432,6 +6432,64 @@ To get the current values of filesystem parameters, see C. For precise details of how tune2fs works, see the L man page."); + ("mdadm_create", (RErr, [String "name"; DeviceList "devices"], [Int64 "missingbitmap"; Int "nrdevices"; Int "spare"; Int64 "chunk"; String "level"]), 299, [Optional "mdadm"], + [], + "create a Linux md (RAID) device", + "\ +Create a Linux md (RAID) device named C on the devices +in the list C. + +The optional parameters are: + +=over 4 + +=item C + +A bitmap of missing devices. If a bit is set it means that a +missing device is added to the array. The least significant bit +corresponds to the first device in the array. + +As examples: + +If C and C then +the resulting array would be C<[EmissingE, \"/dev/sda\"]>. + +If C and C then +the resulting array would be C<[\"/dev/sda\", EmissingE]>. + +This defaults to C<0> (no missing devices). + +The length of C + the number of bits set in +C must equal C + C. + +=item C + +The number of active RAID devices. + +If not set, this defaults to the length of C plus +the number of bits set in C. + +=item C + +The number of spare devices. + +If not set, this defaults to C<0>. + +=item C + +The chunk size in bytes. + +=item C + +The RAID level, which can be one of: +I, I, I<0>, I, I, I<1>, I, +I, I<4>, I, I<5>, I, I<6>, I, I<10>. +Some of these are synonymous, and more levels may be added in future. + +If not set, this defaults to C. + +=back"); + ] let all_functions = non_daemon_functions @ daemon_functions diff --git a/po/POTFILES.in b/po/POTFILES.in index 0ed9e45..fcc612d 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -48,6 +48,7 @@ daemon/ls.c daemon/luks.c daemon/lvm-filter.c daemon/lvm.c +daemon/md.c daemon/mkfs.c daemon/mknod.c daemon/modprobe.c diff --git a/regressions/Makefile.am b/regressions/Makefile.am index 0af7e8c..5263905 100644 --- a/regressions/Makefile.am +++ b/regressions/Makefile.am @@ -49,6 +49,7 @@ TESTS = \ test-luks-list.sh \ test-lvm-filtering.sh \ test-lvm-mapping.pl \ + test-mdadm.sh \ test-noexec-stack.pl \ test-qemudie-killsub.sh \ test-qemudie-midcommand.sh \ diff --git a/regressions/test-mdadm.sh b/regressions/test-mdadm.sh new file mode 100755 index 0000000..3ad4f22 --- /dev/null +++ b/regressions/test-mdadm.sh @@ -0,0 +1,95 @@ +#!/bin/bash - +# libguestfs +# Copyright (C) 2011 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 guestfish mdadm-create command. + +set -e + +rm -f md-test1.img md-test2.img md-test3.img md-test4.img + +../fish/guestfish <