diff options
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 9e57e97bd530..d568ab4a487f 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) |