summaryrefslogtreecommitdiffstats
path: root/Manage.c
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2012-08-13 08:00:21 +1000
committerNeilBrown <neilb@suse.de>2012-08-13 08:00:21 +1000
commitd070235d3f866ca270c5bdc799165b7ddb1f3bb1 (patch)
tree5cd5cd0d62866e46ef3ebaba09a48c5a9003ad46 /Manage.c
parent38aeaf3af6828fbefb19b6da1c12479578915391 (diff)
downloadmdadm-d070235d3f866ca270c5bdc799165b7ddb1f3bb1.tar.gz
Manage_subdevs: factor out Manage_delete
Now Manage_subdevs is now small enough to be manageable. Signed-off-by: NeilBrown <neilb@suse.de>
Diffstat (limited to 'Manage.c')
-rw-r--r--Manage.c220
1 files changed, 115 insertions, 105 deletions
diff --git a/Manage.c b/Manage.c
index c1123bd8..d5fc9740 100644
--- a/Manage.c
+++ b/Manage.c
@@ -840,6 +840,111 @@ int Manage_add(int fd, int tfd, struct mddev_dev *dv,
return 1;
}
+int Manage_remove(struct supertype *tst, int fd, struct mddev_dev *dv,
+ int sysfd, unsigned long rdev, int verbose, char *devname)
+{
+ int lfd = -1;
+ int err;
+
+ if (tst->ss->external) {
+ /* To remove a device from a container, we must
+ * check that it isn't in use in an array.
+ * This involves looking in the 'holders'
+ * directory - there must be just one entry,
+ * the container.
+ * To ensure that it doesn't get used as a
+ * hot spare while we are checking, we
+ * get an O_EXCL open on the container
+ */
+ int dnum = fd2devnum(fd);
+ lfd = open_dev_excl(dnum);
+ if (lfd < 0) {
+ pr_err("Cannot get exclusive access "
+ " to container - odd\n");
+ return -1;
+ }
+ /* In the detached case it is not possible to
+ * check if we are the unique holder, so just
+ * rely on the 'detached' checks
+ */
+ if (strcmp(dv->devname, "detached") == 0 ||
+ sysfd >= 0 ||
+ sysfs_unique_holder(dnum, rdev))
+ /* pass */;
+ else {
+ pr_err("%s is %s, cannot remove.\n",
+ dv->devname,
+ errno == EEXIST ? "still in use":
+ "not a member");
+ close(lfd);
+ return -1;
+ }
+ }
+ /* FIXME check that it is a current member */
+ 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;
+ else
+ err = 0;
+ } else {
+ err = ioctl(fd, HOT_REMOVE_DISK, rdev);
+ if (err && errno == ENODEV) {
+ /* Old kernels rejected this if no personality
+ * is 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 == (int)major(rdev) &&
+ dv->disk.minor == (int)minor(rdev))
+ break;
+ if (dv)
+ err = sysfs_set_str(sra, dv,
+ "state", "remove");
+ else
+ err = -1;
+ if (sra)
+ sysfs_free(sra);
+ }
+ }
+ if (err) {
+ pr_err("hot remove failed "
+ "for %s: %s\n", dv->devname,
+ strerror(errno));
+ if (lfd >= 0)
+ close(lfd);
+ return -1;
+ }
+ if (tst->ss->external) {
+ /*
+ * Before dropping our exclusive open we make an
+ * attempt at preventing mdmon from seeing an
+ * 'add' event before reconciling this 'remove'
+ * event.
+ */
+ char *name = devnum2devname(fd2devnum(fd));
+
+ if (!name) {
+ pr_err("unable to get container name\n");
+ return -1;
+ }
+
+ ping_manager(name);
+ free(name);
+ }
+ if (lfd >= 0)
+ close(lfd);
+ if (verbose >= 0)
+ pr_err("hot removed %s from %s\n",
+ dv->devname, devname);
+ return 1;
+}
+
int Manage_subdevs(char *devname, int fd,
struct mddev_dev *devlist, int verbose, int test,
char *update, int force)
@@ -866,7 +971,6 @@ int Manage_subdevs(char *devname, int fd,
int tfd = -1;
struct supertype *tst;
char *subarray = NULL;
- int lfd = -1;
int sysfd = -1;
int count = 0; /* number of actions taken */
struct mdinfo info;
@@ -896,7 +1000,6 @@ int Manage_subdevs(char *devname, int fd,
stb.st_rdev = 0;
for (dv = devlist; dv; dv = dv->next) {
- int err;
int rv;
if (strcmp(dv->devname, "failed") == 0 ||
@@ -1064,111 +1167,18 @@ int Manage_subdevs(char *devname, int fd,
pr_err("Cannot remove disks from a"
" \'member\' array, perform this"
" operation on the parent container\n");
- if (sysfd >= 0)
- close(sysfd);
- goto abort;
- }
- if (tst->ss->external) {
- /* To remove a device from a container, we must
- * check that it isn't in use in an array.
- * This involves looking in the 'holders'
- * directory - there must be just one entry,
- * the container.
- * To ensure that it doesn't get used as a
- * hot spare while we are checking, we
- * get an O_EXCL open on the container
- */
- int dnum = fd2devnum(fd);
- lfd = open_dev_excl(dnum);
- if (lfd < 0) {
- pr_err("Cannot get exclusive access "
- " to container - odd\n");
- if (sysfd >= 0)
- close(sysfd);
- goto abort;
- }
- /* In the detached case it is not possible to
- * check if we are the unique holder, so just
- * rely on the 'detached' checks
- */
- if (strcmp(dv->devname, "detached") == 0 ||
- sysfd >= 0 ||
- sysfs_unique_holder(dnum, stb.st_rdev))
- /* pass */;
- else {
- pr_err("%s is %s, cannot remove.\n",
- dv->devname,
- errno == EEXIST ? "still in use":
- "not a member");
- close(lfd);
- goto abort;
- }
- }
- /* FIXME check that it is a current member */
- 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;
- else
- err = 0;
+ rv = -1;
+ } else
+ rv = Manage_remove(tst, fd, dv, sysfd,
+ stb.st_rdev, verbose,
+ devname);
+ if (sysfd >= 0)
close(sysfd);
- sysfd = -1;
- } else {
- err = ioctl(fd, HOT_REMOVE_DISK, (unsigned long)stb.st_rdev);
- if (err && errno == ENODEV) {
- /* Old kernels rejected this if no personality
- * is 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 == (int)major(stb.st_rdev) &&
- dv->disk.minor == (int)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) {
- pr_err("hot remove failed "
- "for %s: %s\n", dv->devname,
- strerror(errno));
- if (lfd >= 0)
- close(lfd);
+ sysfd = -1;
+ if (rv < 0)
goto abort;
- }
- if (tst->ss->external) {
- /*
- * Before dropping our exclusive open we make an
- * attempt at preventing mdmon from seeing an
- * 'add' event before reconciling this 'remove'
- * event.
- */
- char *name = devnum2devname(fd2devnum(fd));
-
- if (!name) {
- pr_err("unable to get container name\n");
- goto abort;
- }
-
- ping_manager(name);
- free(name);
- }
- if (lfd >= 0)
- close(lfd);
- count++;
- if (verbose >= 0)
- pr_err("hot removed %s from %s\n",
- dv->devname, devname);
+ if (rv > 0)
+ count++;
break;
case 'f': /* set faulty */