]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
Rename subarray v2
authorDan Williams <dan.j.williams@intel.com>
Tue, 22 Jun 2010 23:30:59 +0000 (16:30 -0700)
committerDan Williams <dan.j.williams@intel.com>
Tue, 22 Jun 2010 23:30:59 +0000 (16:30 -0700)
Allow the name of the array stored in the metadata to be updated.  In
some cases the metadata format may not be able to support this rename
without modifying the UUID.  In these cases the request will be blocked.
Otherwise we allow the rename to take place, even for active arrays.
This assumes that the user understands the difference between the kernel
node name, the device node symlink name, and the metadata specific name.

Anticipating further need to modify subarrays in-place, introduce the
->update_subarray() superswitch method.  A future potential use
case is setting storage pool (spare-group) identifiers.

Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Manage.c
ReadMe.c
mdadm.8
mdadm.c
mdadm.h
super-intel.c

index f6fb3ef1875e7d3e29942ad2d1da08b3982f7a3e..cca15031d8eb35d163e5176f6b8122a5e164f15b 100644 (file)
--- a/Manage.c
+++ b/Manage.c
@@ -869,4 +869,57 @@ int autodetect(void)
        }
        return rv;
 }
        }
        return rv;
 }
+
+int Update_subarray(char *dev, char *subarray, char *update, mddev_ident_t ident, int quiet)
+{
+       struct supertype supertype, *st = &supertype;
+       int fd, rv = 2;
+
+       memset(st, 0, sizeof(*st));
+       if (snprintf(st->subarray, sizeof(st->subarray), "%s", subarray) >=
+           sizeof(st->subarray)) {
+               if (!quiet)
+                       fprintf(stderr,
+                               Name ": Input overflow for subarray '%s' > %zu bytes\n",
+                               subarray, sizeof(st->subarray) - 1);
+               return 2;
+       }
+
+       fd = open_subarray(dev, st, quiet);
+       if (fd < 0)
+               return 2;
+
+       if (!st->ss->update_subarray) {
+               if (!quiet)
+                       fprintf(stderr,
+                               Name ": Operation not supported for %s metadata\n",
+                               st->ss->name);
+               goto free_super;
+       }
+
+       if (mdmon_running(st->devnum))
+               st->update_tail = &st->updates;
+
+       rv = st->ss->update_subarray(st, update, ident);
+
+       if (rv) {
+               if (!quiet)
+                       fprintf(stderr, Name ": Failed to update %s of subarray-%s in %s\n",
+                               update, subarray, dev);
+       } else if (st->update_tail)
+               flush_metadata_updates(st);
+       else
+               st->ss->sync_metadata(st);
+
+       if (rv == 0 && strcmp(update, "name") == 0 && !quiet)
+               fprintf(stderr,
+                       Name ": Updated subarray-%s name from %s, UUIDs may have changed\n",
+                       subarray, dev);
+
+ free_super:
+       st->ss->free_super(st);
+       close(fd);
+
+       return rv;
+}
 #endif
 #endif
