Introduction
Subsystems (2)
PATCH 1/1 Introduction
Following are 20 patches for md/raid in 2.6.15-rc5-mm2
The first 2 are suitable for 2.6.15.
The first fixes a use-after-free bug in raid1 which could only cause problems with using raid1 with some devices in write-behind mode.
The second fixes a carelessness that could result in a deadlock if raid5 stripe_cache_size were set too low.
3 through 8 are assorted minor cleanups or bugfixes only relevant to -mm 9 through 20 add a lot more information about md arrays to sysfs and allow a lot of it to be settable. This will ultimately make it possible to completely configure an md array through sysfs without using the ioctl's at all. This is good because the ioctl's are limited and while I've manage to squeeze some extra functionality out of them, they've reached their limit.
One particular goal I am working towards here is to be able to have an md array where the metadata is completely managed by userspace. A program would read the superblock - fill in the correct information via sysfs, and start the array.
On device failure or other events, userspace gets notified and take necessary action like identifying a spare, passing it to md, and requesting a reconstruction.
This means that e.g. DDF can be supported without adding complexity to the kernel.
Thanks,
NeilBrown
[PATCH md 001 of 20] Fix a use-after-free bug in raid1
[PATCH md 002 of 20] Use correct size of raid5 stripe cache when measuring how full it is. [PATCH md 003 of 20] Define and use safe_put_page for md.
[PATCH md 004 of 20] Helper function to match commands written to sysfs files. [PATCH md 005 of 20] Fix typo in comment.
[PATCH md 006 of 20] Make a couple of names in md.c static
[PATCH md 007 of 20] Make sure bitmap updates are visible through filesystem. [PATCH md 008 of 20] Fix rdev->pending counts in raid1
[PATCH md 009 of 20] Allow chunk_size to be settable through sysfs
[PATCH md 010 of 20] Allow md array component size to be accessed and set via sysfs [PATCH md 011 of 20] Expose md metadata format in sysfs.
[PATCH md 012 of 20] Allow array level to be set textually via sysfs. [PATCH md 013 of 20] Count corrected read errors per drive.
[PATCH md 014 of 20] Allow md/raid_disks to be settable.
[PATCH md 015 of 20] Keep better track of dev/array size when assembling md arrays. [PATCH md 016 of 20] Expose device slot information via sysfs
[PATCH md 017 of 20] Export rdev->data_offset via sysfs
[PATCH md 018 of 20] Allow available size of component devices to be set via sysfs. [PATCH md 019 of 20] Support adding new devices to md arrays via sysfs [PATCH md 020 of 20] Allow sync-speed to be controlled per-device
PATCH 1/1 Fix a use-after-free bug in raid1
Who would submit code with a FIXME like that in it !!!!
### Diffstat output
./drivers/md/raid1.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/md/raid1.c renamed from drivers/md/raid1.c~current~ +3 -2
@@ -323,7 +323,6 @@ static int raid1_end_write_request(struc* this branch is our 'one mirror IO has finished' event handler: */ r1_bio->bios[mirror] =NULL ; -bio_put (bio);if (!uptodate) {md_error (r1_bio->mddev, conf->mirrors[mirror].rdev);/* an I/O failed, we can't clear the bitmap */
@@ -380,7 +379,6 @@ static int raid1_end_write_request(struc }if (test_bit (R1BIO_BehindIO, &r1_bio->state)) {/* free extra copy of the data pages */ -/* FIXME bio has been freed!!! */ int i = bio->bi_vcnt;while (i--)put_page (bio->bi_io_vec[i].bv_page);
@@ -394,6 +392,9 @@ static int raid1_end_write_request(strucraid_end_bio_io (r1_bio); } +if (r1_bio->bios[mirror]==NULL ) +bio_put (bio); +rdev_dec_pending (conf->mirrors[mirror].rdev, conf->mddev);return 0 ; }
PATCH 1/1 Use correct size of raid5 stripe cache when measuring how full it is.
In reply to NeilBrownThe raid5 stripe cache was recently changed from fixed size (NR_STRIPES) to variable size (conf->max_nr_stripes). However there are two places that still use the constant and as a result, reducing the size of the stripe cache can result in a deadlock.
### Diffstat output
./drivers/md/raid5.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/md/raid5.c renamed from drivers/md/raid5.c~current~ +4 -3
@@ -96,7 +96,7 @@ static inline void __release_stripe(raidlist_add_tail (&sh->lru, &conf->inactive_list);atomic_dec (&conf->active_stripes);if (!conf->inactive_blocked || -atomic_read (&conf->active_stripes) < (NR_STRIPES *3 /4 )) +atomic_read (&conf->active_stripes) < (conf->max_nr_stripes*3 /4 ))wake_up (&conf->wait_for_stripe); } }
@@ -255,7 +255,8 @@ static struct stripe_head *get_active_st conf->inactive_blocked =1 ;wait_event_lock_irq (conf->wait_for_stripe, !list_empty (&conf->inactive_list) && - (atomic_read (&conf->active_stripes) < (NR_STRIPES *3 /4 ) + (atomic_read (&conf->active_stripes) + < (conf->max_nr_stripes *3 /4 ) || !conf->inactive_blocked), conf->device_lock, unplug_slaves(conf->mddev);
@@ -1915,7 +1916,7 @@ static int run(mddev_t *mddev) goto abort; } } -memory = conf->max_nr_stripes * (sizeof (struct stripe_head ) + + memory = conf->max_nr_stripes * (sizeof (struct stripe_head ) + conf->raid_disks * ((sizeof (struct bio ) +PAGE_SIZE ))) /1024 ;if (grow_stripes (conf, conf->max_nr_stripes)) { printk(KERN_ERR
PATCH 1/1 Define and use safe_put_page for md.
In reply to NeilBrownmd sometimes call put_page on NULL pointers (treating it like kfree). This is not safe, so define and use a 'safe_put_page' which checks for NULL.
### Diffstat output
./drivers/md/bitmap.c | 3 +-- ./drivers/md/raid1.c | 8 ++++---- ./drivers/md/raid10.c | 8 ++++---- ./drivers/md/raid6main.c | 3 +-- ./include/linux/raid/md_k.h | 5 +++++ 5 files changed, 15 insertions(+), 12 deletions(-)
drivers/md/bitmap.c renamed from drivers/md/bitmap.c~current~ +1 -2
@@ -626,8 +626,7 @@ static void bitmap_file_unmap(struct bitkfree (map);kfree (attr); -if (sb_page) -put_page (sb_page); +safe_put_page (sb_page); }static void bitmap_stop_daemon (struct bitmap *bitmap);
drivers/md/raid1.c renamed from drivers/md/raid1.c~current~ +4 -4
@@ -136,7 +136,7 @@ static void * r1buf_pool_alloc(gfp_t gfp out_free_pages:for (i=0 ; i <RESYNC_PAGES ; i++)for (j=0 ; j < pi->raid_disks; j++) -put_page (r1_bio->bios[j]->bi_io_vec[i].bv_page); +safe_put_page (r1_bio->bios[j]->bi_io_vec[i].bv_page); j =-1 ; out_free_bio:while ( ++j < pi->raid_disks )
@@ -156,7 +156,7 @@ static void r1buf_pool_free(void *__r1_bif (j ==0 || r1bio->bios[j]->bi_io_vec[i].bv_page != r1bio->bios[0 ]->bi_io_vec[i].bv_page) -put_page (r1bio->bios[j]->bi_io_vec[i].bv_page); +safe_put_page (r1bio->bios[j]->bi_io_vec[i].bv_page); }for (i=0 ; i < pi->raid_disks; i++)bio_put (r1bio->bios[i]);
@@ -381,7 +381,7 @@ static int raid1_end_write_request(struc/* free extra copy of the data pages */ int i = bio->bi_vcnt;while (i--) -put_page (bio->bi_io_vec[i].bv_page); +safe_put_page (bio->bi_io_vec[i].bv_page); }/* clear the bitmap if all writes complete successfully */ bitmap_endwrite(r1_bio->mddev->bitmap, r1_bio->sector,
@@ -1907,7 +1907,7 @@ out_free_conf:if (conf->r1bio_pool)mempool_destroy (conf->r1bio_pool);kfree (conf->mirrors); -put_page (conf->tmppage); +safe_put_page (conf->tmppage);kfree (conf->poolinfo);kfree (conf); mddev->private =NULL ;
drivers/md/raid10.c renamed from drivers/md/raid10.c~current~ +4 -4
@@ -132,10 +132,10 @@ static void * r10buf_pool_alloc(gfp_t gf out_free_pages:for ( ; i >0 ; i--) -put_page (bio->bi_io_vec[i-1 ].bv_page); +safe_put_page (bio->bi_io_vec[i-1 ].bv_page);while (j--)for (i =0 ; i <RESYNC_PAGES ; i++) -put_page (r10_bio->devs[j].bio->bi_io_vec[i].bv_page); +safe_put_page (r10_bio->devs[j].bio->bi_io_vec[i].bv_page); j =-1 ; out_free_bio:while ( ++j < nalloc )
@@ -155,7 +155,7 @@ static void r10buf_pool_free(void *__r10struct bio *bio = r10bio->devs[j].bio;if (bio) {for (i =0 ; i <RESYNC_PAGES ; i++) { -put_page (bio->bi_io_vec[i].bv_page); +safe_put_page (bio->bi_io_vec[i].bv_page); bio->bi_io_vec[i].bv_page =NULL ; }bio_put (bio);
@@ -2042,7 +2042,7 @@ static int run(mddev_t *mddev) out_free_conf:if (conf->r10bio_pool)mempool_destroy (conf->r10bio_pool); -put_page (conf->tmppage); +safe_put_page (conf->tmppage);kfree (conf->mirrors);kfree (conf); mddev->private =NULL ;
drivers/md/raid6main.c renamed from drivers/md/raid6main.c~current~ +1 -2
@@ -2072,8 +2072,7 @@ static int run(mddev_t *mddev) abort:if (conf) {print_raid6_conf (conf); -if (conf->spare_page) -put_page (conf->spare_page); +safe_put_page (conf->spare_page);kfree (conf->stripe_hashtbl);kfree (conf); }
include/linux/raid/md_k.h renamed from include/linux/raid/md_k.h~current~ +5 -0
@@ -324,5 +324,10 @@ do { \__wait_event_lock_irq (wq, condition, lock, cmd); \ } while (0) +static inline void safe_put_page(struct page *p) +{ +if (p)put_page (p); +} +#endif
PATCH 1/1 Helper function to match commands written to sysfs files.
In reply to NeilBrownCommands written to sysfs files may, or my not, be \n terminated. We want to accept with case. For this we use cmd_match.
### Diffstat output
./drivers/md/md.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-)
drivers/md/md.c renamed from drivers/md/md.c~current~ +24 -5
@@ -1525,6 +1525,26 @@ repeat: } +/* words written to sysfs files may, or my not, be \n terminated. +* We want to accept with case. For this we use cmd_match. +*/ +static int cmd_match (const char *cmd,const char *str) +{ +/* See if cmd, written into a sysfs file, matches +* str. They must either be the same, or cmd can +* have a trailing newline +*/ +while (*cmd && *str && *cmd == *str) { + cmd++; + str++; + } +if (*cmd =='\n' ) + cmd++; +if (*str || *cmd) +return 0 ; +return 1 ; +} +struct rdev_sysfs_entry {struct attribute attr;ssize_t (*show)(mdk_rdev_t *,char *);
@@ -1799,7 +1819,7 @@ action_store(mddev_t *mddev, const charif (!mddev->pers || !mddev->pers->sync_request)return -EINVAL ; -if (strcmp (page,"idle" )==0 ||strcmp (page,"idle\n" )==0 ) { +if (cmd_match (page,"idle" )) {if (mddev->sync_thread) {set_bit (MD_RECOVERY_INTR , &mddev->recovery);md_unregister_thread (mddev->sync_thread);
@@ -1812,13 +1832,12 @@ action_store(mddev_t *mddev, const charif (test_bit (MD_RECOVERY_RUNNING , &mddev->recovery) ||test_bit (MD_RECOVERY_NEEDED , &mddev->recovery))return -EBUSY ; -if (strcmp (page,"resync" )==0 ||strcmp (page,"resync\n" )==0 || -strcmp (page,"recover" )==0 ||strcmp (page,"recover\n" )==0 ) +if (cmd_match (page,"resync" ) ||cmd_match (page,"recover" ))set_bit (MD_RECOVERY_NEEDED , &mddev->recovery);else { -if (strcmp (page,"check" )==0 ||strcmp (page,"check\n" )==0 ) +if (cmd_match (page,"check" ))set_bit (MD_RECOVERY_CHECK , &mddev->recovery); -else if (strcmp (page,"repair" )!=0 &&strcmp (page,"repair\n" )!=0 ) +else if (cmd_match (page,"repair" ))return -EINVAL ;set_bit (MD_RECOVERY_REQUESTED , &mddev->recovery);set_bit (MD_RECOVERY_SYNC , &mddev->recovery);
PATCH 1/1 Fix typo in comment.
In reply to NeilBrown### Diffstat output
./drivers/md/raid10.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/md/raid10.c renamed from drivers/md/raid10.c~current~ +1 -1
@@ -712,7 +712,7 @@ static void allow_barrier(conf_t *conf)static void freeze_array (conf_t *conf) {/* stop syncio and normal IO and wait for everything to -* go quite. +* go quiet. * We increment barrier and nr_waiting, and then * wait until barrier+nr_pending match nr_queued+2 */
PATCH 1/1 Make a couple of names in md.c static
In reply to NeilBrown.. because they aren't used outside md.c
### Diffstat output
./drivers/md/md.c | 4 ++-- ./include/linux/raid/md_k.h | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-)
drivers/md/md.c renamed from drivers/md/md.c~current~ +2 -2
@@ -144,7 +144,7 @@ static int start_readonly;* start array, stop array, error, add device, remove device, * start build, activate spare */ -DECLARE_WAIT_QUEUE_HEAD (md_event_waiters); +static DECLARE_WAIT_QUEUE_HEAD (md_event_waiters);static atomic_t md_event_count;void md_new_event (mddev_t *mddev) {
@@ -279,7 +279,7 @@ static inline void mddev_unlock(mddev_tmd_wakeup_thread (mddev->thread); } -mdk_rdev_t *find_rdev_nr (mddev_t *mddev,int nr) +static mdk_rdev_t *find_rdev_nr (mddev_t *mddev,int nr) {mdk_rdev_t * rdev;struct list_head *tmp;
include/linux/raid/md_k.h renamed from include/linux/raid/md_k.h~current~ +0 -2
@@ -263,8 +263,6 @@ static inline char * mdname (mddev_t * mreturn mddev->gendisk ? mddev->gendisk->disk_name :"mdX" ; } -extern mdk_rdev_t *find_rdev_nr (mddev_t *mddev,int nr); -/* * iterates through some rdev ringlist. It's safe to remove the * current 'rdev'. Dont touch 'tmp' though.
PATCH 1/1 Make sure bitmap updates are visible through filesystem.
In reply to NeilBrownWhen we update a page_cache page in the kernel, we need to flush_dache_page or userspace might not see the change.
### Diffstat output
./drivers/md/bitmap.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/md/bitmap.c renamed from drivers/md/bitmap.c~current~ +2 -0
@@ -315,6 +315,8 @@ static int write_page(struct bitmap *bitif (bitmap->file ==NULL )return write_sb_page (bitmap->mddev, bitmap->offset, page, wait); +flush_dcache_page (page);/* make sure visible to anyone reading the file */ +if (wait)lock_page (page);else {
PATCH 1/1 Fix rdev->pending counts in raid1
In reply to NeilBrownWhen we do a user-requested check/repair, we lose count of the outstanding requests...
Also make sure that when anything is written to md/sync_action, the RECOVERY_NEEDED flag is set and the thread is woken up so any changes take effect.
### Diffstat output
./drivers/md/md.c | 11 ++++------- ./drivers/md/raid1.c | 10 ++++++---- 2 files changed, 10 insertions(+), 11 deletions(-)
drivers/md/md.c renamed from drivers/md/md.c~current~ +4 -7
@@ -1826,13 +1826,10 @@ action_store(mddev_t *mddev, const char mddev->sync_thread =NULL ; mddev->recovery =0 ; } -return len; - } - -if (test_bit (MD_RECOVERY_RUNNING , &mddev->recovery) || -test_bit (MD_RECOVERY_NEEDED , &mddev->recovery)) + }else if (test_bit (MD_RECOVERY_RUNNING , &mddev->recovery) || +test_bit (MD_RECOVERY_NEEDED , &mddev->recovery))return -EBUSY ; -if (cmd_match (page,"resync" ) ||cmd_match (page,"recover" )) +else if (cmd_match (page,"resync" ) ||cmd_match (page,"recover" ))set_bit (MD_RECOVERY_NEEDED , &mddev->recovery);else {if (cmd_match (page,"check" ))
@@ -1841,8 +1838,8 @@ action_store(mddev_t *mddev, const charreturn -EINVAL ;set_bit (MD_RECOVERY_REQUESTED , &mddev->recovery);set_bit (MD_RECOVERY_SYNC , &mddev->recovery); -set_bit (MD_RECOVERY_NEEDED , &mddev->recovery); } +set_bit (MD_RECOVERY_NEEDED , &mddev->recovery);md_wakeup_thread (mddev->thread);return len; }
drivers/md/raid1.c renamed from drivers/md/raid1.c~current~ +6 -4
@@ -527,7 +527,7 @@ static int read_balance(conf_t *conf, r1/* cannot risk returning a device that failed * before we inc'ed nr_pending */ -atomic_dec (&rdev->nr_pending); +rdev_dec_pending (rdev, conf->mddev); goto retry; } conf->next_seq_sect = this_sector + sectors;
@@ -830,7 +830,7 @@ static int make_request(request_queue_t !test_bit(Faulty, &rdev->flags)) {atomic_inc (&rdev->nr_pending);if (test_bit (Faulty, &rdev->flags)) { -atomic_dec (&rdev->nr_pending); +rdev_dec_pending (rdev, mddev); r1_bio->bios[i] =NULL ; }else r1_bio->bios[i] = bio;
@@ -1176,6 +1176,7 @@ static void sync_request_write(mddev_t *if (r1_bio->bios[primary]->bi_end_io == end_sync_read &&test_bit (BIO_UPTODATE , &r1_bio->bios[primary]->bi_flags)) { r1_bio->bios[primary]->bi_end_io =NULL ; +rdev_dec_pending (conf->mirrors[primary].rdev, mddev);break ; } r1_bio->read_disk = primary;
@@ -1193,9 +1194,10 @@ static void sync_request_write(mddev_t *break ;if (j >=0 ) mddev->resync_mismatches += r1_bio->sectors; -if (j <0 ||test_bit (MD_RECOVERY_CHECK , &mddev->recovery)) +if (j <0 ||test_bit (MD_RECOVERY_CHECK , &mddev->recovery)) { sbio->bi_end_io =NULL ; -else { +rdev_dec_pending (conf->mirrors[i].rdev, mddev); + }else {/* fixup the bio for reuse */ sbio->bi_vcnt = vcnt; sbio->bi_size = r1_bio->sectors <<9 ;
PATCH 1/1 Allow chunk_size to be settable through sysfs
In reply to NeilBrown... only before array is started of course.
### Diffstat output
./Documentation/md.txt | 8 ++++++++ ./drivers/md/md.c | 26 ++++++++++++++++++++++++++ 2 files changed, 34 insertions(+)
Documentation/md.txt renamed from Documentation/md.txt~current~ +8 -0
@@ -166,6 +166,14 @@ All md devices contain: will be empty. If an array is being resized (not currently possible) this will contain the larger of the old and new sizes. + chunk_size + This is the size if bytes for 'chunks' and is only relevant to + raid levels that involve striping (1,4,5,6,10). The address space + of the array is conceptually divided into chunks and consecutive + chunks are striped onto neighbouring devices. + The size should be atleast PAGE_SIZE (4k) and should be a power + of 2. This can only be set while assembling an array + As component devices are added to an md array, they appear in the 'md' directory as new directories named dev-XXX
drivers/md/md.c renamed from drivers/md/md.c~current~ +26 -0
@@ -1795,6 +1795,31 @@ raid_disks_show(mddev_t *mddev, char *pastatic struct md_sysfs_entry md_raid_disks =__ATTR_RO (raid_disks);static ssize_t +chunk_size_show (mddev_t *mddev,char *page) +{ +return sprintf (page,"%d\n" , mddev->chunk_size); +} + +static ssize_t +chunk_size_store (mddev_t *mddev,const char *buf,size_t len) +{ +/* can only set chunk_size if array is not yet active */ +char *e; +unsigned long n =simple_strtoul (buf, &e,10 ); + +if (mddev->pers) +return -EBUSY ; +if (!*buf || (*e && *e !='\n' )) +return -EINVAL ; + + mddev->chunk_size = n; +return len; +} +static struct md_sysfs_entry md_chunk_size = +__ATTR (chunk_size,0644 , chunk_size_show, chunk_size_store); + + +static ssize_t action_show (mddev_t *mddev,char *page) {char *type ="idle" ;
@@ -1861,6 +1886,7 @@ md_mismatches = __ATTR_RO(mismatch_cnt);static struct attribute *md_default_attrs[] = { &md_level.attr, &md_raid_disks.attr, + &md_chunk_size.attr,NULL , };
PATCH 1/1 Allow md array component size to be accessed and set via sysfs
In reply to NeilBrown### Diffstat output
./Documentation/md.txt | 9 +++ ./drivers/md/md.c | 131 +++++++++++++++++++++++++++++++++---------------- 2 files changed, 98 insertions(+), 42 deletions(-)
Documentation/md.txt renamed from Documentation/md.txt~current~ +9 -0
@@ -174,6 +174,15 @@ All md devices contain: The size should be atleast PAGE_SIZE (4k) and should be a power of 2. This can only be set while assembling an array + component_size + For arrays with data redundancy (i.e. not raid0, linear, faulty, + multipath), all components must be the same size - or at least + there must a size that they all provide space for. This is a key + part or the geometry of the array. It is measured in sectors + and can be read from here. Writing to this value may resize + the array if the personality supports it (raid1, raid5, raid6), + and if the component drives are large enough. + As component devices are added to an md array, they appear in the 'md' directory as new directories named dev-XXX
drivers/md/md.c renamed from drivers/md/md.c~current~ +89 -42
156 lines not on this page · raw message
PATCH 1/1 Expose md metadata format in sysfs.
In reply to NeilBrownAllow it to be set to a particular version, or 'none'.
### Diffstat output
./Documentation/md.txt | 6 ++++++ ./drivers/md/md.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+)
Documentation/md.txt renamed from Documentation/md.txt~current~ +6 -0
@@ -183,6 +183,12 @@ All md devices contain: the array if the personality supports it (raid1, raid5, raid6), and if the component drives are large enough. + metadata_version + This indicates the format that is being used to record metadata + about the array. It can be 0.90 (traditional format), 1.0, 1.1, + 1.2 (newer format in varying locations) or "none" indicating that + the kernel isn't managing metadata at all. + As component devices are added to an md array, they appear in the 'md' directory as new directories named dev-XXX
drivers/md/md.c renamed from drivers/md/md.c~current~ +49 -0
61 lines not on this page · raw message
PATCH 1/1 Allow array level to be set textually via sysfs.
In reply to NeilBrown### Diffstat output
./Documentation/md.txt | 8 +++++ ./drivers/md/faulty.c | 1 ./drivers/md/linear.c | 3 +- ./drivers/md/md.c | 61 ++++++++++++++++++++++++++++++++++---------- ./drivers/md/multipath.c | 1 ./drivers/md/raid0.c | 1 ./drivers/md/raid1.c | 1 ./drivers/md/raid10.c | 1 ./drivers/md/raid5.c | 2 + ./drivers/md/raid6main.c | 1 ./include/linux/raid/md_k.h | 1 11 files changed, 67 insertions(+), 14 deletions(-)
Documentation/md.txt renamed from Documentation/md.txt~current~ +8 -0
@@ -189,6 +189,14 @@ All md devices contain: 1.2 (newer format in varying locations) or "none" indicating that the kernel isn't managing metadata at all. + level + The raid 'level' for this array. The name will often (but not + always) be the same as the name of the module that implements the + level. To be auto-loaded the module must have an alias + md-$LEVEL e.g. md-raid5 + This can be written only while the array is being assembled, not + after it is started. + As component devices are added to an md array, they appear in the 'md' directory as new directories named dev-XXX
drivers/md/faulty.c renamed from drivers/md/faulty.c~current~ +1 -0
@@ -342,4 +342,5 @@ module_init(raid_init);module_exit (raid_exit);MODULE_LICENSE ("GPL" );MODULE_ALIAS ("md-personality-10" );/* faulty */ +MODULE_ALIAS ("md-faulty" );MODULE_ALIAS ("md-level--5" );
drivers/md/linear.c renamed from drivers/md/linear.c~current~ +2 -1
@@ -376,5 +376,6 @@ static void linear_exit (void)module_init (linear_init);module_exit (linear_exit);MODULE_LICENSE ("GPL" ); -MODULE_ALIAS ("md-personality-1" );/* LINEAR - degrecated*/ +MODULE_ALIAS ("md-personality-1" );/* LINEAR - deprecated*/ +MODULE_ALIAS ("md-linear" );MODULE_ALIAS ("md-level--1" );
drivers/md/md.c renamed from drivers/md/md.c~current~ +48 -13
109 lines not on this page · raw message
drivers/md/multipath.c renamed from drivers/md/multipath.c~current~ +1 -0
@@ -579,4 +579,5 @@ module_init(multipath_init);module_exit (multipath_exit);MODULE_LICENSE ("GPL" );MODULE_ALIAS ("md-personality-7" );/* MULTIPATH */ +MODULE_ALIAS ("md-multipath" );MODULE_ALIAS ("md-level--4" );
drivers/md/raid0.c renamed from drivers/md/raid0.c~current~ +1 -0
@@ -536,4 +536,5 @@ module_init(raid0_init);module_exit (raid0_exit);MODULE_LICENSE ("GPL" );MODULE_ALIAS ("md-personality-2" );/* RAID0 */ +MODULE_ALIAS ("md-raid0" );MODULE_ALIAS ("md-level-0" );
drivers/md/raid1.c renamed from drivers/md/raid1.c~current~ +1 -0
@@ -2092,4 +2092,5 @@ module_init(raid_init);module_exit (raid_exit);MODULE_LICENSE ("GPL" );MODULE_ALIAS ("md-personality-3" );/* RAID1 */ +MODULE_ALIAS ("md-raid1" );MODULE_ALIAS ("md-level-1" );
drivers/md/raid10.c renamed from drivers/md/raid10.c~current~ +1 -0
@@ -2117,4 +2117,5 @@ module_init(raid_init);module_exit (raid_exit);MODULE_LICENSE ("GPL" );MODULE_ALIAS ("md-personality-9" );/* RAID10 */ +MODULE_ALIAS ("md-raid10" );MODULE_ALIAS ("md-level-10" );
drivers/md/raid5.c renamed from drivers/md/raid5.c~current~ +2 -0
@@ -2240,5 +2240,7 @@ module_init(raid5_init);module_exit (raid5_exit);MODULE_LICENSE ("GPL" );MODULE_ALIAS ("md-personality-4" );/* RAID5 */ +MODULE_ALIAS ("md-raid5" ); +MODULE_ALIAS ("md-raid4" );MODULE_ALIAS ("md-level-5" );MODULE_ALIAS ("md-level-4" );
drivers/md/raid6main.c renamed from drivers/md/raid6main.c~current~ +1 -0
@@ -2341,4 +2341,5 @@ module_init(raid6_init);module_exit (raid6_exit);MODULE_LICENSE ("GPL" );MODULE_ALIAS ("md-personality-8" );/* RAID6 */ +MODULE_ALIAS ("md-raid6" );MODULE_ALIAS ("md-level-6" );
include/linux/raid/md_k.h renamed from include/linux/raid/md_k.h~current~ +1 -0
@@ -119,6 +119,7 @@ struct mddev_sint chunk_size;time_t ctime, utime;int level, layout; +char clevel[16 ];int raid_disks;int max_disks;sector_t size;/* used size of component devices */
PATCH 1/1 Count corrected read errors per drive.
In reply to NeilBrownStore this total in superblock (As appropriate),
and make it available to userspace via sysfs.
### Diffstat output
./Documentation/md.txt | 11 +++++++++++ ./drivers/md/md.c | 27 ++++++++++++++++++++++++++- ./drivers/md/raid1.c | 2 ++ ./drivers/md/raid10.c | 11 ++++++++--- ./drivers/md/raid5.c | 3 +++ ./drivers/md/raid6main.c | 3 +++ ./include/linux/raid/md_k.h | 4 ++++ 7 files changed, 57 insertions(+), 4 deletions(-)
Documentation/md.txt renamed from Documentation/md.txt~current~ +11 -0
@@ -222,6 +222,17 @@ Each directory contains: of being recoverred to This list make grow in future. + errors + An approximate count of read errors that have been detected on + this device but have not caused the device to be evicted from + the array (either because they were corrected or because they + happened while the array was read-only). When using version-1 + metadata, this value persists across restarts of the array. + + This value can be written while assembling an array thus + providing an ongoing count for arrays with metadata managed by + userspace. + An active md device will also contain and entry for each active device in the array. These are named
drivers/md/md.c renamed from drivers/md/md.c~current~ +26 -1
@@ -1000,6 +1000,7 @@ static int super_1_load(mdk_rdev_t *rdev } rdev->preferred_minor =0xffff ; rdev->data_offset =le64_to_cpu (sb->data_offset); +atomic_set (&rdev->corrected_errors,le32_to_cpu (sb->cnt_corrected_read)); rdev->sb_size =le32_to_cpu (sb->max_dev) *2 +256 ; bmask =queue_hardsect_size (rdev->bdev->bd_disk->queue)-1 ;
@@ -1139,6 +1140,8 @@ static void super_1_sync(mddev_t *mddev,else sb->resync_offset =cpu_to_le64 (0 ); + sb->cnt_corrected_read =atomic_read (&rdev->corrected_errors); +if (mddev->bitmap && mddev->bitmap_file ==NULL ) { sb->bitmap_offset =cpu_to_le32 ((__u32 )mddev->bitmap_offset); sb->feature_map =cpu_to_le32 (MD_FEATURE_BITMAP_OFFSET );
@@ -1592,9 +1595,30 @@ super_show(mdk_rdev_t *rdev, char *page) }static struct rdev_sysfs_entry rdev_super =__ATTR_RO (super); +static ssize_t +errors_show (mdk_rdev_t *rdev,char *page) +{ +return sprintf (page,"%d\n" ,atomic_read (&rdev->corrected_errors)); +} + +static ssize_t +errors_store (mdk_rdev_t *rdev,const char *buf,size_t len) +{ +char *e; +unsigned long n =simple_strtoul (buf, &e,10 ); +if (*buf && (*e ==0 || *e =='\n' )) { +atomic_set (&rdev->corrected_errors, n); +return len; + } +return -EINVAL ; +} +static struct rdev_sysfs_entry rdev_errors = +__ATTR (errors,0644 , errors_show, errors_store); +static struct attribute *rdev_default_attrs[] = { &rdev_state.attr, &rdev_super.attr, + &rdev_errors.attr,NULL , }; static ssize_t
@@ -1674,6 +1698,7 @@ static mdk_rdev_t *md_import_device(dev_ rdev->data_offset =0 ;atomic_set (&rdev->nr_pending,0 );atomic_set (&rdev->read_errors,0 ); +atomic_set (&rdev->corrected_errors,0 ); size = rdev->bdev->bd_inode->i_size >>BLOCK_SIZE_BITS ;if (!size) {
@@ -4721,7 +4746,7 @@ static int set_ro(const char *val, strucint num =simple_strtoul (val, &e,10 );if (*val && (*e =='\0' || *e =='\n' )) { start_readonly = num; -return 0 ;; +return 0 ; }return -EINVAL ; }
drivers/md/raid1.c renamed from drivers/md/raid1.c~current~ +2 -0
@@ -1265,6 +1265,7 @@ static void sync_request_write(mddev_t *if (r1_bio->bios[d]->bi_end_io != end_sync_read)continue ; rdev = conf->mirrors[d].rdev; +atomic_add (s, &rdev->corrected_errors); if (sync_page_io(rdev->bdev, sect + rdev->data_offset, s<<9,
@@ -1463,6 +1464,7 @@ static void raid1d(mddev_t *mddev) d = conf->raid_disks; d--; rdev = conf->mirrors[d].rdev; +atomic_add (s, &rdev->corrected_errors);if (rdev &&test_bit (In_sync, &rdev->flags)) { if (sync_page_io(rdev->bdev,
drivers/md/raid10.c renamed from drivers/md/raid10.c~current~ +8 -3
@@ -1122,9 +1122,13 @@ static int end_sync_read(struct bio *bioif (test_bit (BIO_UPTODATE , &bio->bi_flags))set_bit (R10BIO_Uptodate, &r10_bio->state); -else if (!test_bit (MD_RECOVERY_SYNC , &conf->mddev->recovery)) -md_error (r10_bio->mddev, - conf->mirrors[d].rdev); +else { +atomic_add (r10_bio->sectors, + &conf->mirrors[d].rdev->corrected_errors); +if (!test_bit (MD_RECOVERY_SYNC , &conf->mddev->recovery)) +md_error (r10_bio->mddev, + conf->mirrors[d].rdev); + }/* for reconstruct, we always reschedule after a read. * for resync, only after all reads
@@ -1430,6 +1434,7 @@ static void raid10d(mddev_t *mddev) sl--; d = r10_bio->devs[sl].devnum; rdev = conf->mirrors[d].rdev; +atomic_add (s, &rdev->corrected_errors);if (rdev &&test_bit (In_sync, &rdev->flags)) { if (sync_page_io(rdev->bdev,
drivers/md/raid5.c renamed from drivers/md/raid5.c~current~ +3 -0
@@ -1400,6 +1400,9 @@ static void handle_stripe(struct stripe_ bi->bi_io_vec[0 ].bv_offset =0 ; bi->bi_size =STRIPE_SIZE ; bi->bi_next =NULL ; +if (rw ==WRITE && +test_bit (R5_ReWrite, &sh->dev[i].flags)) +atomic_add (STRIPE_SECTORS , &rdev->corrected_errors);generic_make_request (bi); }else {if (rw ==1 )
drivers/md/raid6main.c renamed from drivers/md/raid6main.c~current~ +3 -0
@@ -1562,6 +1562,9 @@ static void handle_stripe(struct stripe_ bi->bi_io_vec[0 ].bv_offset =0 ; bi->bi_size =STRIPE_SIZE ; bi->bi_next =NULL ; +if (rw ==WRITE && +test_bit (R5_ReWrite, &sh->dev[i].flags)) +atomic_add (STRIPE_SECTORS , &rdev->corrected_errors);generic_make_request (bi); }else {if (rw ==1 )
include/linux/raid/md_k.h renamed from include/linux/raid/md_k.h~current~ +4 -0
@@ -95,6 +95,10 @@ struct mdk_rdev_satomic_t read_errors;/* number of consecutive read errors that * we have tried to ignore. */ +atomic_t corrected_errors;/* number of corrected read errors, +* for reporting to userspace and storing +* in superblock. +*/ };struct mddev_s
Re: [PATCH md 013 of 20] Count corrected read errors per drive.
Quoted 7 lines · NeilBrown
+ errors
+ An approximate count of read errors that have been detected on + this device but have not caused the device to be evicted from + the array (either because they were corrected or because they+ happened while the array was read-only). When using version-1
+ metadata, this value persists across restarts of the array.
Looks funny. Mixture of tabs and spaces I guess.
<fixes it>
PATCH 1/1 Allow md/raid_disks to be settable.
In reply to NeilBrownIf array is active, try to reshape, else just set the value.
### Diffstat output
./Documentation/md.txt | 3 + ./drivers/md/md.c | 74 +++++++++++++++++++++++++++++++++---------------- 2 files changed, 54 insertions(+), 23 deletions(-)
Documentation/md.txt renamed from Documentation/md.txt~current~ +3 -0
@@ -165,6 +165,9 @@ All md devices contain: in a fully functional array. If this is not yet known, the file will be empty. If an array is being resized (not currently possible) this will contain the larger of the old and new sizes. + Some raid level (RAID1) allow this value to be set while the + array is active. This will reconfigure the array. Otherwise + it can only be set while assembling an array. chunk_size This is the size if bytes for 'chunks' and is only relevant to
drivers/md/md.c renamed from drivers/md/md.c~current~ +51 -23
92 lines not on this page · raw message
PATCH 1/1 Keep better track of dev/array size when assembling md arrays.
In reply to NeilBrownMove the checks - that dev size is never less than array size - into bind_rdev_to_array to make sure it always happens properly (there is one place where currently it doesn't).
Also reject any superblock which claims an array size smaller than the device in question can hold.
### Diffstat output
./drivers/md/md.c | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-)
drivers/md/md.c renamed from drivers/md/md.c~current~ +23 -18
@@ -695,6 +695,10 @@ static int super_90_load(mdk_rdev_t *rde } rdev->size =calc_dev_size (rdev, sb->chunk_size); +if (rdev->size < sb->size && sb->level >1 ) +/* "this cannot possibly happen" ... */ + ret = -EINVAL ; + abort:return ret; }
@@ -1039,6 +1043,9 @@ static int super_1_load(mdk_rdev_t *rdev rdev->size =le64_to_cpu (sb->data_size)/2 ;if (le32_to_cpu (sb->chunksize)) rdev->size &= ~((sector_t )le32_to_cpu (sb->chunksize)/2 -1 ); + +if (le32_to_cpu (sb->size) > rdev->size*2 ) +return -EINVAL ;return 0 ; }
@@ -1224,6 +1231,14 @@ static int bind_rdev_to_array(mdk_rdev_tMD_BUG ();return -EINVAL ; } +/* make sure rdev->size exceeds mddev->size */ +if (rdev->size && (mddev->size ==0 || rdev->size < mddev->size)) { +if (mddev->pers) +/* Cannot change size, so fail */ +return -ENOSPC ; +else + mddev->size = rdev->size; + } same_pdev =match_dev_unit (mddev, rdev);if (same_pdev) printk(KERN_WARNING
@@ -2898,12 +2913,6 @@ static int add_new_disk(mddev_t * mddev,if (info->state & (1 <<MD_DISK_WRITEMOSTLY ))set_bit (WriteMostly, &rdev->flags); - err =bind_rdev_to_array (rdev, mddev); -if (err) { -export_rdev (rdev); -return err; - } -if (!mddev->persistent) {printk (KERN_INFO "md: nonpersistent superblock ...\n" ); rdev->sb_offset = rdev->bdev->bd_inode->i_size >>BLOCK_SIZE_BITS ;
@@ -2911,8 +2920,11 @@ static int add_new_disk(mddev_t * mddev, rdev->sb_offset =calc_dev_sboffset (rdev->bdev); rdev->size =calc_dev_size (rdev, mddev->chunk_size); -if (!mddev->size || (mddev->size > rdev->size)) - mddev->size = rdev->size; + err =bind_rdev_to_array (rdev, mddev); +if (err) { +export_rdev (rdev); +return err; + } }return 0 ;
@@ -2984,15 +2996,6 @@ static int hot_add_disk(mddev_t * mddev, size =calc_dev_size (rdev, mddev->chunk_size); rdev->size = size; -if (size < mddev->size) { -printk (KERN_WARNING -"%s: disk size %llu blocks < array size %llu\n" , -mdname (mddev), (unsigned long long )size, - (unsigned long long )mddev->size); - err = -ENOSPC ; - goto abort_export; - } -if (test_bit (Faulty, &rdev->flags)) { printk(KERN_WARNING "md: can not hot-add faulty %s disk to %s!\n",
@@ -3002,7 +3005,9 @@ static int hot_add_disk(mddev_t * mddev, }clear_bit (In_sync, &rdev->flags); rdev->desc_nr =-1 ; -bind_rdev_to_array (rdev, mddev); + err =bind_rdev_to_array (rdev, mddev); +if (err) + goto abort_export;/* * The rest should better be atomic, we can have disk failures
PATCH 1/1 Expose device slot information via sysfs
In reply to NeilBrownThis the role that a device has in an array can be viewed and set.
### Diffstat output
./Documentation/md.txt | 8 ++++++++ ./drivers/md/md.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+)
Documentation/md.txt renamed from Documentation/md.txt~current~ +8 -0
@@ -236,6 +236,14 @@ Each directory contains: providing an ongoing count for arrays with metadata managed by userspace. + slot + This gives the role that the device has in the array. It will + either be 'none' if the device is not active in the array + (i.e. is a spare or has failed) or an integer less than the + 'raid_disks' number for the array indicating which possition + it currently fills. This can only be set while assembling an + array. A device for which this is set is assumed to be working. + An active md device will also contain and entry for each active device in the array. These are named
drivers/md/md.c renamed from drivers/md/md.c~current~ +35 -0
@@ -1630,10 +1630,45 @@ errors_store(mdk_rdev_t *rdev, const chastatic struct rdev_sysfs_entry rdev_errors =__ATTR (errors,0644 , errors_show, errors_store); +static ssize_t +slot_show (mdk_rdev_t *rdev,char *page) +{ +if (rdev->raid_disk <0 ) +return sprintf (page,"none\n" ); +else +return sprintf (page,"%d\n" , rdev->raid_disk); +} + +static ssize_t +slot_store (mdk_rdev_t *rdev,const char *buf,size_t len) +{ +char *e; +int slot =simple_strtoul (buf, &e,10 ); +if (strncmp (buf,"none" ,4 )==0 ) + slot =-1 ; +else if (e==buf || (*e && *e!='\n' )) +return -EINVAL ; +if (rdev->mddev->pers) +/* Cannot set slot in active array (yet) */ +return -EBUSY ; +if (slot >= rdev->mddev->raid_disks) +return -ENOSPC ; + rdev->raid_disk = slot; +/* assume it is working */ + rdev->flags =0 ; +set_bit (In_sync, &rdev->flags); +return len; +} + + +static struct rdev_sysfs_entry rdev_slot = +__ATTR (slot,0644 , slot_show, slot_store); +static struct attribute *rdev_default_attrs[] = { &rdev_state.attr, &rdev_super.attr, &rdev_errors.attr, + &rdev_slot.attr,NULL , }; static ssize_t
PATCH 1/1 Export rdev->data_offset via sysfs
In reply to NeilBrown### Diffstat output
./Documentation/md.txt | 6 ++++++ ./drivers/md/md.c | 23 +++++++++++++++++++++++ 2 files changed, 29 insertions(+)
Documentation/md.txt renamed from Documentation/md.txt~current~ +6 -0
@@ -244,6 +244,12 @@ Each directory contains: it currently fills. This can only be set while assembling an array. A device for which this is set is assumed to be working. + offset + This gives the location in the device (in sectors from the + start) where data from the array will be stored. Any part of + the device before this offset us not touched, unless it is + used for storing metadata (Formats 1.1 and 1.2). + An active md device will also contain and entry for each active device in the array. These are named
drivers/md/md.c renamed from drivers/md/md.c~current~ +23 -0
@@ -1664,11 +1664,34 @@ slot_store(mdk_rdev_t *rdev, const charstatic struct rdev_sysfs_entry rdev_slot =__ATTR (slot,0644 , slot_show, slot_store); +static ssize_t +offset_show (mdk_rdev_t *rdev,char *page) +{ +return sprintf (page,"%llu\n" , rdev->data_offset); +} + +static ssize_t +offset_store (mdk_rdev_t *rdev,const char *buf,size_t len) +{ +char *e; +unsigned long long offset =simple_strtoull (buf, &e,10 ); +if (e==buf || (*e && *e !='\n' )) +return -EINVAL ; +if (rdev->mddev->pers) +return -EBUSY ; + rdev->data_offset = offset; +return len; +} + +static struct rdev_sysfs_entry rdev_offset = +__ATTR (offset,0644 , offset_show, offset_store); +static struct attribute *rdev_default_attrs[] = { &rdev_state.attr, &rdev_super.attr, &rdev_errors.attr, &rdev_slot.attr, + &rdev_offset.attr,NULL , }; static ssize_t
PATCH 1/1 Allow available size of component devices to be set via sysfs.
In reply to NeilBrown### Diffstat output
./Documentation/md.txt | 7 +++++++ ./drivers/md/md.c | 25 +++++++++++++++++++++++++ 2 files changed, 32 insertions(+)
Documentation/md.txt renamed from Documentation/md.txt~current~ +7 -0
@@ -250,6 +250,13 @@ Each directory contains: the device before this offset us not touched, unless it is used for storing metadata (Formats 1.1 and 1.2). + size + The amount of the device, after the offset, that can be used + for storage of data. This will normally be the same as the + component_size. This can be written while assembling an + array. If a value less than the current component_size is + written, component_size will be reduced to this value. + An active md device will also contain and entry for each active device in the array. These are named
drivers/md/md.c renamed from drivers/md/md.c~current~ +25 -0
@@ -1686,12 +1686,37 @@ offset_store(mdk_rdev_t *rdev, const chastatic struct rdev_sysfs_entry rdev_offset =__ATTR (offset,0644 , offset_show, offset_store); +static ssize_t +rdev_size_show (mdk_rdev_t *rdev,char *page) +{ +return sprintf (page,"%llu\n" , rdev->size); +} + +static ssize_t +rdev_size_store (mdk_rdev_t *rdev,const char *buf,size_t len) +{ +char *e; +unsigned long long size =simple_strtoull (buf, &e,10 ); +if (e==buf || (*e && *e !='\n' )) +return -EINVAL ; +if (rdev->mddev->pers) +return -EBUSY ; + rdev->size = size; +if (size < rdev->mddev->size || rdev->mddev->size ==0 ) + rdev->mddev->size = size; +return len; +} + +static struct rdev_sysfs_entry rdev_size = +__ATTR (size,0644 , rdev_size_show, rdev_size_store); +static struct attribute *rdev_default_attrs[] = { &rdev_state.attr, &rdev_super.attr, &rdev_errors.attr, &rdev_slot.attr, &rdev_offset.attr, + &rdev_size.attr,NULL , }; static ssize_t
PATCH 1/1 Support adding new devices to md arrays via sysfs
In reply to NeilBrownWriting major:minor to md/new_dev will bind that device to the array.
### Diffstat output
./Documentation/md.txt | 8 ++++++ ./drivers/md/md.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+)
Documentation/md.txt renamed from Documentation/md.txt~current~ +8 -0
@@ -200,6 +200,14 @@ All md devices contain: This can be written only while the array is being assembled, not after it is started. + new_dev + This file can be written but not read. The value written should + be a block device number as major:minor. e.g. 8:0 + This will cause that device to be attached to the array, if it is + available. It will then appear at md/dev-XXX (depending on the + name of the device) and further configuration is then possible. + + As component devices are added to an md array, they appear in the 'md' directory as new directories named dev-XXX
drivers/md/md.c renamed from drivers/md/md.c~current~ +60 -0
72 lines not on this page · raw message
PATCH 1/1 Allow sync-speed to be controlled per-device
In reply to NeilBrownAlso export current (average) speed and status in sysfs.
### Diffstat output
./Documentation/md.txt | 22 ++++++++ ./drivers/md/md.c | 110 ++++++++++++++++++++++++++++++++++++++++++-- ./include/linux/raid/md_k.h | 4 + 3 files changed, 131 insertions(+), 5 deletions(-)
Documentation/md.txt renamed from Documentation/md.txt~current~ +22 -0
@@ -207,6 +207,28 @@ All md devices contain: available. It will then appear at md/dev-XXX (depending on the name of the device) and further configuration is then possible. + sync_speed_min + sync_speed_max + This are similar to /proc/sys/dev/raid/speed_limit_{min,max} + however they only apply to the particular array. + If no value has been written to these, of if the word 'system' + is written, then the system-wide value is used. If a value, + in kibibytes-per-second is written, then it is used. + When the files are read, they show the currently active value + followed by "(local)" or "(system)" depending on whether it is + a locally set or system-wide value. + + sync_completed + This shows the number of sectors that have been completed of + whatever the current sync_action is, followed by the number of + sectors in total that could need to be processed. The two + numbers are separated by a '/' thus effectively showing one + value, a fraction of the process that is complete. + + sync_speed + This shows the current actual speed, in K/sec, of the current + sync_action. It is averaged over the last 30 seconds. + As component devices are added to an md array, they appear in the 'md' directory as new directories named
drivers/md/md.c renamed from drivers/md/md.c~current~ +105 -5
152 lines not on this page · raw message
include/linux/raid/md_k.h renamed from include/linux/raid/md_k.h~current~ +4 -0
@@ -143,6 +143,10 @@ struct mddev_ssector_t resync_mismatches;/* count of sectors where * parity/replica mismatch found */ +/* if zero, use the system-wide default */ +int sync_speed_min; +int sync_speed_max; +int ok_start_degraded;/* recovery/resync flags * NEEDED: we might need to start a resync/recover
Re: [PATCH md 020 of 20] Allow sync-speed to be controlled per-device
Typo.
of if -> or if
Quoted 226 lines · NeilBrown
Also export current (average) speed and status in sysfs.
Signed-off-by Neil Brown <[email protected]>### Diffstat output
./Documentation/md.txt | 22 ++++++++ ./drivers/md/md.c | 110 ++++++++++++++++++++++++++++++++++++++++++-- ./include/linux/raid/md_k.h | 4 + 3 files changed, 131 insertions(+), 5 deletions(-)diff
./Documentation/md.txt~current~./Documentation/md.txtDocumentation/md.txt renamed from Documentation/md.txt~current~ +22
-0@@ -207,6 +207,28 @@ All md devices contain: available. It will then appear at md/dev-XXX (depending on the name of the device) and further configuration is then possible. + sync_speed_min + sync_speed_max + This are similar to /proc/sys/dev/raid/speed_limit_{min,max} + however they only apply to the particular array. + If no value has been written to these, of if the word 'system' + is written, then the system-wide value is used. If a value, + in kibibytes-per-second is written, then it is used. + When the files are read, they show the currently active value + followed by "(local)" or "(system)" depending on whether it is + a locally set or system-wide value. + + sync_completed + This shows the number of sectors that have been completed of + whatever the current sync_action is, followed by the number of + sectors in total that could need to be processed. The two + numbers are separated by a '/' thus effectively showing one + value, a fraction of the process that is complete. + + sync_speed + This shows the current actual speed, in K/sec, of the current + sync_action. It is averaged over the last 30 seconds. + As component devices are added to an md array, they appear in the 'md' directory as new directories nameddiff
./drivers/md/md.c~current~./drivers/md/md.cdrivers/md/md.c renamed from drivers/md/md.c~current~ +96
-0@@ -81,10 +81,22 @@ static DEFINE_SPINLOCK(pers_lock);* idle IO detection. * * you can change it via /proc/sys/dev/raid/speed_limit_min and _max. +* or /sys/block/mdX/md/sync_speed_{min,max} */ static int sysctl_speed_limit_min =1000 ;static int sysctl_speed_limit_max =200000 ; +static inline int speed_min (mddev_t *mddev) +{ +return mddev->sync_speed_min ? + mddev->sync_speed_min : sysctl_speed_limit_min; +} + +static inline int speed_max (mddev_t *mddev) +{ +return mddev->sync_speed_max ? + mddev->sync_speed_max : sysctl_speed_limit_max; +}static struct ctl_table_header *raid_table_header;@@ -2197,6 +2209,90 @@ md_scan_mode = __ATTR(sync_action, S_IRUstatic struct md_sysfs_entry md_mismatches =__ATTR_RO (mismatch_cnt); +static ssize_t +sync_min_show (mddev_t *mddev,char *page) +{ +return sprintf (page,"%d (%s)\n" ,speed_min (mddev), + mddev->sync_speed_min ?"local" :"system" ); +} + +static ssize_t +sync_min_store (mddev_t *mddev,const char *buf,size_t len) +{ +int min; +char *e; +if (strncmp (buf,"system" ,6 )==0 ) { + mddev->sync_speed_min =0 ; +return len; + } + min =simple_strtoul (buf, &e,10 ); +if (buf == e || (*e && *e !='\n' ) || min <=0 ) +return -EINVAL ; + mddev->sync_speed_min = min; +return len; +} + +static struct md_sysfs_entry md_sync_min = +__ATTR (sync_speed_min,S_IRUGO |S_IWUSR , sync_min_show, sync_min_store); + +static ssize_t +sync_max_show (mddev_t *mddev,char *page) +{ +return sprintf (page,"%d (%s)\n" ,speed_max (mddev), + mddev->sync_speed_max ?"local" :"system" ); +} + +static ssize_t +sync_max_store (mddev_t *mddev,const char *buf,size_t len) +{ +int max; +char *e; +if (strncmp (buf,"system" ,6 )==0 ) { + mddev->sync_speed_max =0 ; +return len; + } + max =simple_strtoul (buf, &e,10 ); +if (buf == e || (*e && *e !='\n' ) || max <=0 ) +return -EINVAL ; + mddev->sync_speed_max = max; +return len; +} + +static struct md_sysfs_entry md_sync_max = +__ATTR (sync_speed_max,S_IRUGO |S_IWUSR , sync_max_show, sync_max_store); + + +static ssize_t +sync_speed_show (mddev_t *mddev,char *page) +{ +unsigned long resync, dt, db; + resync = (mddev->curr_resync -atomic_read (&mddev->recovery_active)); + dt = ((jiffies - mddev->resync_mark) /HZ ); +if (!dt) dt++; + db = resync - (mddev->resync_mark_cnt); +return sprintf (page,"%ld\n" , db/dt/2 );/* K/sec */ +} + +static struct md_sysfs_entry +md_sync_speed =__ATTR_RO (sync_speed); + +static ssize_t +sync_completed_show (mddev_t *mddev,char *page) +{ +unsigned long max_blocks, resync; + +if (test_bit (MD_RECOVERY_SYNC , &mddev->recovery)) + max_blocks = mddev->resync_max_sectors; +else + max_blocks = mddev->size <<1 ; + + resync = (mddev->curr_resync -atomic_read (&mddev->recovery_active)); +return sprintf (page,"%lu / %lu\n" , resync, max_blocks); +} + +static struct md_sysfs_entry +md_sync_completed =__ATTR_RO (sync_completed); +static struct attribute *md_default_attrs[] = {drivers/md/md.c renamed from drivers/md/md.c~current~ +9
-5&md_level.attr, &md_raid_disks.attr,@@ -2210,6 +2306,10 @@ static struct attribute *md_default_attrstatic struct attribute *md_redundancy_attrs[] = { &md_scan_mode.attr, &md_mismatches.attr, + &md_sync_min.attr, + &md_sync_max.attr, + &md_sync_speed.attr, + &md_sync_completed.attr,NULL , };static struct attribute_group md_redundancy_group = {@@ -4425,10 +4525,10 @@ static void md_do_sync(mddev_t *mddev)printk (KERN_INFO "md: syncing RAID array %s\n" ,mdname (mddev));printk (KERN_INFO "md: minimum _guaranteed_ reconstruction speed:" -" %d KB/sec/disc.\n" , sysctl_speed_limit_min); +" %d KB/sec/disc.\n" ,speed_min (mddev));printk (KERN_INFO "md: using maximum available idle IO bandwidth " "(but not more than %d KB/sec) for reconstruction.\n" , - sysctl_speed_limit_max); +speed_max (mddev));is_mddev_idle (mddev);/* this also initializes IO event counters */ /* we don't use the checkpoint if there's a bitmap */ @@ -4469,7 +4569,7 @@ static void md_do_sync(mddev_t *mddev) skipped =0 ; sectors = mddev->pers->sync_request (mddev, j, &skipped, - currspeed < sysctl_speed_limit_min); + currspeed <speed_min (mddev));if (sectors ==0 ) {set_bit (MD_RECOVERY_ERR , &mddev->recovery); goto out;@@ -4534,8 +4634,8 @@ static void md_do_sync(mddev_t *mddev) currspeed = ((unsigned long )(io_sectors-mddev->resync_mark_cnt))/2 /((jiffies-mddev->resync_mark)/HZ +1 ) +1 ; -if (currspeed > sysctl_speed_limit_min) { -if ((currspeed > sysctl_speed_limit_max) || +if (currspeed >speed_min (mddev)) { +if ((currspeed >speed_max (mddev)) || !is_mddev_idle (mddev)) {msleep (500 ); goto repeat;diff
./include/linux/raid/md_k.h~current~./include/linux/raid/md_k.h
---./include/linux/raid/md_k.h~current~2005-12-12 12:12:50.000000000
+1100
+++./include/linux/raid/md_k.h2005-12-12 12:12:53.000000000 +1100drivers/md/md.c renamed from drivers/md/md.c~current~ +4
-1@@ -143,6 +143,10 @@ struct mddev_ssector_t resync_mismatches;/* count of sectors where * parity/replica mismatch found */ +/* if zero, use the system-wide default */ +int sync_speed_min; +int sync_speed_max; +int ok_start_degraded;/* recovery/resync flags * NEEDED: we might need to start a resync/recover -
Quoted 3 lines
To unsubscribe from this list: send the line "unsubscribe linux-raid" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
--Jeff