diff options
| author | NeilBrown <neilb@suse.de> | 2006-01-06 03:20:49 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-06 11:34:08 -0500 |
| commit | a35b0d695d44410eb1734c9abb632725a3138628 (patch) | |
| tree | 0da4a3ba93cf8a1fd2b4dcad3dd251def752942d /drivers/md | |
| parent | 3b34380ae8c5df6debd85183c7fa1ac05f79b7d2 (diff) | |
[PATCH] md: allow md array component size to be accessed and set via sysfs
Signed-off-by: Neil Brown <neilb@suse.de>
Acked-by: Greg KH <greg@kroah.com>
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 | 131 |
1 files changed, 89 insertions, 42 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c index 9e57e97bd53..d568ab4a487 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c | |||
| @@ -1820,6 +1820,44 @@ __ATTR(chunk_size, 0644, chunk_size_show, chunk_size_store); | |||
| 1820 | 1820 | ||
| 1821 | 1821 | ||
| 1822 | static ssize_t | 1822 | static ssize_t |
| 1823 | size_show(mddev_t *mddev, char *page) | ||
| 1824 | { | ||
| 1825 | return sprintf(page, "%llu\n", (unsigned long long)mddev->size); | ||
| 1826 | } | ||
| 1827 | |||
| 1828 | static int update_size(mddev_t *mddev, unsigned long size); | ||
| 1829 | |||
| 1830 | static ssize_t | ||
| 1831 | size_store(mddev_t *mddev, const char *buf, size_t len) | ||
| 1832 | { | ||
| 1833 | /* If array is inactive, we can reduce the component size, but | ||
| 1834 | * not increase it (except from 0). | ||
| 1835 | * If array is active, we can try an on-line resize | ||
| 1836 | */ | ||
| 1837 | char *e; | ||
| 1838 | int err = 0; | ||
| 1839 | unsigned long long size = simple_strtoull(buf, &e, 10); | ||
| 1840 | if (!*buf || *buf == '\n' || | ||
| 1841 | (*e && *e != '\n')) | ||
| 1842 | return -EINVAL; | ||
| 1843 | |||
| 1844 | if (mddev->pers) { | ||
| 1845 | err = update_size(mddev, size); | ||
| 1846 | md_update_sb(mddev); | ||
| 1847 | } else { | ||
| 1848 | if (mddev->size == 0 || | ||
| 1849 | mddev->size > size) | ||
| 1850 | mddev->size = size; | ||
| 1851 | else | ||
| 1852 | err = -ENOSPC; | ||
| 1853 | } | ||
| 1854 | return err ? err : len; | ||
| 1855 | } | ||
| 1856 | |||
| 1857 | static struct md_sysfs_entry md_size = | ||
| 1858 | __ATTR(component_size, 0644, size_show, size_store); | ||
| 1859 | |||
| 1860 | static ssize_t | ||
| 1823 | action_show(mddev_t *mddev, char *page) | 1861 | action_show(mddev_t *mddev, char *page) |
| 1824 | { | 1862 | { |
| 1825 | char *type = "idle"; | 1863 | char *type = "idle"; |
| @@ -1887,6 +1925,7 @@ static struct attribute *md_default_attrs[] = { | |||
| 1887 | &md_level.attr, | 1925 | &md_level.attr, |
| 1888 | &md_raid_disks.attr, | 1926 | &md_raid_disks.attr, |
| 1889 | &md_chunk_size.attr, | 1927 | &md_chunk_size.attr, |
| 1928 | &md_size.attr, | ||
| 1890 | NULL, | 1929 | NULL, |
| 1891 | }; | 1930 | }; |
| 1892 | 1931 | ||
| @@ -3005,6 +3044,54 @@ static int set_array_info(mddev_t * mddev, mdu_array_info_t *info) | |||
| 3005 | return 0; | 3044 | return 0; |
| 3006 | } | 3045 | } |
| 3007 | 3046 | ||
| 3047 | static int update_size(mddev_t *mddev, unsigned long size) | ||
| 3048 | { | ||
| 3049 | mdk_rdev_t * rdev; | ||
| 3050 | int rv; | ||
| 3051 | struct list_head *tmp; | ||
| 3052 | |||
| 3053 | if (mddev->pers->resize == NULL) | ||
| 3054 | return -EINVAL; | ||
| 3055 | /* The "size" is the amount of each device that is used. | ||
| 3056 | * This can only make sense for arrays with redundancy. | ||
| 3057 | * linear and raid0 always use whatever space is available | ||
| 3058 | * We can only consider changing the size if no resync | ||
| 3059 | * or reconstruction is happening, and if the new size | ||
| 3060 | * is acceptable. It must fit before the sb_offset or, | ||
| 3061 | * if that is <data_offset, it must fit before the | ||
| 3062 | * size of each device. | ||
| 3063 | * If size is zero, we find the largest size that fits. | ||
| 3064 | */ | ||
| 3065 | if (mddev->sync_thread) | ||
| 3066 | return -EBUSY; | ||
| 3067 | ITERATE_RDEV(mddev,rdev,tmp) { | ||
| 3068 | sector_t avail; | ||
| 3069 | int fit = (size == 0); | ||
| 3070 | if (rdev->sb_offset > rdev->data_offset) | ||
| 3071 | avail = (rdev->sb_offset*2) - rdev->data_offset; | ||
| 3072 | else | ||
| 3073 | avail = get_capacity(rdev->bdev->bd_disk) | ||
| 3074 | - rdev->data_offset; | ||
| 3075 | if (fit && (size == 0 || size > avail/2)) | ||
| 3076 | size = avail/2; | ||
| 3077 | if (avail < ((sector_t)size << 1)) | ||
| 3078 | return -ENOSPC; | ||
| 3079 | } | ||
| 3080 | rv = mddev->pers->resize(mddev, (sector_t)size *2); | ||
| 3081 | if (!rv) { | ||
| 3082 | struct block_device *bdev; | ||
| 3083 | |||
| 3084 | bdev = bdget_disk(mddev->gendisk, 0); | ||
| 3085 | if (bdev) { | ||
| 3086 | down(&bdev->bd_inode->i_sem); | ||
| 3087 | i_size_write(bdev->bd_inode, mddev->array_size << 10); | ||
| 3088 | up(&bdev->bd_inode->i_sem); | ||
| 3089 | bdput(bdev); | ||
| 3090 | } | ||
| 3091 | } | ||
| 3092 | return rv; | ||
| 3093 | } | ||
| 3094 | |||
| 3008 | /* | 3095 | /* |
| 3009 | * update_array_info is used to change the configuration of an | 3096 | * update_array_info is used to change the configuration of an |
| 3010 | * on-line array. | 3097 | * on-line array. |
| @@ -3053,49 +3140,9 @@ static int update_array_info(mddev_t *mddev, mdu_array_info_t *info) | |||
| 3053 | else | 3140 | else |
| 3054 | return mddev->pers->reconfig(mddev, info->layout, -1); | 3141 | return mddev->pers->reconfig(mddev, info->layout, -1); |
| 3055 | } | 3142 | } |
| 3056 | if (mddev->size != info->size) { | 3143 | if (mddev->size != info->size) |
| 3057 | mdk_rdev_t * rdev; | 3144 | rv = update_size(mddev, info->size); |
| 3058 | struct list_head *tmp; | ||
| 3059 | if (mddev->pers->resize == NULL) | ||
| 3060 | return -EINVAL; | ||
| 3061 | /* The "size" is the amount of each device that is used. | ||
| 3062 | * This can only make sense for arrays with redundancy. | ||
| 3063 | * linear and raid0 always use whatever space is available | ||
| 3064 | * We can only consider changing the size if no resync | ||
| 3065 | * or reconstruction is happening, and if the new size | ||
| 3066 | * is acceptable. It must fit before the sb_offset or, | ||
| 3067 | * if that is <data_offset, it must fit before the | ||
| 3068 | * size of each device. | ||
| 3069 | * If size is zero, we find the largest size that fits. | ||
| 3070 | */ | ||
| 3071 | if (mddev->sync_thread) | ||
| 3072 | return -EBUSY; | ||
| 3073 | ITERATE_RDEV(mddev,rdev,tmp) { | ||
| 3074 | sector_t avail; | ||
| 3075 | int fit = (info->size == 0); | ||
| 3076 | if (rdev->sb_offset > rdev->data_offset) | ||
| 3077 | avail = (rdev->sb_offset*2) - rdev->data_offset; | ||
| 3078 | else | ||
| 3079 | avail = get_capacity(rdev->bdev->bd_disk) | ||
| 3080 | - rdev->data_offset; | ||
| 3081 | if (fit && (info->size == 0 || info->size > avail/2)) | ||
| 3082 | info->size = avail/2; | ||
| 3083 | if (avail < ((sector_t)info->size << 1)) | ||
| 3084 | return -ENOSPC; | ||
| 3085 | } | ||
| 3086 | rv = mddev->pers->resize(mddev, (sector_t)info->size *2); | ||
| 3087 | if (!rv) { | ||
| 3088 | struct block_device *bdev; | ||
| 3089 | 3145 | ||
| 3090 | bdev = bdget_disk(mddev->gendisk, 0); | ||
| 3091 | if (bdev) { | ||
| 3092 | down(&bdev->bd_inode->i_sem); | ||
| 3093 | i_size_write(bdev->bd_inode, mddev->array_size << 10); | ||
| 3094 | up(&bdev->bd_inode->i_sem); | ||
| 3095 | bdput(bdev); | ||
| 3096 | } | ||
| 3097 | } | ||
| 3098 | } | ||
| 3099 | if (mddev->raid_disks != info->raid_disks) { | 3146 | if (mddev->raid_disks != info->raid_disks) { |
| 3100 | /* change the number of raid disks */ | 3147 | /* change the number of raid disks */ |
| 3101 | if (mddev->pers->reshape == NULL) | 3148 | if (mddev->pers->reshape == NULL) |
