aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/md.c
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2008-03-04 17:29:33 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-03-04 19:35:18 -0500
commit27c529bb8e906d5d692152bc127cc09477d3629e (patch)
tree1bcfa43a45206e03bbc729c5d3af4bed830d4439 /drivers/md/md.c
parent25156198235325805cd7295ed694509fd6e3a29e (diff)
md: lock access to rdev attributes properly
When we access attributes of an rdev (component device on an md array) through sysfs, we really need to lock the array against concurrent changes. We currently do that when we change an attribute, but not when we read an attribute. We need to lock when reading as well else rdev->mddev could become NULL while we are accessing it. So add appropriate locking (mddev_lock) to rdev_attr_show. rdev_size_store requires some extra care as well as it needs to unlock the mddev while scanning other mddevs for overlapping regions. We currently assume that rdev->mddev will still be unchanged after the scan, but that cannot be certain. So take a copy of rdev->mddev for use at the end of the function. Signed-off-by: Neil Brown <neilb@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/md/md.c')
-rw-r--r--drivers/md/md.c35
1 files changed, 26 insertions, 9 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c
index a986845ea0c3..827824a9f3e9 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -2001,9 +2001,11 @@ rdev_size_store(mdk_rdev_t *rdev, const char *buf, size_t len)
2001 char *e; 2001 char *e;
2002 unsigned long long size = simple_strtoull(buf, &e, 10); 2002 unsigned long long size = simple_strtoull(buf, &e, 10);
2003 unsigned long long oldsize = rdev->size; 2003 unsigned long long oldsize = rdev->size;
2004 mddev_t *my_mddev = rdev->mddev;
2005
2004 if (e==buf || (*e && *e != '\n')) 2006 if (e==buf || (*e && *e != '\n'))
2005 return -EINVAL; 2007 return -EINVAL;
2006 if (rdev->mddev->pers) 2008 if (my_mddev->pers)
2007 return -EBUSY; 2009 return -EBUSY;
2008 rdev->size = size; 2010 rdev->size = size;
2009 if (size > oldsize && rdev->mddev->external) { 2011 if (size > oldsize && rdev->mddev->external) {
@@ -2016,7 +2018,7 @@ rdev_size_store(mdk_rdev_t *rdev, const char *buf, size_t len)
2016 int overlap = 0; 2018 int overlap = 0;
2017 struct list_head *tmp, *tmp2; 2019 struct list_head *tmp, *tmp2;
2018 2020
2019 mddev_unlock(rdev->mddev); 2021 mddev_unlock(my_mddev);
2020 for_each_mddev(mddev, tmp) { 2022 for_each_mddev(mddev, tmp) {
2021 mdk_rdev_t *rdev2; 2023 mdk_rdev_t *rdev2;
2022 2024
@@ -2036,7 +2038,7 @@ rdev_size_store(mdk_rdev_t *rdev, const char *buf, size_t len)
2036 break; 2038 break;
2037 } 2039 }
2038 } 2040 }
2039 mddev_lock(rdev->mddev); 2041 mddev_lock(my_mddev);
2040 if (overlap) { 2042 if (overlap) {
2041 /* Someone else could have slipped in a size 2043 /* Someone else could have slipped in a size
2042 * change here, but doing so is just silly. 2044 * change here, but doing so is just silly.
@@ -2048,8 +2050,8 @@ rdev_size_store(mdk_rdev_t *rdev, const char *buf, size_t len)
2048 return -EBUSY; 2050 return -EBUSY;
2049 } 2051 }
2050 } 2052 }
2051 if (size < rdev->mddev->size || rdev->mddev->size == 0) 2053 if (size < my_mddev->size || my_mddev->size == 0)
2052 rdev->mddev->size = size; 2054 my_mddev->size = size;
2053 return len; 2055 return len;
2054} 2056}
2055 2057
@@ -2070,10 +2072,21 @@ rdev_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
2070{ 2072{
2071 struct rdev_sysfs_entry *entry = container_of(attr, struct rdev_sysfs_entry, attr); 2073 struct rdev_sysfs_entry *entry = container_of(attr, struct rdev_sysfs_entry, attr);
2072 mdk_rdev_t *rdev = container_of(kobj, mdk_rdev_t, kobj); 2074 mdk_rdev_t *rdev = container_of(kobj, mdk_rdev_t, kobj);
2075 mddev_t *mddev = rdev->mddev;
2076 ssize_t rv;
2073 2077
2074 if (!entry->show) 2078 if (!entry->show)
2075 return -EIO; 2079 return -EIO;
2076 return entry->show(rdev, page); 2080
2081 rv = mddev ? mddev_lock(mddev) : -EBUSY;
2082 if (!rv) {
2083 if (rdev->mddev == NULL)
2084 rv = -EBUSY;
2085 else
2086 rv = entry->show(rdev, page);
2087 mddev_unlock(mddev);
2088 }
2089 return rv;
2077} 2090}
2078 2091
2079static ssize_t 2092static ssize_t
@@ -2082,15 +2095,19 @@ rdev_attr_store(struct kobject *kobj, struct attribute *attr,
2082{ 2095{
2083 struct rdev_sysfs_entry *entry = container_of(attr, struct rdev_sysfs_entry, attr); 2096 struct rdev_sysfs_entry *entry = container_of(attr, struct rdev_sysfs_entry, attr);
2084 mdk_rdev_t *rdev = container_of(kobj, mdk_rdev_t, kobj); 2097 mdk_rdev_t *rdev = container_of(kobj, mdk_rdev_t, kobj);
2085 int rv; 2098 ssize_t rv;
2099 mddev_t *mddev = rdev->mddev;
2086 2100
2087 if (!entry->store) 2101 if (!entry->store)
2088 return -EIO; 2102 return -EIO;
2089 if (!capable(CAP_SYS_ADMIN)) 2103 if (!capable(CAP_SYS_ADMIN))
2090 return -EACCES; 2104 return -EACCES;
2091 rv = mddev_lock(rdev->mddev); 2105 rv = mddev ? mddev_lock(mddev): -EBUSY;
2092 if (!rv) { 2106 if (!rv) {
2093 rv = entry->store(rdev, page, length); 2107 if (rdev->mddev == NULL)
2108 rv = -EBUSY;
2109 else
2110 rv = entry->store(rdev, page, length);
2094 mddev_unlock(rdev->mddev); 2111 mddev_unlock(rdev->mddev);
2095 } 2112 }
2096 return rv; 2113 return rv;