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/md.c | |
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/md.c')
-rw-r--r-- | drivers/md/md.c | 62 |
1 files changed, 28 insertions, 34 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) |