diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/md/raid6main.c | 149 |
1 files changed, 115 insertions, 34 deletions
diff --git a/drivers/md/raid6main.c b/drivers/md/raid6main.c index f618a53b98be..ed2abb2e2e2d 100644 --- a/drivers/md/raid6main.c +++ b/drivers/md/raid6main.c | |||
@@ -115,7 +115,7 @@ static void __release_stripe(raid6_conf_t *conf, struct stripe_head *sh) | |||
115 | list_add_tail(&sh->lru, &conf->inactive_list); | 115 | list_add_tail(&sh->lru, &conf->inactive_list); |
116 | atomic_dec(&conf->active_stripes); | 116 | atomic_dec(&conf->active_stripes); |
117 | if (!conf->inactive_blocked || | 117 | if (!conf->inactive_blocked || |
118 | atomic_read(&conf->active_stripes) < (NR_STRIPES*3/4)) | 118 | atomic_read(&conf->active_stripes) < (conf->max_nr_stripes*3/4)) |
119 | wake_up(&conf->wait_for_stripe); | 119 | wake_up(&conf->wait_for_stripe); |
120 | } | 120 | } |
121 | } | 121 | } |
@@ -273,7 +273,8 @@ static struct stripe_head *get_active_stripe(raid6_conf_t *conf, sector_t sector | |||
273 | conf->inactive_blocked = 1; | 273 | conf->inactive_blocked = 1; |
274 | wait_event_lock_irq(conf->wait_for_stripe, | 274 | wait_event_lock_irq(conf->wait_for_stripe, |
275 | !list_empty(&conf->inactive_list) && | 275 | !list_empty(&conf->inactive_list) && |
276 | (atomic_read(&conf->active_stripes) < (NR_STRIPES *3/4) | 276 | (atomic_read(&conf->active_stripes) |
277 | < (conf->max_nr_stripes *3/4) | ||
277 | || !conf->inactive_blocked), | 278 | || !conf->inactive_blocked), |
278 | conf->device_lock, | 279 | conf->device_lock, |
279 | unplug_slaves(conf->mddev); | 280 | unplug_slaves(conf->mddev); |
@@ -302,9 +303,31 @@ static struct stripe_head *get_active_stripe(raid6_conf_t *conf, sector_t sector | |||
302 | return sh; | 303 | return sh; |
303 | } | 304 | } |
304 | 305 | ||
305 | static int grow_stripes(raid6_conf_t *conf, int num) | 306 | static int grow_one_stripe(raid6_conf_t *conf) |
306 | { | 307 | { |
307 | struct stripe_head *sh; | 308 | struct stripe_head *sh; |
309 | sh = kmem_cache_alloc(conf->slab_cache, GFP_KERNEL); | ||
310 | if (!sh) | ||
311 | return 0; | ||
312 | memset(sh, 0, sizeof(*sh) + (conf->raid_disks-1)*sizeof(struct r5dev)); | ||
313 | sh->raid_conf = conf; | ||
314 | spin_lock_init(&sh->lock); | ||
315 | |||
316 | if (grow_buffers(sh, conf->raid_disks)) { | ||
317 | shrink_buffers(sh, conf->raid_disks); | ||
318 | kmem_cache_free(conf->slab_cache, sh); | ||
319 | return 0; | ||
320 | } | ||
321 | /* we just created an active stripe so... */ | ||
322 | atomic_set(&sh->count, 1); | ||
323 | atomic_inc(&conf->active_stripes); | ||
324 | INIT_LIST_HEAD(&sh->lru); | ||
325 | release_stripe(sh); | ||
326 | return 1; | ||
327 | } | ||
328 | |||
329 | static int grow_stripes(raid6_conf_t *conf, int num) | ||
330 | { | ||
308 | kmem_cache_t *sc; | 331 | kmem_cache_t *sc; |
309 | int devs = conf->raid_disks; | 332 | int devs = conf->raid_disks; |
310 | 333 | ||
@@ -316,44 +339,33 @@ static int grow_stripes(raid6_conf_t *conf, int num) | |||
316 | if (!sc) | 339 | if (!sc) |
317 | return 1; | 340 | return 1; |
318 | conf->slab_cache = sc; | 341 | conf->slab_cache = sc; |
319 | while (num--) { | 342 | while (num--) |
320 | sh = kmem_cache_alloc(sc, GFP_KERNEL); | 343 | if (!grow_one_stripe(conf)) |
321 | if (!sh) | ||
322 | return 1; | ||
323 | memset(sh, 0, sizeof(*sh) + (devs-1)*sizeof(struct r5dev)); | ||
324 | sh->raid_conf = conf; | ||
325 | spin_lock_init(&sh->lock); | ||
326 | |||
327 | if (grow_buffers(sh, conf->raid_disks)) { | ||
328 | shrink_buffers(sh, conf->raid_disks); | ||
329 | kmem_cache_free(sc, sh); | ||
330 | return 1; | 344 | return 1; |
331 | } | ||
332 | /* we just created an active stripe so... */ | ||
333 | atomic_set(&sh->count, 1); | ||
334 | atomic_inc(&conf->active_stripes); | ||
335 | INIT_LIST_HEAD(&sh->lru); | ||
336 | release_stripe(sh); | ||
337 | } | ||
338 | return 0; | 345 | return 0; |
339 | } | 346 | } |
340 | 347 | ||
341 | static void shrink_stripes(raid6_conf_t *conf) | 348 | static int drop_one_stripe(raid6_conf_t *conf) |
342 | { | 349 | { |
343 | struct stripe_head *sh; | 350 | struct stripe_head *sh; |
351 | spin_lock_irq(&conf->device_lock); | ||
352 | sh = get_free_stripe(conf); | ||
353 | spin_unlock_irq(&conf->device_lock); | ||
354 | if (!sh) | ||
355 | return 0; | ||
356 | if (atomic_read(&sh->count)) | ||
357 | BUG(); | ||
358 | shrink_buffers(sh, conf->raid_disks); | ||
359 | kmem_cache_free(conf->slab_cache, sh); | ||
360 | atomic_dec(&conf->active_stripes); | ||
361 | return 1; | ||
362 | } | ||
363 | |||
364 | static void shrink_stripes(raid6_conf_t *conf) | ||
365 | { | ||
366 | while (drop_one_stripe(conf)) | ||
367 | ; | ||
344 | 368 | ||
345 | while (1) { | ||
346 | spin_lock_irq(&conf->device_lock); | ||
347 | sh = get_free_stripe(conf); | ||
348 | spin_unlock_irq(&conf->device_lock); | ||
349 | if (!sh) | ||
350 | break; | ||
351 | if (atomic_read(&sh->count)) | ||
352 | BUG(); | ||
353 | shrink_buffers(sh, conf->raid_disks); | ||
354 | kmem_cache_free(conf->slab_cache, sh); | ||
355 | atomic_dec(&conf->active_stripes); | ||
356 | } | ||
357 | kmem_cache_destroy(conf->slab_cache); | 369 | kmem_cache_destroy(conf->slab_cache); |
358 | conf->slab_cache = NULL; | 370 | conf->slab_cache = NULL; |
359 | } | 371 | } |
@@ -1912,6 +1924,74 @@ static void raid6d (mddev_t *mddev) | |||
1912 | PRINTK("--- raid6d inactive\n"); | 1924 | PRINTK("--- raid6d inactive\n"); |
1913 | } | 1925 | } |
1914 | 1926 | ||
1927 | static ssize_t | ||
1928 | raid6_show_stripe_cache_size(mddev_t *mddev, char *page) | ||
1929 | { | ||
1930 | raid6_conf_t *conf = mddev_to_conf(mddev); | ||
1931 | if (conf) | ||
1932 | return sprintf(page, "%d\n", conf->max_nr_stripes); | ||
1933 | else | ||
1934 | return 0; | ||
1935 | } | ||
1936 | |||
1937 | static ssize_t | ||
1938 | raid6_store_stripe_cache_size(mddev_t *mddev, const char *page, size_t len) | ||
1939 | { | ||
1940 | raid6_conf_t *conf = mddev_to_conf(mddev); | ||
1941 | char *end; | ||
1942 | int new; | ||
1943 | if (len >= PAGE_SIZE) | ||
1944 | return -EINVAL; | ||
1945 | if (!conf) | ||
1946 | return -ENODEV; | ||
1947 | |||
1948 | new = simple_strtoul(page, &end, 10); | ||
1949 | if (!*page || (*end && *end != '\n') ) | ||
1950 | return -EINVAL; | ||
1951 | if (new <= 16 || new > 32768) | ||
1952 | return -EINVAL; | ||
1953 | while (new < conf->max_nr_stripes) { | ||
1954 | if (drop_one_stripe(conf)) | ||
1955 | conf->max_nr_stripes--; | ||
1956 | else | ||
1957 | break; | ||
1958 | } | ||
1959 | while (new > conf->max_nr_stripes) { | ||
1960 | if (grow_one_stripe(conf)) | ||
1961 | conf->max_nr_stripes++; | ||
1962 | else break; | ||
1963 | } | ||
1964 | return len; | ||
1965 | } | ||
1966 | |||
1967 | static struct md_sysfs_entry | ||
1968 | raid6_stripecache_size = __ATTR(stripe_cache_size, S_IRUGO | S_IWUSR, | ||
1969 | raid6_show_stripe_cache_size, | ||
1970 | raid6_store_stripe_cache_size); | ||
1971 | |||
1972 | static ssize_t | ||
1973 | stripe_cache_active_show(mddev_t *mddev, char *page) | ||
1974 | { | ||
1975 | raid6_conf_t *conf = mddev_to_conf(mddev); | ||
1976 | if (conf) | ||
1977 | return sprintf(page, "%d\n", atomic_read(&conf->active_stripes)); | ||
1978 | else | ||
1979 | return 0; | ||
1980 | } | ||
1981 | |||
1982 | static struct md_sysfs_entry | ||
1983 | raid6_stripecache_active = __ATTR_RO(stripe_cache_active); | ||
1984 | |||
1985 | static struct attribute *raid6_attrs[] = { | ||
1986 | &raid6_stripecache_size.attr, | ||
1987 | &raid6_stripecache_active.attr, | ||
1988 | NULL, | ||
1989 | }; | ||
1990 | static struct attribute_group raid6_attrs_group = { | ||
1991 | .name = NULL, | ||
1992 | .attrs = raid6_attrs, | ||
1993 | }; | ||
1994 | |||
1915 | static int run(mddev_t *mddev) | 1995 | static int run(mddev_t *mddev) |
1916 | { | 1996 | { |
1917 | raid6_conf_t *conf; | 1997 | raid6_conf_t *conf; |
@@ -2095,6 +2175,7 @@ static int stop (mddev_t *mddev) | |||
2095 | shrink_stripes(conf); | 2175 | shrink_stripes(conf); |
2096 | kfree(conf->stripe_hashtbl); | 2176 | kfree(conf->stripe_hashtbl); |
2097 | blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/ | 2177 | blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/ |
2178 | sysfs_remove_group(&mddev->kobj, &raid6_attrs_group); | ||
2098 | kfree(conf); | 2179 | kfree(conf); |
2099 | mddev->private = NULL; | 2180 | mddev->private = NULL; |
2100 | return 0; | 2181 | return 0; |