Commit a35b0d695d44410eb1734c9abb632725a3138628
Committed by
Linus Torvalds
1 parent
3b34380ae8
[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>
Showing 2 changed files with 98 additions and 42 deletions Side-by-side Diff
Documentation/md.txt
... | ... | @@ -174,6 +174,15 @@ |
174 | 174 | The size should be atleast PAGE_SIZE (4k) and should be a power |
175 | 175 | of 2. This can only be set while assembling an array |
176 | 176 | |
177 | + component_size | |
178 | + For arrays with data redundancy (i.e. not raid0, linear, faulty, | |
179 | + multipath), all components must be the same size - or at least | |
180 | + there must a size that they all provide space for. This is a key | |
181 | + part or the geometry of the array. It is measured in sectors | |
182 | + and can be read from here. Writing to this value may resize | |
183 | + the array if the personality supports it (raid1, raid5, raid6), | |
184 | + and if the component drives are large enough. | |
185 | + | |
177 | 186 | As component devices are added to an md array, they appear in the 'md' |
178 | 187 | directory as new directories named |
179 | 188 | dev-XXX |
drivers/md/md.c
... | ... | @@ -1820,6 +1820,44 @@ |
1820 | 1820 | |
1821 | 1821 | |
1822 | 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 | 1861 | action_show(mddev_t *mddev, char *page) |
1824 | 1862 | { |
1825 | 1863 | char *type = "idle"; |
... | ... | @@ -1887,6 +1925,7 @@ |
1887 | 1925 | &md_level.attr, |
1888 | 1926 | &md_raid_disks.attr, |
1889 | 1927 | &md_chunk_size.attr, |
1928 | + &md_size.attr, | |
1890 | 1929 | NULL, |
1891 | 1930 | }; |
1892 | 1931 | |
... | ... | @@ -3005,6 +3044,54 @@ |
3005 | 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 | 3096 | * update_array_info is used to change the configuration of an |
3010 | 3097 | * on-line array. |
3011 | 3098 | |
... | ... | @@ -3053,49 +3140,9 @@ |
3053 | 3140 | else |
3054 | 3141 | return mddev->pers->reconfig(mddev, info->layout, -1); |
3055 | 3142 | } |
3056 | - if (mddev->size != info->size) { | |
3057 | - mdk_rdev_t * rdev; | |
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; | |
3143 | + if (mddev->size != info->size) | |
3144 | + rv = update_size(mddev, info->size); | |
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 | 3146 | if (mddev->raid_disks != info->raid_disks) { |
3100 | 3147 | /* change the number of raid disks */ |
3101 | 3148 | if (mddev->pers->reshape == NULL) |