raid5: create multiple threads to handle stripes
RFC v2 1/1 raid5: create multiple threads to handle stripes
This is a new tempt to make raid5 handle stripes in multiple threads, as suggested by Neil to have maxium flexibility and better numa binding. It basically is a combination of my first and second generation patches. By default, no multiple thread is enabled (all stripes are handled by raid5d).
An example to enable multiple threads:
#echo 3 > /sys/block/md0/md/auxthread_number
This will create 3 auxiliary threads to handle stripes. The threads can run on any cpus and handle stripes produced by any cpus.
#echo 1-3 > /sys/block/md0/md/aux0_cpulist
This will bind auxiliary thread 0 to cpu 1-3, and this thread will only handle stripes produced by cpu 1-3. User tool can further change the thread's affinity, but the thread can only handle stripes produced by cpu 1-3 till the sysfs entry is changed again.
If stripes produced by a CPU aren't handled by any auxiliary thread, such stripes will be handled by raid5d. Otherwise, raid5d doesn't handle any stripes.
Please let me know how do you think about it. I'll split the patch to a more reviewable form if no one objects the idea.
--- drivers/md/bitmap.c | 48 ++++-- drivers/md/md.c | 158 ++++++++++++++------- drivers/md/md.h | 12 - drivers/md/multipath.c | 3 drivers/md/raid1.c | 3 drivers/md/raid10.c | 3 drivers/md/raid5.c | 354 +++++++++++++++++++++++++++++++++++++++++++++---- drivers/md/raid5.h | 18 ++ 8 files changed, 494 insertions(+), 105 deletions(-)
drivers/md/raid5.c +328 -26
@@ -196,6 +196,21 @@ static int stripe_operations_active(strutest_bit (STRIPE_COMPUTE_RUN , &sh->state); } +static void raid5_wakeup_stripe_thread (struct stripe_head *sh) +{ +struct r5conf *conf = sh->raid_conf; +struct raid5_percpu *percpu; +int i, orphaned =1 ; + + percpu =per_cpu_ptr (conf->percpu, sh->cpu); +for_each_cpu (i, &percpu->handle_threads) { +md_wakeup_thread (conf->aux_threads[i]->thread); + orphaned =0 ; + } +if (orphaned) +md_wakeup_thread (conf->mddev->thread); +} +static void do_release_stripe (struct r5conf *conf,struct stripe_head *sh) {BUG_ON (!list_empty (&sh->lru));
@@ -208,9 +223,19 @@ static void do_release_stripe(struct r5c sh->bm_seq - conf->seq_write > 0) list_add_tail(&sh->lru, &conf->bitmap_list); else { +int cpu = sh->cpu; +struct raid5_percpu *percpu; +if (!cpu_online (cpu)) { + cpu =cpumask_any (cpu_online_mask); + sh->cpu = cpu; + } + percpu =per_cpu_ptr (conf->percpu, cpu); +clear_bit (STRIPE_DELAYED , &sh->state);clear_bit (STRIPE_BIT_DELAY , &sh->state); -list_add_tail (&sh->lru, &conf->handle_list); +list_add_tail (&sh->lru, &percpu->handle_list); +raid5_wakeup_stripe_thread (sh); +return ; }md_wakeup_thread (conf->mddev->thread); }else {
@@ -355,6 +380,7 @@ static void init_stripe(struct stripe_heraid5_build_block (sh, i, previous); }insert_hash (conf, sh); + sh->cpu =smp_processor_id (); } static struct stripe_head *__find_stripe(struct r5conf *conf, sector_t sector,
@@ -3689,12 +3715,19 @@ static void raid5_activate_delayed(strucwhile (!list_empty (&conf->delayed_list)) {struct list_head *l = conf->delayed_list.next;struct stripe_head *sh; +int cpu; sh = list_entry(l, struct stripe_head, lru);list_del_init (l);clear_bit (STRIPE_DELAYED , &sh->state);if (!test_and_set_bit (STRIPE_PREREAD_ACTIVE , &sh->state))atomic_inc (&conf->preread_active_stripes);list_add_tail (&sh->lru, &conf->hold_list); + cpu = sh->cpu; +if (!cpu_online (cpu)) { + cpu =cpumask_any (cpu_online_mask); + sh->cpu = cpu; + } +raid5_wakeup_stripe_thread (sh); } } }
@@ -3968,18 +4001,29 @@ static int chunk_aligned_read(struct mdd* head of the hold_list has changed, i.e. the head was promoted to the * handle_list. */ -static struct stripe_head *__get_priority_stripe (struct r5conf *conf) +static struct stripe_head *__get_priority_stripe (struct r5conf *conf, +cpumask_t *mask) { -struct stripe_head *sh; - +struct stripe_head *sh =NULL , *tmp; +struct list_head *handle_list =NULL ; +int cpu; + +/* Should we take action to avoid starvation of latter CPUs ? */ +for_each_cpu (cpu, mask) { +struct raid5_percpu *percpu =per_cpu_ptr (conf->percpu, cpu); +if (!list_empty (&percpu->handle_list)) { + handle_list = &percpu->handle_list; +break ; + } + }pr_debug ("%s: handle: %s hold: %s full_writes: %d bypass_count: %d\n" , __func__, -list_empty (&conf->handle_list) ?"empty" :"busy" , + !handle_list ?"empty" :"busy" ,list_empty (&conf->hold_list) ?"empty" :"busy" ,atomic_read (&conf->pending_full_writes), conf->bypass_count); -if (!list_empty (&conf->handle_list)) { - sh =list_entry (conf->handle_list.next,typeof (*sh), lru); +if (handle_list) { + sh =list_entry (handle_list->next,typeof (*sh), lru);if (list_empty (&conf->hold_list)) conf->bypass_count =0 ;
@@ -3997,12 +4041,23 @@ static struct stripe_head *__get_priorit ((conf->bypass_threshold && conf->bypass_count > conf->bypass_threshold) || atomic_read(&conf->pending_full_writes) == 0)) { - sh = list_entry(conf->hold_list.next, -typeof (*sh), lru); - conf->bypass_count -= conf->bypass_threshold; -if (conf->bypass_count <0 ) - conf->bypass_count =0 ; - } else + +list_for_each_entry (tmp, &conf->hold_list, lru) { +if (cpumask_test_cpu (tmp->cpu, mask) || + !cpu_online (tmp->cpu)) { + sh = tmp; +break ; + } + } + +if (sh) { + conf->bypass_count -= conf->bypass_threshold; +if (conf->bypass_count <0 ) + conf->bypass_count =0 ; + } + } + +if (!sh)return NULL ;list_del_init (&sh->lru);
@@ -4594,13 +4649,13 @@ static int retry_aligned_read(struct r5 }#define MAX_STRIPE_BATCH 8 -static int handle_active_stripes (struct r5conf *conf) +static int handle_active_stripes (struct r5conf *conf,cpumask_t *mask) {struct stripe_head *batch[MAX_STRIPE_BATCH ], *sh;int i, batch_size =0 ;while (batch_size <MAX_STRIPE_BATCH && - (sh =__get_priority_stripe (conf)) !=NULL ) + (sh =__get_priority_stripe (conf, mask)) !=NULL ) batch[batch_size++] = sh;if (batch_size ==0 )
@@ -4618,6 +4673,37 @@ static int handle_active_stripes(structreturn batch_size; } +static void raid5auxd (struct md_thread *thread) +{ +struct mddev *mddev = thread->mddev; +struct r5conf *conf = mddev->private; +struct blk_plug plug; +int handled; +cpumask_t *mask; +struct raid5_auxth *auxth = thread->thread_data; + +pr_debug ("+++ raid5auxd active\n" ); + +blk_start_plug (&plug); + handled =0 ; +spin_lock_irq (&conf->device_lock); +while (1 ) { +int batch_size; + mask = &auxth->worker_mask; + + batch_size =handle_active_stripes (conf, mask); +if (!batch_size) +break ; + handled += batch_size; + } +pr_debug ("%d stripes handled\n" , handled); + +spin_unlock_irq (&conf->device_lock); +blk_finish_plug (&plug); + +pr_debug ("--- raid5auxd inactive\n" ); +} +/* * This is our raid5 kernel thread. *
@@ -4625,8 +4711,9 @@ static int handle_active_stripes(struct* During the scan, completed stripes are saved for us by the interrupt * handler, so that they will not have to wait for our next wakeup. */ -static void raid5d (struct mddev *mddev) +static void raid5d (struct md_thread *thread) { +struct mddev *mddev = thread->mddev;struct r5conf *conf = mddev->private;int handled;struct blk_plug plug;
@@ -4664,7 +4751,7 @@ static void raid5d(struct mddev *mddev) handled++; } - batch_size =handle_active_stripes (conf); + batch_size =handle_active_stripes (conf, &conf->global_mask);if (!batch_size)break ; handled += batch_size;
@@ -4686,7 +4773,8 @@ static void raid5d(struct mddev *mddev) }static ssize_t -raid5_show_stripe_cache_size (struct mddev *mddev,char *page) +raid5_show_stripe_cache_size (struct mddev *mddev,struct md_sysfs_entry *entry, +char *page) {struct r5conf *conf = mddev->private;if (conf)
@@ -4722,7 +4810,8 @@ raid5_set_cache_size(struct mddev *mddevEXPORT_SYMBOL (raid5_set_cache_size);static ssize_t -raid5_store_stripe_cache_size (struct mddev *mddev,const char *page,size_t len) +raid5_store_stripe_cache_size (struct mddev *mddev,struct md_sysfs_entry *entry, +const char *page,size_t len) {struct r5conf *conf = mddev->private;unsigned long new;
@@ -4747,7 +4836,8 @@ raid5_stripecache_size = __ATTR(stripe_c raid5_store_stripe_cache_size);static ssize_t -raid5_show_preread_threshold (struct mddev *mddev,char *page) +raid5_show_preread_threshold (struct mddev *mddev,struct md_sysfs_entry *entry, +char *page) {struct r5conf *conf = mddev->private;if (conf)
@@ -4757,7 +4847,8 @@ raid5_show_preread_threshold(struct mdde }static ssize_t -raid5_store_preread_threshold (struct mddev *mddev,const char *page,size_t len) +raid5_store_preread_threshold (struct mddev *mddev,struct md_sysfs_entry *entry, +const char *page,size_t len) {struct r5conf *conf = mddev->private;unsigned long new;
@@ -4781,7 +4872,8 @@ raid5_preread_bypass_threshold = __ATTR( raid5_store_preread_threshold);static ssize_t -stripe_cache_active_show (struct mddev *mddev,char *page) +stripe_cache_active_show (struct mddev *mddev,struct md_sysfs_entry *entry, +char *page) {struct r5conf *conf = mddev->private;if (conf)
@@ -4793,10 +4885,198 @@ stripe_cache_active_show(struct mddev *mstatic struct md_sysfs_entry raid5_stripecache_active =__ATTR_RO (stripe_cache_active); +static void raid5_update_threads_handle_mask (struct mddev *mddev) +{ +int cpu, i; +struct raid5_percpu *percpu; +struct r5conf *conf = mddev->private; + +for_each_online_cpu (cpu) { + percpu =per_cpu_ptr (conf->percpu, cpu); +cpumask_clear (&percpu->handle_threads); + } +cpumask_copy (&conf->global_mask, cpu_online_mask); + +for (i =0 ; i < conf->aux_thread_num; i++) { +cpumask_t *worker_mask = &conf->aux_threads[i]->worker_mask; +for_each_cpu (cpu, worker_mask) { + percpu =per_cpu_ptr (conf->percpu, cpu); +cpumask_set_cpu (i, &percpu->handle_threads); + } +cpumask_andnot (&conf->global_mask, &conf->global_mask, + worker_mask); + } +} + +static ssize_t raid5_show_thread_cpulist (struct mddev *mddev, +struct md_sysfs_entry *entry,char *page) +{ +struct raid5_auxth *thread =container_of (entry, + struct raid5_auxth, sysfs_entry); + +return cpulist_scnprintf (page,PAGE_SIZE , &thread->worker_mask); +} + +static ssize_t +raid5_store_thread_cpulist (struct mddev *mddev,struct md_sysfs_entry *entry, +const char *page,size_t len) +{ +struct raid5_auxth *thread =container_of (entry, + struct raid5_auxth, sysfs_entry); +struct r5conf *conf = mddev->private; +cpumask_var_t mask; + +if (!alloc_cpumask_var (&mask,GFP_KERNEL )) +return -ENOMEM ; + +if (cpulist_parse (page, mask)) { +free_cpumask_var (mask); +return -EINVAL ; + } + +get_online_cpus (); +spin_lock_irq (&conf->device_lock); +cpumask_copy (&thread->worker_mask, mask); +raid5_update_threads_handle_mask (mddev); +spin_unlock_irq (&conf->device_lock); +put_online_cpus (); +set_cpus_allowed_ptr (thread->thread->tsk, mask); + +free_cpumask_var (mask); +return len; +} + +static ssize_t +raid5_show_auxthread_number (struct mddev *mddev,struct md_sysfs_entry *entry, +char *page) +{ +struct r5conf *conf = mddev->private; +if (conf) +return sprintf (page,"%d\n" , conf->aux_thread_num); +else +return 0 ; +} + +static void __free_aux_thread (struct mddev *mddev,struct raid5_auxth *thread) +{ +sysfs_remove_file (&mddev->kobj, &thread->sysfs_entry.attr); +md_unregister_thread (&thread->thread); +kfree (thread); +} + +static struct raid5_auxth *__create_aux_thread (struct mddev *mddev,int i) +{ +struct raid5_auxth *thread; +char name[10 ]; + + thread =kzalloc (sizeof (*thread),GFP_KERNEL ); +if (!thread) +return NULL ; +sprintf (name,"aux%d" , i); + thread->thread =md_register_thread (raid5auxd, mddev, name); +if (!thread->thread) { +kfree (thread); +return NULL ; + } +cpumask_copy (&thread->worker_mask, cpu_online_mask); + thread->thread->thread_data = thread; + +snprintf (thread->sysfs_name,sizeof (thread->sysfs_name) -1 , +"aux%d_cpulist" , i); + thread->sysfs_entry.attr.name = thread->sysfs_name; + thread->sysfs_entry.attr.mode =S_IRUGO |S_IWUSR ; +sysfs_attr_init (&thread->sysfs_entry.attr); + thread->sysfs_entry.show = raid5_show_thread_cpulist; + thread->sysfs_entry.store = raid5_store_thread_cpulist; + +if (sysfs_create_file (&mddev->kobj, &thread->sysfs_entry.attr)) { +md_unregister_thread (&thread->thread); +kfree (thread); +return NULL ; + } + +return thread; +} + +static ssize_t +raid5_store_auxthread_number (struct mddev *mddev,struct md_sysfs_entry *entry, +const char *page,size_t len) +{ +struct r5conf *conf = mddev->private; +unsigned long new; +int i; +struct raid5_auxth **threads; + +if (len >=PAGE_SIZE ) +return -EINVAL ; +if (!conf) +return -ENODEV ; + +if (strict_strtoul (page,10 , &new)) +return -EINVAL ; + +if (new == conf->aux_thread_num) +return len; + +/* There is no point creating more threads than cpu number */ +if (new >num_online_cpus ()) +return -EINVAL ; + +if (new > conf->aux_thread_num) { + threads =kzalloc (sizeof (struct raid5_auxth *) * new, +GFP_KERNEL ); +if (!threads) +return -ENOMEM ; + + i = conf->aux_thread_num; +while (i < new) { + threads[i] =__create_aux_thread (mddev, i); +if (!threads[i]) + goto error; + + i++; + } +memcpy (threads, conf->aux_threads, +sizeof (struct raid5_auxth *) * conf->aux_thread_num); +get_online_cpus (); +spin_lock_irq (&conf->device_lock); +kfree (conf->aux_threads); + conf->aux_threads = threads; + conf->aux_thread_num = new; +raid5_update_threads_handle_mask (mddev); +spin_unlock_irq (&conf->device_lock); +put_online_cpus (); + }else { +int old = conf->aux_thread_num; + +get_online_cpus (); +spin_lock_irq (&conf->device_lock); + conf->aux_thread_num = new; +raid5_update_threads_handle_mask (mddev); +spin_unlock_irq (&conf->device_lock); +put_online_cpus (); +for (i = new; i < old; i++) +__free_aux_thread (mddev, conf->aux_threads[i]); + } + +return len; +error: +while (--i >= conf->aux_thread_num) +__free_aux_thread (mddev, threads[i]); +kfree (threads); +return -ENOMEM ; +} + +static struct md_sysfs_entry +raid5_auxthread_number =__ATTR (auxthread_number,S_IRUGO |S_IWUSR , + raid5_show_auxthread_number, + raid5_store_auxthread_number); +static struct attribute *raid5_attrs[] = { &raid5_stripecache_size.attr, &raid5_stripecache_active.attr, &raid5_preread_bypass_threshold.attr, + &raid5_auxthread_number.attr,NULL , };static struct attribute_group raid5_attrs_group = {
@@ -4844,6 +5124,7 @@ static void raid5_free_percpu(struct r5cstatic void free_conf (struct r5conf *conf) { +kfree (conf->aux_threads);shrink_stripes (conf);raid5_free_percpu (conf);kfree (conf->disks);
@@ -4856,7 +5137,7 @@ static int raid456_cpu_notify(struct not void *hcpu) { struct r5conf *conf = container_of(nfb, struct r5conf, cpu_notify); -long cpu = (long )hcpu; +long cpu = (long )hcpu, anycpu;struct raid5_percpu *percpu =per_cpu_ptr (conf->percpu, cpu);switch (action) {
@@ -4875,9 +5156,17 @@ static int raid456_cpu_notify(struct not __func__, cpu);return notifier_from_errno (-ENOMEM ); } +INIT_LIST_HEAD (&(percpu->handle_list)); +cpumask_clear (&percpu->handle_threads);break ;case CPU_DEAD :case CPU_DEAD_FROZEN : +spin_lock_irq (&conf->device_lock); + anycpu =cpumask_any (cpu_online_mask); +list_splice_tail_init (&percpu->handle_list, + &per_cpu_ptr (conf->percpu, anycpu)->handle_list); +spin_unlock_irq (&conf->device_lock); +safe_put_page (percpu->spare_page);kfree (percpu->scribble); percpu->spare_page =NULL ;
@@ -4886,6 +5175,10 @@ static int raid456_cpu_notify(struct notdefault : break; } + +spin_lock_irq (&conf->device_lock); +raid5_update_threads_handle_mask (conf->mddev); +spin_unlock_irq (&conf->device_lock);return NOTIFY_OK ; }#endif
@@ -4906,20 +5199,24 @@ static int raid5_alloc_percpu(struct r5cget_online_cpus (); err =0 ;for_each_present_cpu (cpu) { +struct raid5_percpu *percpu =per_cpu_ptr (conf->percpu, cpu); +if (conf->level ==6 ) { spare_page =alloc_page (GFP_KERNEL );if (!spare_page) { err = -ENOMEM ;break ; } -per_cpu_ptr (conf->percpu, cpu)->spare_page = spare_page; + percpu->spare_page = spare_page; } scribble =kmalloc (conf->scribble_len,GFP_KERNEL );if (!scribble) { err = -ENOMEM ;break ; } -per_cpu_ptr (conf->percpu, cpu)->scribble = scribble; + percpu->scribble = scribble; +INIT_LIST_HEAD (&percpu->handle_list); +cpumask_clear (&percpu->handle_threads); }#ifdef CONFIG_HOTPLUG_CPU conf->cpu_notify.notifier_call = raid456_cpu_notify;
@@ -4975,7 +5272,6 @@ static struct r5conf *setup_conf(structspin_lock_init (&conf->device_lock);init_waitqueue_head (&conf->wait_for_stripe);init_waitqueue_head (&conf->wait_for_overlap); -INIT_LIST_HEAD (&conf->handle_list);INIT_LIST_HEAD (&conf->hold_list);INIT_LIST_HEAD (&conf->delayed_list);INIT_LIST_HEAD (&conf->bitmap_list);
@@ -4986,6 +5282,8 @@ static struct r5conf *setup_conf(struct conf->bypass_threshold =BYPASS_THRESHOLD ; conf->recovery_disabled = mddev->recovery_disabled -1 ; +cpumask_copy (&conf->global_mask, cpu_online_mask); + conf->raid_disks = mddev->raid_disks;if (mddev->reshape_position == MaxSector) conf->previous_raid_disks = mddev->raid_disks;
@@ -5402,6 +5700,10 @@ abort:static int stop (struct mddev *mddev) {struct r5conf *conf = mddev->private; +int i; + +for (i =0 ; i < conf->aux_thread_num; i++) +__free_aux_thread (mddev, conf->aux_threads[i]);md_unregister_thread (&mddev->thread);if (mddev->queue)
drivers/md/raid5.h +18 -0
@@ -211,6 +211,7 @@ struct stripe_head {enum check_states check_state;enum reconstruct_states reconstruct_state;spinlock_t stripe_lock; +int cpu;/** * struct stripe_operations * @target - STRIPE_OP_COMPUTE_BLK target
@@ -364,6 +365,14 @@ struct disk_info {struct md_rdev *rdev, *replacement; }; +struct raid5_auxth { +struct md_thread *thread; +/* which CPUs should the auxiliary thread handle stripes from */ +cpumask_t worker_mask; +struct md_sysfs_entry sysfs_entry; +char sysfs_name[20 ]; +}; +struct r5conf {struct hlist_head *stripe_hashtbl;struct mddev *mddev;
@@ -432,6 +441,11 @@ struct r5conf {* lists and performing address * conversions */ +struct list_head handle_list; +cpumask_t handle_threads;/* Which threads can the CPU's +* stripes be handled. It really +* is a bitmap to aux_threads +*/ }__percpu *percpu;size_t scribble_len;/* size of scribble region must be * associated with conf to handle
@@ -459,6 +473,10 @@ struct r5conf {* the new thread here until we fully activate the array. */ struct md_thread *thread; +int aux_thread_num; +struct raid5_auxth **aux_threads; +/* which CPUs should raid5d thread handle stripes from */ +cpumask_t global_mask; };/*
drivers/md/md.c +103 -55
476 lines not on this page · raw message
drivers/md/md.h +7 -5
@@ -479,8 +479,9 @@ struct md_personalitystruct md_sysfs_entry {struct attribute attr; -ssize_t (*show)(struct mddev *,char *); -ssize_t (*store)(struct mddev *,const char *,size_t ); +ssize_t (*show)(struct mddev *,struct md_sysfs_entry *,char *); +ssize_t (*store)(struct mddev *,struct md_sysfs_entry *, +const char *,size_t ); };extern struct attribute_group md_bitmap_group;
@@ -540,12 +541,13 @@ static inline void sysfs_unlink_rdev(strlist_for_each_entry_rcu (rdev, &((mddev)->disks), same_set) struct md_thread { -void (*run) (struct mddev *mddev); +void (*run) (struct md_thread *thread);struct mddev *mddev;wait_queue_head_t wqueue;unsigned long flags;struct task_struct *tsk;unsigned long timeout; +void *thread_data; };#define THREAD_WAKEUP 0
@@ -584,7 +586,7 @@ static inline void safe_put_page(structextern int register_md_personality (struct md_personality *p);extern int unregister_md_personality (struct md_personality *p);extern struct md_thread *md_register_thread ( -void (*run)(struct mddev *mddev), +void (*run)(struct md_thread *thread),struct mddev *mddev,const char *name);extern void md_unregister_thread (struct md_thread **threadp);
@@ -603,7 +605,7 @@ extern void md_super_write(struct mddevextern void md_super_wait (struct mddev *mddev);extern int sync_page_io (struct md_rdev *rdev,sector_t sector,int size,struct page *page,int rw,bool metadata_op); -extern void md_do_sync (struct mddev *mddev); +extern void md_do_sync (struct md_thread *thread);extern void md_new_event (struct mddev *mddev);extern int md_allow_write (struct mddev *mddev);extern void md_wait_for_blocked_rdev (struct md_rdev *rdev,struct mddev *mddev);
drivers/md/multipath.c +2 -1
@@ -335,8 +335,9 @@ abort:* 3. Performs writes following reads for array syncronising. */ -static void multipathd (struct mddev *mddev) +static void multipathd (struct md_thread *thread) { +struct mddev *mddev = thread->mddev;struct multipath_bh *mp_bh;struct bio *bio;unsigned long flags;
drivers/md/raid1.c +2 -1
@@ -2285,8 +2285,9 @@ read_more: } } -static void raid1d (struct mddev *mddev) +static void raid1d (struct md_thread *thread) { +struct mddev *mddev = thread->mddev;struct r1bio *r1_bio;unsigned long flags;struct r1conf *conf = mddev->private;
drivers/md/raid10.c +2 -1
@@ -2667,8 +2667,9 @@ static void handle_write_completed(struc } } -static void raid10d (struct mddev *mddev) +static void raid10d (struct md_thread *thread) { +struct mddev *mddev = thread->mddev;struct r10bio *r10_bio;unsigned long flags;struct r10conf *conf = mddev->private;
drivers/md/bitmap.c +32 -16
140 lines not on this page · raw message
Quoted 16 lines · Shaohua Li
This is a new tempt to make raid5 handle stripes in multiple threads, as suggested by Neil to have maxium flexibility and better numa binding. It basically is a combination of my first and second generation patches. By default, no multiple thread is enabled (all stripes are handled by raid5d).
An example to enable multiple threads:
#echo 3 >/sys/block/md0/md/auxthread_number
This will create 3 auxiliary threads to handle stripes. The threads can run on any cpus and handle stripes produced by any cpus.#echo 1-3 >
/sys/block/md0/md/aux0_cpulist
This will bind auxiliary thread 0 to cpu 1-3, and this thread will only handle stripes produced by cpu 1-3. User tool can further change the thread's affinity, but the thread can only handle stripes produced by cpu 1-3 till the sysfs entry is changed again.
Quoted 8 lines
If stripes produced by a CPU aren't handled by any auxiliary thread, such stripes will be handled by raid5d. Otherwise, raid5d doesn't handle any stripes.
Please let me know how do you think about it. I'll split the patch to a more reviewable form if no one objects the idea.
Signed-off-by Shaohua Li <[email protected]>
Looks ok to me.
I think the md_sysfs_entry changes are probably asking for a new md_thread kobj_type in the hierarchy rather than sprinkling a md_sysfs_entry around. Similar to what happens for rdevs... and I expect the threads may grow more attributes once there.
/sys/block/mdX/md/threadX/mask
...active?
...idle?
--
Dan
2012/8/8 Dan Williams <[email protected]>:
Quoted 28 lines · Shaohua Li
Quoted 16 lines
This is a new tempt to make raid5 handle stripes in multiple threads, as suggested by Neil to have maxium flexibility and better numa binding. It basically is a combination of my first and second generation patches. By default, no multiple thread is enabled (all stripes are handled by raid5d).
An example to enable multiple threads:
#echo 3 >/sys/block/md0/md/auxthread_number
This will create 3 auxiliary threads to handle stripes. The threads can run on any cpus and handle stripes produced by any cpus.#echo 1-3 >
/sys/block/md0/md/aux0_cpulist
This will bind auxiliary thread 0 to cpu 1-3, and this thread will only handle stripes produced by cpu 1-3. User tool can further change the thread's affinity, but the thread can only handle stripes produced by cpu 1-3 till the sysfs entry is changed again.Quoted 8 lines
If stripes produced by a CPU aren't handled by any auxiliary thread, such stripes will be handled by raid5d. Otherwise, raid5d doesn't handle any stripes.
Please let me know how do you think about it. I'll split the patch to a more reviewable form if no one objects the idea.
Signed-off-by Shaohua Li <[email protected]>Looks ok to me.
Quoted 8 lines
I think the
md_sysfs_entrychanges are probably asking for a newmd_threadkobj_typein the hierarchy rather than sprinkling amd_sysfs_entryaround. Similar to what happens for rdevs... and I expect the threads may grow more attributes once there.
/sys/block/mdX/md/threadX/mask
...active?
...idle?
Sure, this makes sense. I'll sort it out in patch submit.