index 387ba6d13f7540f43212ccf62cb4a36021d0819d..fa333109055372174d67227c3baa70cb88751f74 100644 (file)
--- a/ReadMe.c
+++ b/ReadMe.c
@@ -109,6 +109,7 @@ struct option long_options[] = {
     {"auto-detect", 0, 0, AutoDetect},
     {"detail-platform", 0, 0, DetailPlatform},
     {"kill-subarray", 1, 0, KillSubarray},
     {"auto-detect", 0, 0, AutoDetect},
     {"detail-platform", 0, 0, DetailPlatform},
     {"kill-subarray", 1, 0, KillSubarray},
+    {"update-subarray", 1, 0, UpdateSubarray},
 
     /* synonyms */
     {"monitor",   0, 0, 'F'},
 
     /* synonyms */
     {"monitor",   0, 0, 'F'},
diff --git a/mdadm.8 b/mdadm.8
index 784ba311252ede2f2226f27f415a544853da8fda..19098199a45f88befcefcd87bd23efdf8f388e76 100644 (file)
--- a/mdadm.8
+++ b/mdadm.8
@@ -1182,6 +1182,14 @@ removing a superblock.  Note that some formats depend on the subarray
 index for generating a UUID, this command will fail if it would change
 the UUID of an active subarray.
 
 index for generating a UUID, this command will fail if it would change
 the UUID of an active subarray.
 
+.TP
+.B \-\-update\-subarray=
+If the device is a container and the argument to \-\-update\-subarray
+specifies a subarray in the container, then attempt to update the given
+superblock field in the subarray. See below in
+.B MISC MODE
+for details.
+
 .TP
 .BR \-t ", " \-\-test
 When used with
 .TP
 .BR \-t ", " \-\-test
 When used with
@@ -1760,6 +1768,28 @@ metadata is platform independent
 metadata failed to find its platform components on this system
 .RE
 
 metadata failed to find its platform components on this system
 .RE
 
+.TP
+.B \-\-update\-subarray=
+If the device is a container and the argument to \-\-update\-subarray
+specifies a subarray in the container, then attempt to update the given
+superblock field in the subarray.  Similar to updating an array in
+"assemble" mode, the field to update is selected by
+.B \-U
+or
+.B \-\-update=
+option.  Currently only
+.B name
+is supported.
+
+The 
+.B name
+option updates the subarray name in the metadata, it may not affect the
+device node name or the device node symlink until the subarray is
+re\-assembled.  If updating 
+.B name
+would change the UUID of an active subarray this operation is blocked,
+and the command will end in an error.
+
 .TP
 .B \-\-examine
 The device should be a component of an md array.
 .TP
 .B \-\-examine
 The device should be a component of an md array.
diff --git a/mdadm.c b/mdadm.c
index 446fab824e9728b861938728b3fdacfef816f173..e7435fd9e6e98b8cdbbec5cec0867f5573eb0363 100644 (file)
--- a/mdadm.c
+++ b/mdadm.c
@@ -218,8 +218,14 @@ int main(int argc, char *argv[])
                case Waitclean:
                case DetailPlatform:
                case KillSubarray:
                case Waitclean:
                case DetailPlatform:
                case KillSubarray:
-                       if (opt == KillSubarray)
+               case UpdateSubarray:
+                       if (opt == KillSubarray || opt == UpdateSubarray) {
+                               if (subarray) {
+                                       fprintf(stderr, Name ": subarray can only be specified once\n");
+                                       exit(2);
+                               }
                                subarray = optarg;
                                subarray = optarg;
+                       }
                case 'K': if (!mode) newmode = MISC; break;
                }
                if (mode && newmode == mode) {
                case 'K': if (!mode) newmode = MISC; break;
                }
                if (mode && newmode == mode) {
@@ -593,11 +599,16 @@ int main(int argc, char *argv[])
 
                case O(CREATE,'N'):
                case O(ASSEMBLE,'N'):
 
                case O(CREATE,'N'):
                case O(ASSEMBLE,'N'):
+               case O(MISC,'N'):
                        if (ident.name[0]) {
                                fprintf(stderr, Name ": name cannot be set twice.   "
                                        "Second value %s.\n", optarg);
                                exit(2);
                        }
                        if (ident.name[0]) {
                                fprintf(stderr, Name ": name cannot be set twice.   "
                                        "Second value %s.\n", optarg);
                                exit(2);
                        }
+                       if (mode == MISC && !subarray) {
+                               fprintf(stderr, Name ": -N/--name only valid with --update-subarray in misc mode\n");
+                               exit(2);
+                       }
                        if (strlen(optarg) > 32) {
                                fprintf(stderr, Name ": name '%s' is too long, 32 chars max.\n",
                                        optarg);
                        if (strlen(optarg) > 32) {
                                fprintf(stderr, Name ": name '%s' is too long, 32 chars max.\n",
                                        optarg);
@@ -624,11 +635,16 @@ int main(int argc, char *argv[])
                        continue;
 
                case O(ASSEMBLE,'U'): /* update the superblock */
                        continue;
 
                case O(ASSEMBLE,'U'): /* update the superblock */
+               case O(MISC,'U'):
                        if (update) {
                                fprintf(stderr, Name ": Can only update one aspect of superblock, both %s and %s given.\n",
                                        update, optarg);
                                exit(2);
                        }
                        if (update) {
                                fprintf(stderr, Name ": Can only update one aspect of superblock, both %s and %s given.\n",
                                        update, optarg);
                                exit(2);
                        }
+                       if (mode == MISC && !subarray) {
+                               fprintf(stderr, Name ": Only subarrays can be updated in misc mode\n");
+                               exit(2);
+                       }
                        update = optarg;
                        if (strcmp(update, "sparc2.2")==0)
                                continue;
                        update = optarg;
                        if (strcmp(update, "sparc2.2")==0)
                                continue;
@@ -812,10 +828,20 @@ int main(int argc, char *argv[])
                case O(MISC, Waitclean):
                case O(MISC, DetailPlatform):
                case O(MISC, KillSubarray):
                case O(MISC, Waitclean):
                case O(MISC, DetailPlatform):
                case O(MISC, KillSubarray):
+               case O(MISC, UpdateSubarray):
                        if (devmode && devmode != opt &&
                            (devmode == 'E' || (opt == 'E' && devmode != 'Q'))) {
                        if (devmode && devmode != opt &&
                            (devmode == 'E' || (opt == 'E' && devmode != 'Q'))) {
-                               fprintf(stderr, Name ": --examine/-E cannot be given with -%c\n",
-                                       devmode =='E'?opt:devmode);
+                               fprintf(stderr, Name ": --examine/-E cannot be given with ");
+                               if (devmode == 'E') {
+                                       if (option_index >= 0)
+                                               fprintf(stderr, "--%s\n",
+                                                       long_options[option_index].name);
+                                       else
+                                               fprintf(stderr, "-%c\n", opt);
+                               } else if (isalpha(devmode))
+                                       fprintf(stderr, "-%c\n", devmode);
+                               else
+                                       fprintf(stderr, "previous option\n");
                                exit(2);
                        }
                        devmode = opt;
                                exit(2);
                        }
                        devmode = opt;
@@ -1411,6 +1437,15 @@ int main(int argc, char *argv[])
                                case KillSubarray:
                                        rv |= Kill_subarray(dv->devname, subarray, quiet);
                                        continue;
                                case KillSubarray:
                                        rv |= Kill_subarray(dv->devname, subarray, quiet);
                                        continue;
+                               case UpdateSubarray:
+                                       if (update == NULL) {
+                                               fprintf(stderr,
+                                                       Name ": -U/--update must be specified with --update-subarray\n");
+                                               rv |= 1;
+                                               continue;
+                                       }
+                                       rv |= Update_subarray(dv->devname, subarray, update, &ident, quiet);
+                                       continue;
                                }
                                mdfd = open_mddev(dv->devname, 1);
                                if (mdfd>=0) {
                                }
                                mdfd = open_mddev(dv->devname, 1);
                                if (mdfd>=0) {
diff --git a/mdadm.h b/mdadm.h
index f3874779778ce6ddb6ad26b8a0728bdef74fc935..68d61a3aaa6c89af898d1b75350df4b70ddd433b 100644 (file)
--- a/mdadm.h
+++ b/mdadm.h
@@ -258,6 +258,7 @@ extern char Version[], Usage[], Help[], OptionHelp[],
 
 /* for option that don't have short equivilents, we assign arbitrary
  * small numbers.  '1' means an undecorated option, so we start at '2'.
 
 /* for option that don't have short equivilents, we assign arbitrary
  * small numbers.  '1' means an undecorated option, so we start at '2'.
+ * (note we must stop before we get to 65 i.e. 'A')
  */
 enum special_options {
        AssumeClean = 2,
  */
 enum special_options {
        AssumeClean = 2,
@@ -266,7 +267,7 @@ enum special_options {
        ReAdd,
        NoDegraded,
        Sparc22,
        ReAdd,
        NoDegraded,
        Sparc22,
-       BackupFile,
+       BackupFile, /* 8 */
        HomeHost,
        AutoHomeHost,
        Symlinks,
        HomeHost,
        AutoHomeHost,
        Symlinks,
@@ -274,6 +275,7 @@ enum special_options {
        Waitclean,
        DetailPlatform,
        KillSubarray,
        Waitclean,
        DetailPlatform,
        KillSubarray,
+       UpdateSubarray, /* 16 */
 };
 
 /* structures read from config file */
 };
 
 /* structures read from config file */
@@ -612,6 +614,8 @@ extern struct superswitch {
        int (*default_layout)(int level); /* optional */
        /* Permit subarray's to be deleted from inactive containers */
        int (*kill_subarray)(struct supertype *st); /* optional */
        int (*default_layout)(int level); /* optional */
        /* Permit subarray's to be deleted from inactive containers */
        int (*kill_subarray)(struct supertype *st); /* optional */
+       /* Permit subarray's to be modified */
+       int (*update_subarray)(struct supertype *st, char *update, mddev_ident_t ident); /* optional */
 
 /* for mdmon */
        int (*open_new)(struct supertype *c, struct active_array *a,
 
 /* for mdmon */
        int (*open_new)(struct supertype *c, struct active_array *a,
@@ -809,6 +813,7 @@ extern int Monitor(mddev_dev_t devlist,
 
 extern int Kill(char *dev, struct supertype *st, int force, int quiet, int noexcl);
 extern int Kill_subarray(char *dev, char *subarray, int quiet);
 
 extern int Kill(char *dev, struct supertype *st, int force, int quiet, int noexcl);
 extern int Kill_subarray(char *dev, char *subarray, int quiet);
+extern int Update_subarray(char *dev, char *subarray, char *update, mddev_ident_t ident, int quiet);
 extern int Wait(char *dev);
 extern int WaitClean(char *dev, int sock, int verbose);
 
 extern int Wait(char *dev);
 extern int WaitClean(char *dev, int sock, int verbose);
 
index d81d620dcecfd3e02796e39dd234a821e4216bb6..f0377b814c946d9b52ec41a033c87e5c91975d4d 100644 (file)
@@ -283,6 +283,7 @@ enum imsm_update_type {
        update_activate_spare,
        update_create_array,
        update_kill_array,
        update_activate_spare,
        update_create_array,
        update_kill_array,
+       update_rename_array,
        update_add_disk,
 };
 
        update_add_disk,
 };
 
@@ -309,6 +310,12 @@ struct imsm_update_kill_array {
        int dev_idx;
 };
 
        int dev_idx;
 };
 
+struct imsm_update_rename_array {
+       enum imsm_update_type type;
+       __u8 name[MAX_RAID_SERIAL_LEN];
+       int dev_idx;
+};
+
 struct imsm_update_add_disk {
        enum imsm_update_type type;
 };
 struct imsm_update_add_disk {
        enum imsm_update_type type;
 };
@@ -2939,6 +2946,30 @@ static void imsm_update_version_info(struct intel_super *super)
        }
 }
 
        }
 }
 
+static int check_name(struct intel_super *super, char *name, int quiet)
+{
+       struct imsm_super *mpb = super->anchor;
+       char *reason = NULL;
+       int i;
+
+       if (strlen(name) > MAX_RAID_SERIAL_LEN)
+               reason = "must be 16 characters or less";
+
+       for (i = 0; i < mpb->num_raid_devs; i++) {
+               struct imsm_dev *dev = get_imsm_dev(super, i);
+
+               if (strncmp((char *) dev->volume, name, MAX_RAID_SERIAL_LEN) == 0) {
+                       reason = "already exists";
+                       break;
+               }
+       }
+
+       if (reason && !quiet)
+               fprintf(stderr, Name ": imsm volume name %s\n", reason);
+
+       return !reason;
+}
+
 static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
                                  unsigned long long size, char *name,
                                  char *homehost, int *uuid)
 static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
                                  unsigned long long size, char *name,
                                  char *homehost, int *uuid)
@@ -2990,16 +3021,8 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
        if (super->current_vol == 0)
                mpb->num_disks = 0;
 
        if (super->current_vol == 0)
                mpb->num_disks = 0;
 
-       for (i = 0; i < super->current_vol; i++) {
-               dev = get_imsm_dev(super, i);
-               if (strncmp((char *) dev->volume, name,
-                            MAX_RAID_SERIAL_LEN) == 0) {
-                       fprintf(stderr, Name": '%s' is already defined for this container\n",
-                               name);
-                       return 0;
-               }
-       }
-
+       if (!check_name(super, name, 0))
+               return 0;
        sprintf(st->subarray, "%d", idx);
        dv = malloc(sizeof(*dv));
        if (!dv) {
        sprintf(st->subarray, "%d", idx);
        dv = malloc(sizeof(*dv));
        if (!dv) {
@@ -4107,6 +4130,54 @@ static int kill_subarray_imsm(struct supertype *st)
 
        return 0;
 }
 
        return 0;
 }
+
+static int update_subarray_imsm(struct supertype *st, char *update, mddev_ident_t ident)
+{
+       /* update the subarray currently referenced by ->current_vol */
+       struct intel_super *super = st->sb;
+       struct imsm_super *mpb = super->anchor;
+
+       if (super->current_vol < 0)
+               return 2;
+
+       if (strcmp(update, "name") == 0) {
+               char *name = ident->name;
+
+               if (is_subarray_active(st->subarray, st->devname)) {
+                       fprintf(stderr,
+                               Name ": Unable to update name of active subarray\n");
+                       return 2;
+               }
+
+               if (!check_name(super, name, 0))
+                       return 2;
+
+               if (st->update_tail) {
+                       struct imsm_update_rename_array *u = malloc(sizeof(*u));
+
+                       if (!u)
+                               return 2;
+                       u->type = update_rename_array;
+                       u->dev_idx = super->current_vol;
+                       snprintf((char *) u->name, MAX_RAID_SERIAL_LEN, "%s", name);
+                       append_metadata_update(st, u, sizeof(*u));
+               } else {
+                       struct imsm_dev *dev;
+                       int i;
+
+                       dev = get_imsm_dev(super, super->current_vol);
+                       snprintf((char *) dev->volume, MAX_RAID_SERIAL_LEN, "%s", name);
+                       for (i = 0; i < mpb->num_raid_devs; i++) {
+                               dev = get_imsm_dev(super, i);
+                               handle_missing(super, dev);
+                       }
+                       super->updates_pending++;
+               }
+       } else
+               return 2;
+
+       return 0;
+}
 #endif /* MDASSEMBLE */
 
 static int is_rebuilding(struct imsm_dev *dev)
 #endif /* MDASSEMBLE */
 
 static int is_rebuilding(struct imsm_dev *dev)
@@ -5217,6 +5288,31 @@ static void imsm_process_update(struct supertype *st,
                super->updates_pending++;
                break;
        }
                super->updates_pending++;
                break;
        }
