diff options
-rw-r--r-- | Manage.c | 53 | ||||
-rw-r--r-- | ReadMe.c | 1 | ||||
-rw-r--r-- | mdadm.8 | 30 | ||||
-rw-r--r-- | mdadm.c | 41 | ||||
-rw-r--r-- | mdadm.h | 7 | ||||
-rw-r--r-- | super-intel.c | 117 |
6 files changed, 235 insertions, 14 deletions
@@ -869,4 +869,57 @@ int autodetect(void) } 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 @@ -109,6 +109,7 @@ struct option long_options[] = { {"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'}, @@ -1183,6 +1183,14 @@ 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 .BR \-\-detail , @@ -1761,6 +1769,28 @@ 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. .I mdadm @@ -218,8 +218,14 @@ int main(int argc, char *argv[]) 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; + } 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(MISC,'N'): 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); @@ -624,11 +635,16 @@ int main(int argc, char *argv[]) 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 (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; @@ -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, UpdateSubarray): 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; @@ -1411,6 +1437,15 @@ int main(int argc, char *argv[]) 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) { @@ -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'. + * (note we must stop before we get to 65 i.e. 'A') */ enum special_options { AssumeClean = 2, @@ -266,7 +267,7 @@ enum special_options { ReAdd, NoDegraded, Sparc22, - BackupFile, + BackupFile, /* 8 */ HomeHost, AutoHomeHost, Symlinks, @@ -274,6 +275,7 @@ enum special_options { Waitclean, DetailPlatform, KillSubarray, + UpdateSubarray, /* 16 */ }; /* 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 */ + /* 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, @@ -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 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); diff --git a/super-intel.c b/super-intel.c index d81d620..f0377b8 100644 --- a/super-intel.c +++ b/super-intel.c @@ -283,6 +283,7 @@ enum imsm_update_type { update_activate_spare, update_create_array, update_kill_array, + update_rename_array, update_add_disk, }; @@ -309,6 +310,12 @@ struct imsm_update_kill_array { 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; }; @@ -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) @@ -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; - 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) { @@ -4107,6 +4130,54 @@ static int kill_subarray_imsm(struct supertype *st) 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) @@ -5217,6 +5288,31 @@ static void imsm_process_update(struct supertype *st, 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 @@ -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, + .update_subarray = update_subarray_imsm, #endif .match_home = match_home_imsm, .uuid_from_super= uuid_from_super_imsm, |