summaryrefslogtreecommitdiffstats
path: root/sysfs.c
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2012-09-24 04:26:03 +0200
committerNeilBrown <neilb@suse.de>2012-09-24 04:26:03 +0200
commitaab15415eddbfa800031cb9f6273ca8fcf59efb7 (patch)
tree63ebdc4928cf9b175f59324be96bb559c5f9e514 /sysfs.c
parentfix: imsm: do not accept too small sizes (diff)
downloadmdadm-aab15415eddbfa800031cb9f6273ca8fcf59efb7.tar.xz
mdadm-aab15415eddbfa800031cb9f6273ca8fcf59efb7.zip
Manage: fix checks for removal from a container.
We must only remove from a container if the device isn't a member of any member array. To check we look at the 'holders' directory in sysfs. We currently skip that check if ->devname is "detached", however that can never be true since the change that introduced add_detached(). Also sysfs_unique_holder returns status in 'errno' which isn't entirely safe as e.g. closedir() is probably allowed to clear it. So make sysfs_unique_holder return an unambigious value, and us it to decide what to report. Signed-off-by: NeilBrown <neilb@suse.de>
Diffstat (limited to 'sysfs.c')
-rw-r--r--sysfs.c34
1 files changed, 16 insertions, 18 deletions
diff --git a/sysfs.c b/sysfs.c
index 0043d272..47294556 100644
--- a/sysfs.c
+++ b/sysfs.c
@@ -778,18 +778,22 @@ int sysfs_unique_holder(int devnum, long rdev)
* and is the only holder.
* we should be locked against races by
* an O_EXCL on devnum
+ * Return values:
+ * 0 - not unique, not even a holder
+ * 1 - unique, this is the only holder.
+ * 2/3 - not unique, there is another holder
+ * -1 - error, cannot find the holders
*/
DIR *dir;
struct dirent *de;
char dirname[100];
char l;
- int found = 0;
+ int ret = 0;
sprintf(dirname, "/sys/dev/block/%d:%d/holders",
major(rdev), minor(rdev));
dir = opendir(dirname);
- errno = ENOENT;
if (!dir)
- return 0;
+ return -1;
l = strlen(dirname);
while ((de = readdir(dir)) != NULL) {
char buf[10];
@@ -807,8 +811,8 @@ int sysfs_unique_holder(int devnum, long rdev)
strcat(dirname+l, "/dev");
fd = open(dirname, O_RDONLY);
if (fd < 0) {
- errno = ENOENT;
- break;
+ /* Probably a race, just ignore this */
+ continue;
}
n = read(fd, buf, sizeof(buf)-1);
close(fd);
@@ -816,24 +820,18 @@ int sysfs_unique_holder(int devnum, long rdev)
continue;
buf[n] = 0;
if (sscanf(buf, "%d:%d%c", &mj, &mn, &c) != 3 ||
- c != '\n') {
- errno = ENOENT;
- break;
- }
+ c != '\n')
+ continue;
if (mj != MD_MAJOR)
mn = -1-(mn>>6);
- if (devnum != mn) {
- errno = EEXIST;
- break;
- }
- found = 1;
+ if (devnum == mn)
+ ret |= 1;
+ else
+ ret |= 2;
}
closedir(dir);
- if (de)
- return 0;
- else
- return found;
+ return ret;
}
int sysfs_freeze_array(struct mdinfo *sra)