+       case update_rename_array: {
+               struct imsm_update_rename_array *u = (void *) update->buf;
+               char name[MAX_RAID_SERIAL_LEN+1];
+               int target = u->dev_idx;
+               struct active_array *a;
+               struct imsm_dev *dev;
+
+               /* sanity check that we are not affecting the uuid of
+                * an active array
+                */
+               snprintf(name, MAX_RAID_SERIAL_LEN, "%s", (char *) u->name);
+               name[MAX_RAID_SERIAL_LEN] = '\0';
+               for (a = st->arrays; a; a = a->next)
+                       if (a->info.container_member == target)
+                               break;
+               dev = get_imsm_dev(super, u->dev_idx);
+               if (a || !dev || !check_name(super, name, 1)) {
+                       dprintf("failed to rename subarray-%d\n", target);
+                       break;
+               }
+
+               snprintf((char *) dev->volume, MAX_RAID_SERIAL_LEN, name);
+               super->updates_pending++;
+               break;
+       }
        case update_add_disk:
 
                /* we may be able to repair some arrays if disks are
        case update_add_disk:
 
                /* we may be able to repair some arrays if disks are
@@ -5393,6 +5489,7 @@ struct superswitch super_imsm = {
        .add_to_super   = add_to_super_imsm,
        .detail_platform = detail_platform_imsm,
        .kill_subarray = kill_subarray_imsm,
        .add_to_super   = add_to_super_imsm,
        .detail_platform = detail_platform_imsm,
        .kill_subarray = kill_subarray_imsm,
+       .update_subarray = update_subarray_imsm,
 #endif
        .match_home     = match_home_imsm,
        .uuid_from_super= uuid_from_super_imsm,
 #endif
        .match_home     = match_home_imsm,
        .uuid_from_super= uuid_from_super_imsm,