diff options
Diffstat (limited to 'drivers/md/raid5.c')
-rw-r--r-- | drivers/md/raid5.c | 183 |
1 files changed, 151 insertions, 32 deletions
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 8cf1ae8b8a71..121fbaa9ed59 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c | |||
@@ -293,9 +293,31 @@ static struct stripe_head *get_active_stripe(raid5_conf_t *conf, sector_t sector | |||
293 | return sh; | 293 | return sh; |
294 | } | 294 | } |
295 | 295 | ||
296 | static int grow_stripes(raid5_conf_t *conf, int num) | 296 | static int grow_one_stripe(raid5_conf_t *conf) |
297 | { | 297 | { |
298 | struct stripe_head *sh; | 298 | struct stripe_head *sh; |
299 | sh = kmem_cache_alloc(conf->slab_cache, GFP_KERNEL); | ||
300 | if (!sh) | ||
301 | return 0; | ||
302 | memset(sh, 0, sizeof(*sh) + (conf->raid_disks-1)*sizeof(struct r5dev)); | ||
303 | sh->raid_conf = conf; | ||
304 | spin_lock_init(&sh->lock); | ||
305 | |||
306 | if (grow_buffers(sh, conf->raid_disks)) { | ||
307 | shrink_buffers(sh, conf->raid_disks); | ||
308 | kmem_cache_free(conf->slab_cache, sh); | ||
309 | return 0; | ||
310 | } | ||
311 | /* we just created an active stripe so... */ | ||
312 | atomic_set(&sh->count, 1); | ||
313 | atomic_inc(&conf->active_stripes); | ||
314 | INIT_LIST_HEAD(&sh->lru); | ||
315 | release_stripe(sh); | ||
316 | return 1; | ||
317 | } | ||
318 | |||
319 | static int grow_stripes(raid5_conf_t *conf, int num) | ||
320 | { | ||
299 | kmem_cache_t *sc; | 321 | kmem_cache_t *sc; |
300 | int devs = conf->raid_disks; | 322 | int devs = conf->raid_disks; |
301 | 323 | ||
@@ -308,43 +330,34 @@ static int grow_stripes(raid5_conf_t *conf, int num) | |||
308 | return 1; | 330 | return 1; |
309 | conf->slab_cache = sc; | 331 | conf->slab_cache = sc; |
310 | while (num--) { | 332 | while (num--) { |
311 | sh = kmem_cache_alloc(sc, GFP_KERNEL); | 333 | if (!grow_one_stripe(conf)) |
312 | if (!sh) | ||
313 | return 1; | ||
314 | memset(sh, 0, sizeof(*sh) + (devs-1)*sizeof(struct r5dev)); | ||
315 | sh->raid_conf = conf; | ||
316 | spin_lock_init(&sh->lock); | ||
317 | |||
318 | if (grow_buffers(sh, conf->raid_disks)) { | ||
319 | shrink_buffers(sh, conf->raid_disks); | ||
320 | kmem_cache_free(sc, sh); | ||
321 | return 1; | 334 | return 1; |
322 | } | ||
323 | /* we just created an active stripe so... */ | ||
324 | atomic_set(&sh->count, 1); | ||
325 | atomic_inc(&conf->active_stripes); | ||
326 | INIT_LIST_HEAD(&sh->lru); | ||
327 | release_stripe(sh); | ||
328 | } | 335 | } |
329 | return 0; | 336 | return 0; |
330 | } | 337 | } |
331 | 338 | ||
332 | static void shrink_stripes(raid5_conf_t *conf) | 339 | static int drop_one_stripe(raid5_conf_t *conf) |
333 | { | 340 | { |
334 | struct stripe_head *sh; | 341 | struct stripe_head *sh; |
335 | 342 | ||
336 | while (1) { | 343 | spin_lock_irq(&conf->device_lock); |
337 | spin_lock_irq(&conf->device_lock); | 344 | sh = get_free_stripe(conf); |
338 | sh = get_free_stripe(conf); | 345 | spin_unlock_irq(&conf->device_lock); |
339 | spin_unlock_irq(&conf->device_lock); | 346 | if (!sh) |
340 | if (!sh) | 347 | return 0; |
341 | break; | 348 | if (atomic_read(&sh->count)) |
342 | if (atomic_read(&sh->count)) | 349 | BUG(); |
343 | BUG(); | 350 | shrink_buffers(sh, conf->raid_disks); |
344 | shrink_buffers(sh, conf->raid_disks); | 351 | kmem_cache_free(conf->slab_cache, sh); |
345 | kmem_cache_free(conf->slab_cache, sh); | 352 | atomic_dec(&conf->active_stripes); |
346 | atomic_dec(&conf->active_stripes); | 353 | return 1; |
347 | } | 354 | } |
355 | |||
356 | static void shrink_stripes(raid5_conf_t *conf) | ||
357 | { | ||
358 | while (drop_one_stripe(conf)) | ||
359 | ; | ||
360 | |||
348 | kmem_cache_destroy(conf->slab_cache); | 361 | kmem_cache_destroy(conf->slab_cache); |
349 | conf->slab_cache = NULL; | 362 | conf->slab_cache = NULL; |
350 | } | 363 | } |
@@ -1714,6 +1727,108 @@ static void raid5d (mddev_t *mddev) | |||
1714 | PRINTK("--- raid5d inactive\n"); | 1727 | PRINTK("--- raid5d inactive\n"); |
1715 | } | 1728 | } |
1716 | 1729 | ||
1730 | struct raid5_sysfs_entry { | ||
1731 | struct attribute attr; | ||
1732 | ssize_t (*show)(raid5_conf_t *, char *); | ||
1733 | ssize_t (*store)(raid5_conf_t *, const char *, ssize_t); | ||
1734 | }; | ||
1735 | |||
1736 | static ssize_t | ||
1737 | raid5_show_stripe_cache_size(raid5_conf_t *conf, char *page) | ||
1738 | { | ||
1739 | return sprintf(page, "%d\n", conf->max_nr_stripes); | ||
1740 | } | ||
1741 | |||
1742 | static ssize_t | ||
1743 | raid5_store_stripe_cache_size(raid5_conf_t *conf, const char *page, ssize_t len) | ||
1744 | { | ||
1745 | char *end; | ||
1746 | int new; | ||
1747 | if (len >= PAGE_SIZE) | ||
1748 | return -EINVAL; | ||
1749 | |||
1750 | new = simple_strtoul(page, &end, 10); | ||
1751 | if (!*page || (*end && *end != '\n') ) | ||
1752 | return -EINVAL; | ||
1753 | if (new <= 16 || new > 32768) | ||
1754 | return -EINVAL; | ||
1755 | while (new < conf->max_nr_stripes) { | ||
1756 | if (drop_one_stripe(conf)) | ||
1757 | conf->max_nr_stripes--; | ||
1758 | else | ||
1759 | break; | ||
1760 | } | ||
1761 | while (new > conf->max_nr_stripes) { | ||
1762 | if (grow_one_stripe(conf)) | ||
1763 | conf->max_nr_stripes++; | ||
1764 | else break; | ||
1765 | } | ||
1766 | return len; | ||
1767 | } | ||
1768 | static struct raid5_sysfs_entry raid5_stripecache_size = { | ||
1769 | .attr = {.name = "stripe_cache_size", .mode = S_IRUGO | S_IWUSR }, | ||
1770 | .show = raid5_show_stripe_cache_size, | ||
1771 | .store = raid5_store_stripe_cache_size, | ||
1772 | }; | ||
1773 | |||
1774 | static ssize_t | ||
1775 | raid5_show_stripe_cache_active(raid5_conf_t *conf, char *page) | ||
1776 | { | ||
1777 | return sprintf(page, "%d\n", atomic_read(&conf->active_stripes)); | ||
1778 | } | ||
1779 | |||
1780 | static struct raid5_sysfs_entry raid5_stripecache_active = { | ||
1781 | .attr = {.name = "stripe_cache_active", .mode = S_IRUGO}, | ||
1782 | .show = raid5_show_stripe_cache_active, | ||
1783 | }; | ||
1784 | |||
1785 | static struct attribute *raid5_default_attrs[] = { | ||
1786 | &raid5_stripecache_size.attr, | ||
1787 | &raid5_stripecache_active.attr, | ||
1788 | NULL, | ||
1789 | }; | ||
1790 | |||
1791 | static ssize_t | ||
1792 | raid5_attr_show(struct kobject *kobj, struct attribute *attr, char *page) | ||
1793 | { | ||
1794 | struct raid5_sysfs_entry *entry = container_of(attr, struct raid5_sysfs_entry, attr); | ||
1795 | raid5_conf_t *conf = container_of(kobj, raid5_conf_t, kobj); | ||
1796 | |||
1797 | if (!entry->show) | ||
1798 | return -EIO; | ||
1799 | return entry->show(conf, page); | ||
1800 | } | ||
1801 | |||
1802 | static ssize_t | ||
1803 | raid5_attr_store(struct kobject *kobj, struct attribute *attr, | ||
1804 | const char *page, size_t length) | ||
1805 | { | ||
1806 | struct raid5_sysfs_entry *entry = container_of(attr, struct raid5_sysfs_entry, attr); | ||
1807 | raid5_conf_t *conf = container_of(kobj, raid5_conf_t, kobj); | ||
1808 | |||
1809 | if (!entry->store) | ||
1810 | return -EIO; | ||
1811 | return entry->store(conf, page, length); | ||
1812 | } | ||
1813 | |||
1814 | static void raid5_free(struct kobject *ko) | ||
1815 | { | ||
1816 | raid5_conf_t *conf = container_of(ko, raid5_conf_t, kobj); | ||
1817 | kfree(conf); | ||
1818 | } | ||
1819 | |||
1820 | |||
1821 | static struct sysfs_ops raid5_sysfs_ops = { | ||
1822 | .show = raid5_attr_show, | ||
1823 | .store = raid5_attr_store, | ||
1824 | }; | ||
1825 | |||
1826 | static struct kobj_type raid5_ktype = { | ||
1827 | .release = raid5_free, | ||
1828 | .sysfs_ops = &raid5_sysfs_ops, | ||
1829 | .default_attrs = raid5_default_attrs, | ||
1830 | }; | ||
1831 | |||
1717 | static int run(mddev_t *mddev) | 1832 | static int run(mddev_t *mddev) |
1718 | { | 1833 | { |
1719 | raid5_conf_t *conf; | 1834 | raid5_conf_t *conf; |
@@ -1855,6 +1970,10 @@ memory = conf->max_nr_stripes * (sizeof(struct stripe_head) + | |||
1855 | } | 1970 | } |
1856 | 1971 | ||
1857 | /* Ok, everything is just fine now */ | 1972 | /* Ok, everything is just fine now */ |
1973 | conf->kobj.parent = kobject_get(&mddev->kobj); | ||
1974 | strcpy(conf->kobj.name, "raid5"); | ||
1975 | conf->kobj.ktype = &raid5_ktype; | ||
1976 | kobject_register(&conf->kobj); | ||
1858 | 1977 | ||
1859 | if (mddev->bitmap) | 1978 | if (mddev->bitmap) |
1860 | mddev->thread->timeout = mddev->bitmap->daemon_sleep * HZ; | 1979 | mddev->thread->timeout = mddev->bitmap->daemon_sleep * HZ; |
@@ -1879,7 +1998,7 @@ abort: | |||
1879 | 1998 | ||
1880 | 1999 | ||
1881 | 2000 | ||
1882 | static int stop (mddev_t *mddev) | 2001 | static int stop(mddev_t *mddev) |
1883 | { | 2002 | { |
1884 | raid5_conf_t *conf = (raid5_conf_t *) mddev->private; | 2003 | raid5_conf_t *conf = (raid5_conf_t *) mddev->private; |
1885 | 2004 | ||
@@ -1888,7 +2007,7 @@ static int stop (mddev_t *mddev) | |||
1888 | shrink_stripes(conf); | 2007 | shrink_stripes(conf); |
1889 | free_pages((unsigned long) conf->stripe_hashtbl, HASH_PAGES_ORDER); | 2008 | free_pages((unsigned long) conf->stripe_hashtbl, HASH_PAGES_ORDER); |
1890 | blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/ | 2009 | blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/ |
1891 | kfree(conf); | 2010 | kobject_unregister(&conf->kobj); |
1892 | mddev->private = NULL; | 2011 | mddev->private = NULL; |
1893 | return 0; | 2012 | return 0; |
1894 | } | 2013 | } |