md: Introduction EXPLAIN PATCH SET HERE
Subsystems (4)
PATCH 1/1 md: Introduction EXPLAIN PATCH SET HERE
Following are 7 md related patches are suitable for the next -mm and maybe for 2.6.25.
They move towards giving user-space programs more fine control of an array so that we can add support for more complex metadata formats (e.g. DDF) without bothering the kernel with such things.
The last patch isn't strictly md related. It adds an ioctl which allows mapping from an open file descriptor on a block device to a name in /sys. This makes finding name of things in /sys more practical. As I put this in block-layer code, I have Cc:ed Jens Axboe.
[PATCH 001 of 7] md: Support 'external' metadata for md arrays.
[PATCH 002 of 7] md: Give userspace control over removing failed devices when external metdata in use [PATCH 003 of 7] md: Allow a maximum extent to be set for resyncing.
[PATCH 004 of 7] md: Allow devices to be shared between md arrays.
[PATCH 005 of 7] md: Lock address when changing attributes of component devices. [PATCH 006 of 7] md: Allow an md array to appear with 0 drives if it has external metadata. [PATCH 007 of 7] md: Get name for block device in sysfs
PATCH 1/1 md: Support 'external' metadata for md arrays.
- Add a state flag 'external' to indicate that the metadata is managed externally (by user-space) so important changes need to be left of user-space to handle.
Alternates are non-persistant ('none') where there is no stable metadata - after the array is stopped there is no record of it's status - and internal which can be version 0.90 or version 1.x
These are selected by writing to the 'metadata' attribute.
- move the updating of superblocks (sync_sbs) to after we have checked if there are any superblocks or not.
- New array state 'write_pending'. This means that the metadata records the array as 'clean', but a write has been requested, so the metadata has to be updated to record a 'dirty' array before the write can continue. This change is reported to md by writing 'active' to the array_state attribute.
- tidy up marking of sb_dirty:
- don't set sb_dirty when resync finishes as md_check_recovery calls md_update_sb when the sync thread finishes anyway.
- Don't set sb_dirty in multipath_run as the array might not be dirty.
- don't mark superblock dirty when switching to 'clean' if there is no internal superblock (if external, userspace can choose to update the superblock whenever it chooses to).
### Diffstat output
./drivers/md/md.c | 77 +++++++++++++++++++++++++++++++++----------- ./include/linux/raid/md_k.h | 3 + 2 files changed, 61 insertions(+), 19 deletions(-)
drivers/md/md.c +58 -19
@@ -778,7 +778,8 @@ static int super_90_validate(mddev_t *md mddev->major_version =0 ; mddev->minor_version = sb->minor_version; mddev->patch_version = sb->patch_version; - mddev->persistent = ! sb->not_persistent; + mddev->persistent =1 ; + mddev->external =0 ; mddev->chunk_size = sb->chunk_size; mddev->ctime = sb->ctime; mddev->utime = sb->utime;
@@ -904,7 +905,7 @@ static void super_90_sync(mddev_t *mddev sb->size = mddev->size; sb->raid_disks = mddev->raid_disks; sb->md_minor = mddev->md_minor; - sb->not_persistent = !mddev->persistent; + sb->not_persistent =0 ; sb->utime = mddev->utime; sb->state =0 ; sb->events_hi = (mddev->events>>32 );
@@ -1158,6 +1159,7 @@ static int super_1_validate(mddev_t *mdd mddev->major_version =1 ; mddev->patch_version =0 ; mddev->persistent =1 ; + mddev->external =0 ; mddev->chunk_size =le32_to_cpu (sb->chunksize) <<9 ; mddev->ctime =le64_to_cpu (sb->ctime) & ((1ULL <<32 )-1 ); mddev->utime =le64_to_cpu (sb->utime) & ((1ULL <<32 )-1 );
@@ -1699,18 +1701,20 @@ repeat:MD_BUG (); mddev->events --; } -sync_sbs (mddev, nospares);/* * do not write anything to disk if using * nonpersistent superblocks */ if (!mddev->persistent) { -clear_bit (MD_CHANGE_PENDING , &mddev->flags); +if (!mddev->external) +clear_bit (MD_CHANGE_PENDING , &mddev->flags); +spin_unlock_irq (&mddev->write_lock);wake_up (&mddev->sb_wait);return ; } +sync_sbs (mddev, nospares);spin_unlock_irq (&mddev->write_lock); dprintk(KERN_INFO
@@ -2430,6 +2434,8 @@ array_state_show(mddev_t *mddev, char *pcase 0 :if (mddev->in_sync) st = clean; +else if (test_bit (MD_CHANGE_CLEAN , &mddev->flags)) + st = write_pending;else if (mddev->safemode) st = active_idle;else
@@ -2460,11 +2466,9 @@ array_state_store(mddev_t *mddev, constbreak ;case clear:/* stopping an active array */ -if (mddev->pers) { -if (atomic_read (&mddev->active) >1 ) -return -EBUSY ; - err =do_md_stop (mddev,0 ); - } +if (atomic_read (&mddev->active) >1 ) +return -EBUSY ; + err =do_md_stop (mddev,0 );break ;case inactive:/* stopping an active array */
@@ -2472,7 +2476,8 @@ array_state_store(mddev_t *mddev, constif (atomic_read (&mddev->active) >1 )return -EBUSY ; err =do_md_stop (mddev,2 ); - } + }else + err =0 ;/* already inactive */ break ;case suspended:break ;/* not supported yet */
@@ -2500,9 +2505,15 @@ array_state_store(mddev_t *mddev, constrestart_array (mddev);spin_lock_irq (&mddev->write_lock);if (atomic_read (&mddev->writes_pending) ==0 ) { - mddev->in_sync =1 ; -set_bit (MD_CHANGE_CLEAN , &mddev->flags); - } +if (mddev->in_sync ==0 ) { + mddev->in_sync =1 ; +if (mddev->persistent) +set_bit (MD_CHANGE_CLEAN , + &mddev->flags); + } + err =0 ; + }else + err = -EBUSY ;spin_unlock_irq (&mddev->write_lock); }else { mddev->ro =0 ;
@@ -2513,7 +2524,8 @@ array_state_store(mddev_t *mddev, constcase active:if (mddev->pers) {restart_array (mddev); -clear_bit (MD_CHANGE_CLEAN , &mddev->flags); +if (mddev->external) +clear_bit (MD_CHANGE_CLEAN , &mddev->flags);wake_up (&mddev->sb_wait); err =0 ; }else {
@@ -2664,7 +2676,9 @@ __ATTR(component_size, S_IRUGO|S_IWUSR,/* Metdata version. -* This is either 'none' for arrays with externally managed metadata, +* This is one of +* 'none' for arrays with no metadata (good luck...) +* 'external' for arrays with externally managed metadata, * or N.M for internally known formats */ static ssize_t
@@ -2673,6 +2687,8 @@ metadata_show(mddev_t *mddev, char *pageif (mddev->persistent)return sprintf (page,"%d.%d\n" , mddev->major_version, mddev->minor_version); +else if (mddev->external) +return sprintf (page,"external:%s\n" , mddev->metadata_type);else return sprintf (page,"none\n" ); }
@@ -2687,6 +2703,21 @@ metadata_store(mddev_t *mddev, const chaif (cmd_match (buf,"none" )) { mddev->persistent =0 ; + mddev->external =0 ; + mddev->major_version =0 ; + mddev->minor_version =90 ; +return len; + } +if (strncmp (buf,"external:" ,9 ) ==0 ) { +int namelen = len-9 ; +if (namelen >=sizeof (mddev->metadata_type)) + namelen =sizeof (mddev->metadata_type)-1 ; +strncpy (mddev->metadata_type, buf+9 , namelen); + mddev->metadata_type[namelen] =0 ; +if (namelen && mddev->metadata_type[namelen-1 ] =='\n' ) + mddev->metadata_type[--namelen] =0 ; + mddev->persistent =0 ; + mddev->external =1 ; mddev->major_version =0 ; mddev->minor_version =90 ;return len;
@@ -2703,6 +2734,7 @@ metadata_store(mddev_t *mddev, const cha mddev->major_version = major; mddev->minor_version = minor; mddev->persistent =1 ; + mddev->external =0 ;return len; }
@@ -3527,6 +3559,7 @@ static int do_md_stop(mddev_t * mddev, i mddev->raid_disks =0 ; mddev->recovery_cp =0 ; mddev->reshape_position = MaxSector; + mddev->external =0 ; }else if (mddev->pers) printk(KERN_INFO "md: %s switched to read-only mode.\n",
@@ -4168,13 +4201,15 @@ static int set_array_info(mddev_t * mddeelse mddev->recovery_cp =0 ; mddev->persistent = ! info->not_persistent; + mddev->external =0 ; mddev->layout = info->layout; mddev->chunk_size = info->chunk_size; mddev->max_disks =MD_SB_DISKS ; - mddev->flags =0 ; +if (mddev->persistent) + mddev->flags =0 ;set_bit (MD_CHANGE_DEVS , &mddev->flags); mddev->default_bitmap_offset =MD_SB_BYTES >>9 ;
@@ -4985,7 +5020,10 @@ static int md_seq_show(struct seq_file * mddev->major_version, mddev->minor_version); } - }else + }else if (mddev->external) +seq_printf (seq," super external:%s" , + mddev->metadata_type); +else seq_printf (seq," super non-persistent" );if (mddev->pers) {
@@ -5591,7 +5629,7 @@ void md_check_recovery(mddev_t *mddev) } if ( ! ( - mddev->flags || + (mddev->flags && !mddev->external) || test_bit(MD_RECOVERY_NEEDED, &mddev->recovery) || test_bit(MD_RECOVERY_DONE, &mddev->recovery) || (mddev->safemode == 1) ||
@@ -5607,7 +5645,8 @@ void md_check_recovery(mddev_t *mddev)if (mddev->safemode && !atomic_read (&mddev->writes_pending) && !mddev->in_sync && mddev->recovery_cp == MaxSector) { mddev->in_sync =1 ; -set_bit (MD_CHANGE_CLEAN , &mddev->flags); +if (mddev->persistent) +set_bit (MD_CHANGE_CLEAN , &mddev->flags); }if (mddev->safemode ==1 ) mddev->safemode =0 ;
include/linux/raid/md_k.h +3 -0
@@ -130,6 +130,9 @@ struct mddev_s minor_version, patch_version;int persistent; +int external;/* metadata is +* managed externally */ +char metadata_type[17 ];/* externally set*/ int chunk_size;time_t ctime, utime;int level, layout;
Re: [PATCH 001 of 7] md: Support 'external' metadata for md arrays.
drivers/md/md.c metadata_store(mddev_t *mddev, const cha · line 2720
Quoted 10 lines · On Fri, 14 Dec 2007 17:26:08 +1100 NeilBrown <[email protected]> wrote:
drivers/md/md.c +10
-0+if (strncmp (buf,"external:" ,9 ) ==0 ) { +int namelen = len-9 ; +if (namelen >=sizeof (mddev->metadata_type)) + namelen =sizeof (mddev->metadata_type)-1 ; +strncpy (mddev->metadata_type, buf+9 , namelen); + mddev->metadata_type[namelen] =0 ; +if (namelen && mddev->metadata_type[namelen-1 ] =='\n' ) + mddev->metadata_type[--namelen] =0 ; + mddev->persistent =0 ; + mddev->external =1 ;
size_t would be a more appropriate type for `namelen'.
PATCH 1/1 md: Give userspace control over removing failed devices when external metdata in use
In reply to NeilBrownWhen a device fails, we must not allow an further writes to the array until the device failure has been recorded in array metadata. When metadata is managed externally, this requires some synchronisation...
Allow/require userspace to explicitly remove failed devices from active service in the array by writing 'none' to the 'slot' attribute. If this reduces the number of failed devices to 0, the write block will automatically be lowered.
### Diffstat output
./drivers/md/md.c | 43 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-)
drivers/md/md.c +34 -9
@@ -1894,20 +1894,44 @@ static ssize_t slot_store(mdk_rdev_t *rdev, const char *buf, size_t len) {char *e; +int err; +char nm[20 ];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); +if (rdev->mddev->pers) { +/* Setting 'slot' on an active array requires also +* updating the 'rd%d' link, and communicating +* with the personality with ->hot_*_disk. +* For now we only support removing +* failed/spare devices. This normally happens automatically, +* but not when the metadata is externally managed. +*/ +if (slot !=-1 ) +return -EBUSY ; +if (rdev->raid_disk ==-1 ) +return -EEXIST ; +/* personality does all needed checks */ +if (rdev->mddev->pers->hot_add_disk ==NULL ) +return -EINVAL ; + err = rdev->mddev->pers-> +hot_remove_disk (rdev->mddev, rdev->raid_disk); +if (err) +return err; +sprintf (nm,"rd%d" , rdev->raid_disk); +sysfs_remove_link (&rdev->mddev->kobj, nm); +set_bit (MD_RECOVERY_NEEDED , &rdev->mddev->recovery); +md_wakeup_thread (rdev->mddev->thread); + }else { +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; }
@@ -5551,6 +5575,7 @@ static int remove_and_add_spares(mddev_t ITERATE_RDEV(mddev,rdev,rtmp)if (rdev->raid_disk >=0 && + !mddev->external && (test_bit (Faulty, &rdev->flags) || !test_bit (In_sync, &rdev->flags)) &&atomic_read (&rdev->nr_pending)==0 ) {
PATCH 1/1 md: Allow a maximum extent to be set for resyncing.
In reply to NeilBrownThis allows userspace to control resync/reshape progress and synchronise it with other activities, such as shared access in a SAN, or backing up critical sections during a tricky reshape.
Writing a number of sectors (which must be a multiple of the chunk size if such is meaningful) causes a resync to pause when it gets to that point.
### Diffstat output
./Documentation/md.txt | 10 +++++ ./drivers/md/md.c | 75 ++++++++++++++++++++++++++++++++++++++------ ./drivers/md/raid1.c | 2 + ./drivers/md/raid10.c | 3 + ./drivers/md/raid5.c | 25 ++++++++++++++ ./include/linux/raid/md_k.h | 2 + 6 files changed, 107 insertions(+), 10 deletions(-)
Documentation/md.txt +10 -0
@@ -416,6 +416,16 @@ also have 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. + A 'select' on this attribute will return when resync completes, + when it reaches the current sync_max (below) and possibly at + other times. + + sync_max + This is a number of sectors at which point a resync/recovery + process will pause. When a resync is active, the value can + only ever be increased, never decreased. The value of 'max' + effectively disables the limit. + sync_speed This shows the current actual speed, in K/sec, of the current
drivers/md/md.c +65 -10
121 lines not on this page · raw message
drivers/md/raid10.c +3 -0
@@ -1657,6 +1657,9 @@ static sector_t sync_request(mddev_t *mdreturn (max_sector - sector_nr) + sectors_skipped; } +if (max_sector > mddev->resync_max) + max_sector = mddev->resync_max;/* Don't do IO beyond here */ +/* make sure whole request will fit in a chunk - if chunks * are meaningful */
drivers/md/raid1.c +2 -0
@@ -1784,6 +1784,8 @@ static sector_t sync_request(mddev_t *mdreturn rv; } +if (max_sector > mddev->resync_max) + max_sector = mddev->resync_max;/* Don't do IO beyond here */ nr_sectors =0 ; sync_blocks =0 ; do {
drivers/md/raid5.c +25 -0
@@ -4277,6 +4277,25 @@ static sector_t reshape_request(mddev_trelease_queue (sq); first_sector +=STRIPE_SECTORS ; } +/* If this takes us to the resync_max point where we have to pause, +* then we need to write out the superblock. +*/ + sector_nr += conf->chunk_size>>9 ; +if (sector_nr >= mddev->resync_max) { +/* Cannot proceed until we've updated the superblock... */ +wait_event (conf->wait_for_overlap, +atomic_read (&conf->reshape_stripes) ==0 ); + mddev->reshape_position = conf->expand_progress; +set_bit (MD_CHANGE_DEVS , &mddev->flags); +md_wakeup_thread (mddev->thread); +wait_event (mddev->sb_wait, + !test_bit (MD_CHANGE_DEVS , &mddev->flags) + ||kthread_should_stop ()); +spin_lock_irq (&conf->device_lock); + conf->expand_lo = mddev->reshape_position; +spin_unlock_irq (&conf->device_lock); +wake_up (&conf->wait_for_overlap); + }return conf->chunk_size>>9 ; }
@@ -4314,6 +4333,12 @@ static inline sector_t sync_request(mddeif (test_bit (MD_RECOVERY_RESHAPE , &mddev->recovery))return reshape_request (mddev, sector_nr, skipped); +/* No need to check resync_max as we never do more than one +* stripe, and as resync_max will always be on a chunk boundary, +* if the check in md_do_sync didn't fire, there is no chance +* of overstepping resync_max here +*/ +/* if there is too many failed drives and we are trying * to resync, then assert that we are finished, because there is * nothing we can do.
include/linux/raid/md_k.h +2 -0
@@ -219,6 +219,8 @@ struct mddev_satomic_t recovery_active;/* blocks scheduled, but not written */ wait_queue_head_t recovery_wait;sector_t recovery_cp; +sector_t resync_max;/* resync should pause +* when it gets here */ spinlock_t write_lock;wait_queue_head_t sb_wait;/* for waiting on superblock updates */
PATCH 1/1 md: Allow devices to be shared between md arrays.
In reply to NeilBrownCurrently, a given device is "claimed" by a particular array so that it cannot be used by other arrays.
This is not ideal for DDF and other metadata schemes which have their own partitioning concept.
So for externally managed metadata, just claim the device for md in general, require that "offset" and "size" are set properly for each device, and make sure that if a device is included in different arrays then the active sections do not overlap.
This involves adding another flag to the rdev which makes it awkward to set "->flags = 0" to clear certain flags. So now clear flags explicitly by name when we want to clear things.
### Diffstat output
./drivers/md/md.c | 93 ++++++++++++++++++++++++++++++++++++++------ ./include/linux/raid/md_k.h | 2 2 files changed, 84 insertions(+), 11 deletions(-)
drivers/md/md.c +82 -11
@@ -774,7 +774,11 @@ static int super_90_validate(mddev_t *md__u64 ev1 =md_event (sb); rdev->raid_disk =-1 ; - rdev->flags =0 ; +clear_bit (Faulty, &rdev->flags); +clear_bit (In_sync, &rdev->flags); +clear_bit (WriteMostly, &rdev->flags); +clear_bit (BarriersNotsupp, &rdev->flags); +if (mddev->raid_disks ==0 ) { mddev->major_version =0 ; mddev->minor_version = sb->minor_version;
@@ -1155,7 +1159,11 @@ static int super_1_validate(mddev_t *mdd__u64 ev1 =le64_to_cpu (sb->events); rdev->raid_disk =-1 ; - rdev->flags =0 ; +clear_bit (Faulty, &rdev->flags); +clear_bit (In_sync, &rdev->flags); +clear_bit (WriteMostly, &rdev->flags); +clear_bit (BarriersNotsupp, &rdev->flags); +if (mddev->raid_disks ==0 ) { mddev->major_version =1 ; mddev->patch_version =0 ;
@@ -1407,7 +1415,7 @@ static int bind_rdev_to_array(mdk_rdev_t goto fail; }list_add (&rdev->same_set, &mddev->disks); -bd_claim_by_disk (rdev->bdev, rdev, mddev->gendisk); +bd_claim_by_disk (rdev->bdev, rdev->bdev->bd_holder, mddev->gendisk);return 0 ; fail:
@@ -1447,7 +1455,7 @@ static void unbind_rdev_from_array(mdk_r* otherwise reused by a RAID array (or any other kernel * subsystem), by bd_claiming the device. */ -static int lock_rdev (mdk_rdev_t *rdev,dev_t dev) +static int lock_rdev (mdk_rdev_t *rdev,dev_t dev,int shared) {int err =0 ;struct block_device *bdev;
@@ -1459,13 +1467,15 @@ static int lock_rdev(mdk_rdev_t *rdev, d __bdevname(dev, b));return PTR_ERR (bdev); } - err =bd_claim (bdev, rdev); + err =bd_claim (bdev, shared ? (mdk_rdev_t *)lock_rdev : rdev);if (err) {printk (KERN_ERR "md: could not bd_claim %s.\n" ,bdevname (bdev, b));blkdev_put (bdev);return err; } +if (!shared) +set_bit (AllReserved, &rdev->flags); rdev->bdev = bdev;return err; }
@@ -1930,7 +1940,8 @@ slot_store(mdk_rdev_t *rdev, const charreturn -ENOSPC ; rdev->raid_disk = slot;/* assume it is working */ - rdev->flags =0 ; +clear_bit (Faulty, &rdev->flags); +clear_bit (WriteMostly, &rdev->flags);set_bit (In_sync, &rdev->flags); }return len;
@@ -1955,6 +1966,10 @@ offset_store(mdk_rdev_t *rdev, const chareturn -EINVAL ;if (rdev->mddev->pers)return -EBUSY ; +if (rdev->size && rdev->mddev->external) +/* Must set offset before size, so overlap checks +* can be sane */ +return -EBUSY ; rdev->data_offset = offset;return len; }
@@ -1968,16 +1983,69 @@ rdev_size_show(mdk_rdev_t *rdev, char *preturn sprintf (page,"%llu\n" , (unsigned long long )rdev->size); } +static int overlaps (sector_t s1,sector_t l1,sector_t s2,sector_t l2) +{ +/* check if two start/length pairs overlap */ +if (s1+l1 <= s2) +return 0 ; +if (s2+l2 <= s1) +return 0 ; +return 1 ; +} +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 ); +unsigned long long oldsize = rdev->size;if (e==buf || (*e && *e !='\n' ))return -EINVAL ;if (rdev->mddev->pers)return -EBUSY ; rdev->size = size; +if (size > oldsize && rdev->mddev->external) { +/* need to check that all other rdevs with the same ->bdev +* do not overlap. We need to unlock the mddev to avoid +* a deadlock. We have already changed rdev->size, and if +* we have to change it back, we will have the lock again. +*/ +mddev_t *mddev; +int overlap =0 ; +struct list_head *tmp, *tmp2; + +mddev_unlock (rdev->mddev); + ITERATE_MDDEV(mddev, tmp) { +mdk_rdev_t *rdev2; + +mddev_lock (mddev); + ITERATE_RDEV(mddev, rdev2, tmp2) +if (test_bit (AllReserved, &rdev2->flags) || + (rdev->bdev == rdev2->bdev && + rdev != rdev2 && +overlaps (rdev->data_offset, rdev->size, + rdev2->data_offset, rdev2->size))) { + overlap =1 ; +break ; + } +mddev_unlock (mddev); +if (overlap) { +mddev_put (mddev); +break ; + } + } +mddev_lock (rdev->mddev); +if (overlap) { +/* Someone else could have slipped in a size +* change here, but doing so is just silly. +* We put oldsize back because we *know* it is +* safe, and trust userspace not to race with +* itself +*/ + rdev->size = oldsize; +return -EBUSY ; + } + }if (size < rdev->mddev->size || rdev->mddev->size ==0 ) rdev->mddev->size = size;return len;
@@ -2061,7 +2129,7 @@ static mdk_rdev_t *md_import_device(dev_if ((err =alloc_disk_sb (rdev))) goto abort_free; - err =lock_rdev (rdev, newdev); + err =lock_rdev (rdev, newdev, super_format ==-2 );if (err) goto abort_free;
@@ -2616,7 +2684,9 @@ new_dev_store(mddev_t *mddev, const charif (err <0 ) goto out; } - }else + }else if (mddev->external) + rdev =md_import_device (dev,-2 ,-1 ); +else rdev =md_import_device (dev,-1 ,-1 );if (IS_ERR (rdev))
@@ -3216,8 +3286,11 @@ static int do_md_run(mddev_t * mddev)/* * Analyze all RAID superblock(s) */ -if (!mddev->raid_disks) +if (!mddev->raid_disks) { +if (!mddev->persistent) +return -EINVAL ;analyze_sbs (mddev); + } chunk_size = mddev->chunk_size;
@@ -4019,8 +4092,6 @@ static int add_new_disk(mddev_t * mddev,else rdev->raid_disk =-1 ; - rdev->flags =0 ; -if (rdev->raid_disk < mddev->raid_disks)if (info->state & (1 <<MD_DISK_SYNC ))set_bit (In_sync, &rdev->flags);
include/linux/raid/md_k.h +2 -0
@@ -81,6 +81,8 @@ struct mdk_rdev_s#define In_sync 2/* device is in_sync with rest of array */ #define WriteMostly 4/* Avoid reading if at all possible */ #define BarriersNotsupp 5/* BIO_RW_BARRIER is not supported */ +#define AllReserved 6/* If whole device is reserved for +* one array */ int desc_nr;/* descriptor index in the superblock */ int raid_disk;/* role of device in array */
Re: [PATCH 004 of 7] md: Allow devices to be shared between md arrays.
Quoted 10 lines · On Fri, 14 Dec 2007 17:26:28 +1100 NeilBrown <[email protected]> wrote:
drivers/md/md.c +10
-0+mddev_unlock (rdev->mddev); + ITERATE_MDDEV(mddev, tmp) { + mdk_rdev_t *rdev2; + + mddev_lock(mddev); + ITERATE_RDEV(mddev, rdev2, tmp2) + if (test_bit(AllReserved, &rdev2->flags) || + (rdev->bdev == rdev2->bdev && + rdev != rdev2 && + overlaps(rdev->data_offset, rdev->size,
drivers/md/md.c rdev_size_show(mdk_rdev_t *rdev, char *p · line 2036
Quoted 10 lines
drivers/md/md.c +10
-0+ rdev2->data_offset, rdev2->size))) { + overlap =1 ; +break ; + } +mddev_unlock (mddev); +if (overlap) { +mddev_put (mddev); +break ; + } + }
eww, ITERATE_MDDEV() and ITERATE_RDEV() are an eyesore.
for_each_mddev() and for_each_rdev() would at least mean the reader doesn't need to check the implementation when wondering what that `break' is breaking from.
Quoted 4 lines
#define
In_sync2 /* device isin_syncwith rest of array */
#define WriteMostly 4 /* Avoid reading if at all possible */
#define BarriersNotsupp 5 /*BIO_RW_BARRIERis not supported */
+#define AllReserved 6 /* If whole device is reserved for
The naming style here is inconsistent.
A task for the keen would be to convert these to an enum and add some namespacing prefix to them.
PATCH 1/1 md: Lock address when changing attributes of component devices.
In reply to NeilBrown### Diffstat output
./drivers/md/md.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/md/md.c +7 -1
@@ -2080,12 +2080,18 @@ rdev_attr_store(struct kobject *kobj, st { struct rdev_sysfs_entry *entry = container_of(attr, struct rdev_sysfs_entry, attr);mdk_rdev_t *rdev =container_of (kobj, mdk_rdev_t, kobj); +int rv;if (!entry->store)return -EIO ;if (!capable (CAP_SYS_ADMIN ))return -EACCES ; -return entry->store (rdev, page, length); + rv =mddev_lock (rdev->mddev); +if (!rv) { + rv = entry->store (rdev, page, length); +mddev_unlock (rdev->mddev); + } +return rv; }static void rdev_free (struct kobject *ko)
PATCH 1/1 md: Allow an md array to appear with 0 drives if it has external metadata.
In reply to NeilBrown### Diffstat output
./drivers/md/md.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/md/md.c +4 -3
@@ -4650,9 +4650,10 @@ static int md_ioctl(struct inode *inode,*/ /* if we are not initialised yet, only ADD_NEW_DISK, STOP_ARRAY, * RUN_ARRAY, and GET_ and SET_BITMAP_FILE are allowed */ -if (!mddev->raid_disks && cmd !=ADD_NEW_DISK && cmd !=STOP_ARRAY - && cmd !=RUN_ARRAY && cmd !=SET_BITMAP_FILE - && cmd !=GET_BITMAP_FILE ) { +if ((!mddev->raid_disks && !mddev->external) + && cmd !=ADD_NEW_DISK && cmd !=STOP_ARRAY + && cmd !=RUN_ARRAY && cmd !=SET_BITMAP_FILE + && cmd !=GET_BITMAP_FILE ) { err = -ENODEV ; goto abort_unlock; }
PATCH 1/1 md: Get name for block device in sysfs
In reply to NeilBrownGiven an fd on a block device, returns a string like
/block/sda/sda1
which can be used to find related information in /sys.
Ideally we should have an ioctl that works on char devices as well, but that seems far from trivial, so it seems reasonable to have this until the later can be implemented.
### Diffstat output
./block/ioctl.c | 13 +++++++++++++ ./include/linux/fs.h | 2 ++ 2 files changed, 15 insertions(+)
block/ioctl.c +13 -0
@@ -227,8 +227,21 @@ int blkdev_ioctl(struct inode *inode, ststruct block_device *bdev = inode->i_bdev;struct gendisk *disk = bdev->bd_disk;int ret, n; +char b[BDEVNAME_SIZE *2 +10 ];switch (cmd) { +case BLKGETNAME : +strcpy (b,"/block/" ); +bdevname (bdev->bd_contains, b+7 ); +if (bdev->bd_contains != bdev) { +char *e = b +strlen (b); + *e++ ='/' ; +bdevname (bdev, e); + } +if (copy_to_user ((char __user *)arg, b,strlen (b)+1 )) +return -EFAULT ; +return 0 ; +case BLKFLSBUF :if (!capable (CAP_SYS_ADMIN ))return -EACCES ;
include/linux/fs.h +2 -0
@@ -218,6 +218,8 @@ extern int dir_notify_enable;#define BLKTRACESTOP _IO(0x12,117)#define BLKTRACETEARDOWN _IO(0x12,118) +#define BLKGETNAME _IOR(0x12, 119, char [1024]) +#define BMAP_IOCTL 1/* obsolete - kept for compatibility */ #define FIBMAP _IO(0x00,1)/* bmap access */ #define FIGETBSZ _IO(0x00,2)/* get the block size used for bmap */
Re: [PATCH 007 of 7] md: Get name for block device in sysfs
Quoted 23 lines · NeilBrown
Given an fd on a block device, returns a string like
/block/sda/sda1which can be used to find related information in /sys.
Ideally we should have an ioctl that works on char devices as well, but that seems far from trivial, so it seems reasonable to have this until the later can be implemented.
Cc Jens Axboe <[email protected]>Signed-off-by Neil Brown <[email protected]>### Diffstat output
./block/ioctl.c | 13 +++++++++++++ ./include/linux/fs.h | 2 ++ 2 files changed, 15 insertions(+)diff
.prev/block/ioctl.c./block/ioctl.c
block/ioctl.c 2007-12-14 16:15:41.000000000 +1100 int blkdev_ioctl(struct inode *inode, st · line 234
Quoted 8 lines
block/ioctl.c 2007-12-14 16:15:41.000000000 +1100 renamed from block/ioctl.c 2007-12-14 17:18:50.000000000 +1100 +3
-0@@ -227,8 +227,21 @@ int blkdev_ioctl(struct inode *inode, st struct block_device *bdev = inode->i_bdev; struct gendisk *disk = bdev->bd_disk; int ret, n; + char b[BDEVNAME_SIZE*2 + 10]; switch(cmd) { + case BLKGETNAME: + strcpy(b, "/block/");
As pointed out to when you came up with the idea, we can't do this. A devpath is a path to the device and will not necessarily start with "/block" for block devices. It may start with "/devices" and can be much longer than BDEVNAME_SIZE*2 + 10.
Please do not apply!
Kay
Re: [PATCH 007 of 7] md: Get name for block device in sysfs
Quoted 7 lines · On Saturday December 15, [email protected] wrote:
Quoted 6 lines · NeilBrown
Given an fd on a block device, returns a string like
/block/sda/sda1which can be used to find related information in /sys.
....
Quoted 5 lines
As pointed out to when you came up with the idea, we can't do this. A devpath is a path to the device and will not necessarily start with "/block" for block devices. It may start with "/devices" and can be much longer than BDEVNAME_SIZE*2 + 10.
When you say "will not necessarily" can I take that to mean that it currently does, but it might (will) change??
In that case can we have the patch as it stands and when the path to block devices in /sys changes, the ioctl can be changed at the same time to match?
Or are you saying that as the kernel is today, some block devices appear under /devices/..., in which case could you please give an example?
Thanks,
NeilBrown
Re: [PATCH 007 of 7] md: Get name for block device in sysfs
Quoted 10 lines · Neil Brown
Quoted 7 lines · On Saturday December 15, [email protected] wrote:
Quoted 6 lines · NeilBrown
Given an fd on a block device, returns a string like
/block/sda/sda1which can be used to find related information in /sys.
....
Quoted 1 line
Quoted 7 lines
Quoted 4 lines
As pointed out to when you came up with the idea, we can't do this. A devpath is a path to the device and will not necessarily start with "/block" for block devices. It may start with "/devices" and can be much longer than BDEVNAME_SIZE*2 + 10.
When you say "will not necessarily" can I take that to mean that it currently does, but it might (will) change??
It's in -mm. The devpath for all block devices, like for all other devices, will start with /devices/* if !SYSFS_DEPRECATED.
Quoted 3 lines
In that case can we have the patch as it stands and when the path to block devices in /sys changes, the ioctl can be changed at the same time to match?
No, you have to use kobject_get_path() to get the path to the object. This will also handle devices where the name contains '/' which needs to be translated to '!', which is broken in this patch.
Quoted 3 lines
Or are you saying that as the kernel is today, some block devices appear under /devices/..., in which case could you please give an example?
We expect the next kernel to have it.
Btw: BLKGETNAME should probably be renamed to something which contains DEVPATH, to make clear that it's a path to, and not the name of the device.
Kay
/sys/block [was: [PATCH 007 of 7] md: Get name for block device in sysfs]
Quoted 13 lines · Kay Sievers
Quoted 12 lines · Neil Brown
Quoted 6 lines · On Saturday December 15, [email protected] wrote:
Quoted 5 lines · NeilBrown
Given an fd on a block device, returns a string like
/block/sda/sda1which can be used to find related information in /sys.
....
Quoted 4 lines
As pointed out to when you came up with the idea, we can't do this. A devpath is a path to the device and will not necessarily start with "/block" for block devices. It may start with "/devices" and can be much longer than BDEVNAME_SIZE*2 + 10.
Quoted 5 lines
Quoted 2 lines
When you say "will not necessarily" can I take that to mean that it currently does, but it might (will) change??
It's in -mm. The devpath for all block devices, like for all other devices, will start with /devices/* if !SYSFS_DEPRECATED.
This is the second time I come across this (planned?) change, and for the second time I can't understand it.
How to distinguish char devices from block devices in sysfs? Is the only way to read a symlink `subsystem' in the device directory?
For now, I've a shell code (used heavily in numerous places), which looks like this:
function makedev() {
...
case $DEVPATH in
/block/*) TYPE=b ;;
*) TYPE=c ;;
esac
...
mknod /dev/$DEV $TYPE $MAJOR $MINOR
}The only external process invocation in there is mknod, all the rest is done using pure shell constructs. Is it really necessary to spawn another process just to read a symlink now? It will be almost 2 times slower....
(Sure thing this may be rewritten in C, but using shell it's MUCH easier to customize if necessary.)
Also, /sys/block/ directory is very easy to use currently, -- unlike other /sys/ stuff which is way too deep and often placed in unknown/unexpected places (and /sys/class/ and /sys/bus/ directories are changing all the time).
What's the benefit of moving things from /sys/block/ to /sys/devices/ ?
Thanks.
/mjt
Re: /sys/block [was: [PATCH 007 of 7] md: Get name for block device in sysfs]
Quoted 20 lines · Michael Tokarev
Quoted 13 lines · Kay Sievers
Quoted 12 lines · Neil Brown
Quoted 6 lines · On Saturday December 15, [email protected] wrote:
Quoted 5 lines · NeilBrown
Given an fd on a block device, returns a string like
/block/sda/sda1which can be used to find related information in /sys.
....
Quoted 4 lines
As pointed out to when you came up with the idea, we can't do this. A devpath is a path to the device and will not necessarily start with "/block" for block devices. It may start with "/devices" and can be much longer than BDEVNAME_SIZE*2 + 10.
Quoted 5 lines
Quoted 2 lines
When you say "will not necessarily" can I take that to mean that it currently does, but it might (will) change??
It's in -mm. The devpath for all block devices, like for all other devices, will start with /devices/* if !SYSFS_DEPRECATED.
Quoted 6 lines
This is the second time I come across this (planned?) change, and for the second time I can't understand it.
How to distinguish char devices from block devices in sysfs? Is the only way to read a symlink `subsystem' in the device directory?
By its subsystem value (block), from the symlink, from the environment, or from $1.
Quoted 13 lines
For now, I've a shell code (used heavily in numerous places), which looks like this:
function makedev() { ... case $DEVPATH in /block/*) TYPE=b ;; *) TYPE=c ;; esac ... mknod /dev/$DEV $TYPE $MAJOR $MINOR }
Quoted 4 lines
The only external process invocation in there is mknod, all the rest is done using pure shell constructs. Is it really necessary to spawn another process just to read a symlink now? It will be almost 2 times slower....
No need.
Quoted 2 lines
(Sure thing this may be rewritten in C, but using shell it's MUCH easier to customize if necessary.)
$SUBSYSTEM == "block"
Quoted 4 lines
Also,
/sys/block/directory is very easy to use currently, -- unlike other/sys/stuff which is way too deep and often placed in unknown/unexpected places (and/sys/class/and/sys/bus/directories are changing all the time).
/sys/block is still there and contains symlinks. And all this happens only for !SYSFS_DEPRECATED.
Quoted 2 lines
What's the benefit of moving things from
/sys/block/to/sys/devices/?
Unification. Block devices are "struct devices", use a class, use the common driver core code instead of their own, show up in the tree, and can be parents for other devices.
Kay
Re: /sys/block [was: [PATCH 007 of 7] md: Get name for block device in sysfs]
Quoted 1 line · Kay Sievers
On Mon, 2007-12-17 at 08:29 +0300, Michael Tokarev wrote:
[]
Quoted 6 lines
Quoted 3 lines
How to distinguish char devices from block devices in sysfs? Is the only way to read a symlink `subsystem' in the device directory?
By its subsystem value (block), from the symlink, from the environment, or from $1.
Environment and $1 comes as arguments for hotplug helper, not when scanning /sys/.
Quoted 13 lines
Quoted 13 lines
For now, I've a shell code (used heavily in numerous places), which looks like this:
function makedev() { ... case $DEVPATH in /block/*) TYPE=b ;; *) TYPE=c ;; esac ... mknod /dev/$DEV $TYPE $MAJOR $MINOR }
Quoted 6 lines
Quoted 4 lines
The only external process invocation in there is mknod, all the rest is done using pure shell constructs. Is it really necessary to spawn another process just to read a symlink now? It will be almost 2 times slower....
No need.
It seems there IS a need now ;)
Thanks for the clarification.
/mjt
Re: /sys/block [was: [PATCH 007 of 7] md: Get name for block device in sysfs]
Quoted 11 lines · Michael Tokarev
Quoted 1 line · Kay Sievers
On Mon, 2007-12-17 at 08:29 +0300, Michael Tokarev wrote:
[]
Quoted 5 lines
Quoted 3 lines
How to distinguish char devices from block devices in sysfs? Is the only way to read a symlink `subsystem' in the device directory?
By its subsystem value (block), from the symlink, from the environment, or from $1.
Environment and $1 comes as arguments for hotplug helper, not when scanning
/sys/.
By the way, that's one of reasons I asked about useful content in uevent files (but failed to provide a patch so far ;). In 2.6.23, those files ARE readable finally, but doesn't contain much info yet.
/mjt