diff options
author | NeilBrown <neilb@suse.de> | 2005-11-09 00:39:39 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-11-09 10:56:39 -0500 |
commit | 96de1e663cda65ba9275afb1bc007f34e5068ba1 (patch) | |
tree | b927dda4f0f2d2669658f5974a848d9f701f330b /drivers/md | |
parent | 3855ad9f398de88a3290f7dd799633c4b73903ea (diff) |
[PATCH] md: fix some locking and module refcounting issues with md's use of sysfs
1/ I really should be using the __ATTR macros for defining attributes, so
that the .owner field get set properly, otherwise modules can be removed
while sysfs files are open. This also involves some name changes of _show
routines.
2/ Always lock the mddev (against reconfiguration) for all sysfs attribute
access. This easily avoid certain races and is completely consistant with
other interfaces (ioctl and /proc/mdstat both always lock against
reconfiguration).
3/ raid5 attributes must check that the 'conf' structure actually exists
(the array could have been stopped while an attribute file was open).
4/ A missing 'kfree' from when the raid5_conf_t was converted to have a
kobject embedded, and then converted back again.
Signed-off-by: Neil Brown <neilb@suse.de>
Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/md')
-rw-r--r-- | drivers/md/md.c | 62 | ||||
-rw-r--r-- | drivers/md/raid5.c | 30 |
2 files changed, 46 insertions, 46 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c index 2b5928976095..b2d8813ed716 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c | |||
@@ -1504,7 +1504,7 @@ struct rdev_sysfs_entry { | |||
1504 | }; | 1504 | }; |
1505 | 1505 | ||
1506 | static ssize_t | 1506 | static ssize_t |
1507 | rdev_show_state(mdk_rdev_t *rdev, char *page) | 1507 | state_show(mdk_rdev_t *rdev, char *page) |
1508 | { | 1508 | { |
1509 | char *sep = ""; | 1509 | char *sep = ""; |
1510 | int len=0; | 1510 | int len=0; |
@@ -1525,13 +1525,11 @@ rdev_show_state(mdk_rdev_t *rdev, char *page) | |||
1525 | return len+sprintf(page+len, "\n"); | 1525 | return len+sprintf(page+len, "\n"); |
1526 | } | 1526 | } |
1527 | 1527 | ||
1528 | static struct rdev_sysfs_entry rdev_state = { | 1528 | static struct rdev_sysfs_entry |
1529 | .attr = {.name = "state", .mode = S_IRUGO }, | 1529 | rdev_state = __ATTR_RO(state); |
1530 | .show = rdev_show_state, | ||
1531 | }; | ||
1532 | 1530 | ||
1533 | static ssize_t | 1531 | static ssize_t |
1534 | rdev_show_super(mdk_rdev_t *rdev, char *page) | 1532 | super_show(mdk_rdev_t *rdev, char *page) |
1535 | { | 1533 | { |
1536 | if (rdev->sb_loaded && rdev->sb_size) { | 1534 | if (rdev->sb_loaded && rdev->sb_size) { |
1537 | memcpy(page, page_address(rdev->sb_page), rdev->sb_size); | 1535 | memcpy(page, page_address(rdev->sb_page), rdev->sb_size); |
@@ -1539,10 +1537,8 @@ rdev_show_super(mdk_rdev_t *rdev, char *page) | |||
1539 | } else | 1537 | } else |
1540 | return 0; | 1538 | return 0; |
1541 | } | 1539 | } |
1542 | static struct rdev_sysfs_entry rdev_super = { | 1540 | static struct rdev_sysfs_entry rdev_super = __ATTR_RO(super); |
1543 | .attr = {.name = "super", .mode = S_IRUGO }, | 1541 | |
1544 | .show = rdev_show_super, | ||
1545 | }; | ||
1546 | static struct attribute *rdev_default_attrs[] = { | 1542 | static struct attribute *rdev_default_attrs[] = { |
1547 | &rdev_state.attr, | 1543 | &rdev_state.attr, |
1548 | &rdev_super.attr, | 1544 | &rdev_super.attr, |
@@ -1728,7 +1724,7 @@ static void analyze_sbs(mddev_t * mddev) | |||
1728 | } | 1724 | } |
1729 | 1725 | ||
1730 | static ssize_t | 1726 | static ssize_t |
1731 | md_show_level(mddev_t *mddev, char *page) | 1727 | level_show(mddev_t *mddev, char *page) |
1732 | { | 1728 | { |
1733 | mdk_personality_t *p = mddev->pers; | 1729 | mdk_personality_t *p = mddev->pers; |
1734 | if (p == NULL) | 1730 | if (p == NULL) |
@@ -1739,21 +1735,15 @@ md_show_level(mddev_t *mddev, char *page) | |||
1739 | return sprintf(page, "%s\n", p->name); | 1735 | return sprintf(page, "%s\n", p->name); |
1740 | } | 1736 | } |
1741 | 1737 | ||
1742 | static struct md_sysfs_entry md_level = { | 1738 | static struct md_sysfs_entry md_level = __ATTR_RO(level); |
1743 | .attr = {.name = "level", .mode = S_IRUGO }, | ||
1744 | .show = md_show_level, | ||
1745 | }; | ||
1746 | 1739 | ||
1747 | static ssize_t | 1740 | static ssize_t |
1748 | md_show_rdisks(mddev_t *mddev, char *page) | 1741 | raid_disks_show(mddev_t *mddev, char *page) |
1749 | { | 1742 | { |
1750 | return sprintf(page, "%d\n", mddev->raid_disks); | 1743 | return sprintf(page, "%d\n", mddev->raid_disks); |
1751 | } | 1744 | } |
1752 | 1745 | ||
1753 | static struct md_sysfs_entry md_raid_disks = { | 1746 | static struct md_sysfs_entry md_raid_disks = __ATTR_RO(raid_disks); |
1754 | .attr = {.name = "raid_disks", .mode = S_IRUGO }, | ||
1755 | .show = md_show_rdisks, | ||
1756 | }; | ||
1757 | 1747 | ||
1758 | static ssize_t | 1748 | static ssize_t |
1759 | md_show_scan(mddev_t *mddev, char *page) | 1749 | md_show_scan(mddev_t *mddev, char *page) |
@@ -1782,10 +1772,10 @@ md_store_scan(mddev_t *mddev, const char *page, size_t len) | |||
1782 | if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) || | 1772 | if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) || |
1783 | test_bit(MD_RECOVERY_NEEDED, &mddev->recovery)) | 1773 | test_bit(MD_RECOVERY_NEEDED, &mddev->recovery)) |
1784 | return -EBUSY; | 1774 | return -EBUSY; |
1785 | down(&mddev->reconfig_sem); | 1775 | |
1786 | if (mddev->pers && mddev->pers->sync_request) | 1776 | if (mddev->pers && mddev->pers->sync_request) |
1787 | canscan=1; | 1777 | canscan=1; |
1788 | up(&mddev->reconfig_sem); | 1778 | |
1789 | if (!canscan) | 1779 | if (!canscan) |
1790 | return -EINVAL; | 1780 | return -EINVAL; |
1791 | 1781 | ||
@@ -1801,22 +1791,18 @@ md_store_scan(mddev_t *mddev, const char *page, size_t len) | |||
1801 | } | 1791 | } |
1802 | 1792 | ||
1803 | static ssize_t | 1793 | static ssize_t |
1804 | md_show_mismatch(mddev_t *mddev, char *page) | 1794 | mismatch_cnt_show(mddev_t *mddev, char *page) |
1805 | { | 1795 | { |
1806 | return sprintf(page, "%llu\n", | 1796 | return sprintf(page, "%llu\n", |
1807 | (unsigned long long) mddev->resync_mismatches); | 1797 | (unsigned long long) mddev->resync_mismatches); |
1808 | } | 1798 | } |
1809 | 1799 | ||
1810 | static struct md_sysfs_entry md_scan_mode = { | 1800 | static struct md_sysfs_entry |
1811 | .attr = {.name = "scan_mode", .mode = S_IRUGO|S_IWUSR }, | 1801 | md_scan_mode = __ATTR(scan_mode, S_IRUGO|S_IWUSR, md_show_scan, md_store_scan); |
1812 | .show = md_show_scan, | ||
1813 | .store = md_store_scan, | ||
1814 | }; | ||
1815 | 1802 | ||
1816 | static struct md_sysfs_entry md_mismatches = { | 1803 | |
1817 | .attr = {.name = "mismatch_cnt", .mode = S_IRUGO }, | 1804 | static struct md_sysfs_entry |
1818 | .show = md_show_mismatch, | 1805 | md_mismatches = __ATTR_RO(mismatch_cnt); |
1819 | }; | ||
1820 | 1806 | ||
1821 | static struct attribute *md_default_attrs[] = { | 1807 | static struct attribute *md_default_attrs[] = { |
1822 | &md_level.attr, | 1808 | &md_level.attr, |
@@ -1831,10 +1817,14 @@ md_attr_show(struct kobject *kobj, struct attribute *attr, char *page) | |||
1831 | { | 1817 | { |
1832 | struct md_sysfs_entry *entry = container_of(attr, struct md_sysfs_entry, attr); | 1818 | struct md_sysfs_entry *entry = container_of(attr, struct md_sysfs_entry, attr); |
1833 | mddev_t *mddev = container_of(kobj, struct mddev_s, kobj); | 1819 | mddev_t *mddev = container_of(kobj, struct mddev_s, kobj); |
1820 | ssize_t rv; | ||
1834 | 1821 | ||
1835 | if (!entry->show) | 1822 | if (!entry->show) |
1836 | return -EIO; | 1823 | return -EIO; |
1837 | return entry->show(mddev, page); | 1824 | mddev_lock(mddev); |
1825 | rv = entry->show(mddev, page); | ||
1826 | mddev_unlock(mddev); | ||
1827 | return rv; | ||
1838 | } | 1828 | } |
1839 | 1829 | ||
1840 | static ssize_t | 1830 | static ssize_t |
@@ -1843,10 +1833,14 @@ md_attr_store(struct kobject *kobj, struct attribute *attr, | |||
1843 | { | 1833 | { |
1844 | struct md_sysfs_entry *entry = container_of(attr, struct md_sysfs_entry, attr); | 1834 | struct md_sysfs_entry *entry = container_of(attr, struct md_sysfs_entry, attr); |
1845 | mddev_t *mddev = container_of(kobj, struct mddev_s, kobj); | 1835 | mddev_t *mddev = container_of(kobj, struct mddev_s, kobj); |
1836 | ssize_t rv; | ||
1846 | 1837 | ||
1847 | if (!entry->store) | 1838 | if (!entry->store) |
1848 | return -EIO; | 1839 | return -EIO; |
1849 | return entry->store(mddev, page, length); | 1840 | mddev_lock(mddev); |
1841 | rv = entry->store(mddev, page, length); | ||
1842 | mddev_unlock(mddev); | ||
1843 | return rv; | ||
1850 | } | 1844 | } |
1851 | 1845 | ||
1852 | static void md_free(struct kobject *ko) | 1846 | static void md_free(struct kobject *ko) |
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 51003b008de7..e2a40283e323 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c | |||
@@ -1746,7 +1746,10 @@ static ssize_t | |||
1746 | raid5_show_stripe_cache_size(mddev_t *mddev, char *page) | 1746 | raid5_show_stripe_cache_size(mddev_t *mddev, char *page) |
1747 | { | 1747 | { |
1748 | raid5_conf_t *conf = mddev_to_conf(mddev); | 1748 | raid5_conf_t *conf = mddev_to_conf(mddev); |
1749 | return sprintf(page, "%d\n", conf->max_nr_stripes); | 1749 | if (conf) |
1750 | return sprintf(page, "%d\n", conf->max_nr_stripes); | ||
1751 | else | ||
1752 | return 0; | ||
1750 | } | 1753 | } |
1751 | 1754 | ||
1752 | static ssize_t | 1755 | static ssize_t |
@@ -1757,6 +1760,8 @@ raid5_store_stripe_cache_size(mddev_t *mddev, const char *page, size_t len) | |||
1757 | int new; | 1760 | int new; |
1758 | if (len >= PAGE_SIZE) | 1761 | if (len >= PAGE_SIZE) |
1759 | return -EINVAL; | 1762 | return -EINVAL; |
1763 | if (!conf) | ||
1764 | return -ENODEV; | ||
1760 | 1765 | ||
1761 | new = simple_strtoul(page, &end, 10); | 1766 | new = simple_strtoul(page, &end, 10); |
1762 | if (!*page || (*end && *end != '\n') ) | 1767 | if (!*page || (*end && *end != '\n') ) |
@@ -1777,23 +1782,23 @@ raid5_store_stripe_cache_size(mddev_t *mddev, const char *page, size_t len) | |||
1777 | return len; | 1782 | return len; |
1778 | } | 1783 | } |
1779 | 1784 | ||
1780 | static struct md_sysfs_entry raid5_stripecache_size = { | 1785 | static struct md_sysfs_entry |
1781 | .attr = {.name = "stripe_cache_size", .mode = S_IRUGO | S_IWUSR }, | 1786 | raid5_stripecache_size = __ATTR(stripe_cache_size, S_IRUGO | S_IWUSR, |
1782 | .show = raid5_show_stripe_cache_size, | 1787 | raid5_show_stripe_cache_size, |
1783 | .store = raid5_store_stripe_cache_size, | 1788 | raid5_store_stripe_cache_size); |
1784 | }; | ||
1785 | 1789 | ||
1786 | static ssize_t | 1790 | static ssize_t |
1787 | raid5_show_stripe_cache_active(mddev_t *mddev, char *page) | 1791 | stripe_cache_active_show(mddev_t *mddev, char *page) |
1788 | { | 1792 | { |
1789 | raid5_conf_t *conf = mddev_to_conf(mddev); | 1793 | raid5_conf_t *conf = mddev_to_conf(mddev); |
1790 | return sprintf(page, "%d\n", atomic_read(&conf->active_stripes)); | 1794 | if (conf) |
1795 | return sprintf(page, "%d\n", atomic_read(&conf->active_stripes)); | ||
1796 | else | ||
1797 | return 0; | ||
1791 | } | 1798 | } |
1792 | 1799 | ||
1793 | static struct md_sysfs_entry raid5_stripecache_active = { | 1800 | static struct md_sysfs_entry |
1794 | .attr = {.name = "stripe_cache_active", .mode = S_IRUGO}, | 1801 | raid5_stripecache_active = __ATTR_RO(stripe_cache_active); |
1795 | .show = raid5_show_stripe_cache_active, | ||
1796 | }; | ||
1797 | 1802 | ||
1798 | static struct attribute *raid5_attrs[] = { | 1803 | static struct attribute *raid5_attrs[] = { |
1799 | &raid5_stripecache_size.attr, | 1804 | &raid5_stripecache_size.attr, |
@@ -1981,6 +1986,7 @@ static int stop(mddev_t *mddev) | |||
1981 | free_pages((unsigned long) conf->stripe_hashtbl, HASH_PAGES_ORDER); | 1986 | free_pages((unsigned long) conf->stripe_hashtbl, HASH_PAGES_ORDER); |
1982 | blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/ | 1987 | blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/ |
1983 | sysfs_remove_group(&mddev->kobj, &raid5_attrs_group); | 1988 | sysfs_remove_group(&mddev->kobj, &raid5_attrs_group); |
1989 | kfree(conf); | ||
1984 | mddev->private = NULL; | 1990 | mddev->private = NULL; |
1985 | return 0; | 1991 | return 0; |
1986 | } | 1992 | } |