summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2010-04-09 08:47:32 +1000
committerNeilBrown <neilb@suse.de>2010-04-09 09:19:18 +1000
commit7a5090d2247936d7cf7d9067c960317ad009940d (patch)
treed53cb6942fd0959d501b80465897b15d3a503d17
parentc81c0cab6ea8ee5fd0eccefba9e64a77ad18df30 (diff)
downloadmdadm-7a5090d2247936d7cf7d9067c960317ad009940d.tar.gz
mdadm-7a5090d2247936d7cf7d9067c960317ad009940d.tar.xz
mdadm-7a5090d2247936d7cf7d9067c960317ad009940d.zip
Support fail/remove using kernel name
Allow kernel names like "sda" and "hdb1" to be used to fail/remove devices from an array. This is useful as after a device has been removed it can be difficult to get the major/minor number. Signed-off-by: NeilBrown <neilb@suse.de>
-rw-r--r--Manage.c101
1 files changed, 81 insertions, 20 deletions
diff --git a/Manage.c b/Manage.c
index f848d8b..ad85705 100644
--- a/Manage.c
+++ b/Manage.c
@@ -341,6 +341,8 @@ int Manage_subdevs(char *devname, int fd,
* 'f' - set the device faulty SET_DISK_FAULTY
* device can be 'detached' in which case any device that
* is inaccessible will be marked faulty.
+ * For 'f' and 'r', the device can also be a kernel-internal
+ * name such as 'sdb'.
*/
mdu_array_info_t array;
mdu_disk_info_t disc;
@@ -353,6 +355,7 @@ int Manage_subdevs(char *devname, int fd,
int duuid[4];
int ouuid[4];
int lfd = -1;
+ int sysfd = -1;
if (ioctl(fd, GET_ARRAY_INFO, &array)) {
fprintf(stderr, Name ": cannot get array info for %s\n",
@@ -442,6 +445,40 @@ int Manage_subdevs(char *devname, int fd,
}
if (jnext == 0)
continue;
+ } else if (strchr(dv->devname, '/') == NULL &&
+ strlen(dv->devname) < 50) {
+ /* Assume this is a kernel-internal name like 'sda1' */
+ int found = 0;
+ char dname[55];
+ if (dv->disposition != 'r' && dv->disposition != 'f') {
+ fprintf(stderr, Name ": %s only meaningful "
+ "with -r of -f, not -%c\n",
+ dv->devname, dv->disposition);
+ return 1;
+ }
+
+ sprintf(dname, "dev-%s", dv->devname);
+ sysfd = sysfs_open(fd2devnum(fd), dname, "block/dev");
+ if (sysfd >= 0) {
+ char dn[20];
+ int mj,mn;
+ if (sysfs_fd_get_str(sysfd, dn, 20) > 0 &&
+ sscanf(dn, "%d:%d", &mj,&mn) == 2) {
+ stb.st_rdev = makedev(mj,mn);
+ found = 1;
+ }
+ close(sysfd);
+ sysfd = -1;
+ }
+ if (!found) {
+ sysfd = sysfs_open(fd2devnum(fd), dname, "state");
+ if (sysfd < 0) {
+ fprintf(stderr, Name ": %s does not appear "
+ "to be a component of %s\n",
+ dv->devname, devname);
+ return 1;
+ }
+ }
} else {
j = 0;
@@ -753,6 +790,8 @@ int Manage_subdevs(char *devname, int fd,
fprintf(stderr, Name ": Cannot remove disks from a"
" \'member\' array, perform this"
" operation on the parent container\n");
+ if (sysfd >= 0)
+ close(sysfd);
return 1;
}
if (tst->ss->external) {
@@ -771,6 +810,8 @@ int Manage_subdevs(char *devname, int fd,
fprintf(stderr, Name
": Cannot get exclusive access "
" to container - odd\n");
+ if (sysfd >= 0)
+ close(sysfd);
return 1;
}
/* in the detached case it is not possible to
@@ -778,6 +819,7 @@ int Manage_subdevs(char *devname, int fd,
* rely on the 'detached' checks
*/
if (strcmp(dv->devname, "detached") == 0 ||
+ sysfd >= 0 ||
sysfs_unique_holder(dnum, stb.st_rdev))
/* pass */;
else {
@@ -791,25 +833,37 @@ int Manage_subdevs(char *devname, int fd,
}
}
/* FIXME check that it is a current member */
- err = ioctl(fd, HOT_REMOVE_DISK, (unsigned long)stb.st_rdev);
- if (err && errno == ENODEV) {
- /* Old kernels rejected this if no personality
- * registered */
- struct mdinfo *sra = sysfs_read(fd, 0, GET_DEVS);
- struct mdinfo *dv = NULL;
- if (sra)
- dv = sra->devs;
- for ( ; dv ; dv=dv->next)
- if (dv->disk.major == major(stb.st_rdev) &&
- dv->disk.minor == minor(stb.st_rdev))
- break;
- if (dv)
- err = sysfs_set_str(sra, dv,
- "state", "remove");
- else
+ if (sysfd >= 0) {
+ /* device has been removed and we don't know
+ * the major:minor number
+ */
+ int n = write(sysfd, "remove", 6);
+ if (n != 6)
err = -1;
- if (sra)
- sysfs_free(sra);
+ else
+ err = 0;
+ close(sysfd);
+ } else {
+ err = ioctl(fd, HOT_REMOVE_DISK, (unsigned long)stb.st_rdev);
+ if (err && errno == ENODEV) {
+ /* Old kernels rejected this if no personality
+ * registered */
+ struct mdinfo *sra = sysfs_read(fd, 0, GET_DEVS);
+ struct mdinfo *dv = NULL;
+ if (sra)
+ dv = sra->devs;
+ for ( ; dv ; dv=dv->next)
+ if (dv->disk.major == major(stb.st_rdev) &&
+ dv->disk.minor == minor(stb.st_rdev))
+ break;
+ if (dv)
+ err = sysfs_set_str(sra, dv,
+ "state", "remove");
+ else
+ err = -1;
+ if (sra)
+ sysfs_free(sra);
+ }
}
if (err) {
fprintf(stderr, Name ": hot remove failed "
@@ -836,7 +890,8 @@ int Manage_subdevs(char *devname, int fd,
ping_manager(name);
free(name);
}
- close(lfd);
+ if (lfd >= 0)
+ close(lfd);
if (verbose >= 0)
fprintf(stderr, Name ": hot removed %s\n",
dnprintable);
@@ -844,11 +899,17 @@ int Manage_subdevs(char *devname, int fd,
case 'f': /* set faulty */
/* FIXME check current member */
- if (ioctl(fd, SET_DISK_FAULTY, (unsigned long) stb.st_rdev)) {
+ if ((sysfd >= 0 && write(sysfd, "faulty", 6) != 6) ||
+ (sysfd < 0 && ioctl(fd, SET_DISK_FAULTY,
+ (unsigned long) stb.st_rdev))) {
fprintf(stderr, Name ": set device faulty failed for %s: %s\n",
dnprintable, strerror(errno));
+ if (sysfd >= 0)
+ close(sysfd);
return 1;
}
+ if (sysfd >= 0)
+ close(sysfd);
if (verbose >= 0)
fprintf(stderr, Name ": set %s faulty in %s\n",
dnprintable, devname);