Commit 90a9ed95 authored by Linus Torvalds's avatar Linus Torvalds Committed by Chris Metcalf

Merge branch 'for-linus' of git://neil.brown.name/md

* 'for-linus' of git://neil.brown.name/md: (24 commits)
  md: clean up do_md_stop
  md: fix another deadlock with removing sysfs attributes.
  md: move revalidate_disk() back outside open_mutex
  md/raid10: fix deadlock with unaligned read during resync
  md/bitmap:  separate out loading a bitmap from initialising the structures.
  md/bitmap: prepare for storing write-intent-bitmap via dm-dirty-log.
  md/bitmap: optimise scanning of empty bitmaps.
  md/bitmap: clean up plugging calls.
  md/bitmap: reduce dependence on sysfs.
  md/bitmap: white space clean up and similar.
  md/raid5: export raid5 unplugging interface.
  md/plug: optionally use plugger to unplug an array during resync/recovery.
  md/raid5: add simple plugging infrastructure.
  md/raid5: export is_congested test
  raid5: Don't set read-ahead when there is no queue
  md: add support for raising dm events.
  md: export various start/stop interfaces
  md: split out md_rdev_init
  md: be more careful setting MD_CHANGE_CLEAN
  md/raid5: ensure we create a unique name for kmem_cache when mddev has no gendisk
  ...
parents 8cbd84f2 fd8aa2c1
...@@ -22,6 +22,20 @@ config ASYNC_RAID6_RECOV ...@@ -22,6 +22,20 @@ config ASYNC_RAID6_RECOV
tristate tristate
select ASYNC_CORE select ASYNC_CORE
select ASYNC_PQ select ASYNC_PQ
select ASYNC_XOR
config ASYNC_RAID6_TEST
tristate "Self test for hardware accelerated raid6 recovery"
depends on ASYNC_RAID6_RECOV
select ASYNC_MEMCPY
---help---
This is a one-shot self test that permutes through the
recovery of all the possible two disk failure scenarios for a
N-disk array. Recovery is performed with the asynchronous
raid6 recovery routines, and will optionally use an offload
engine if one is available.
If unsure, say N.
config ASYNC_TX_DISABLE_PQ_VAL_DMA config ASYNC_TX_DISABLE_PQ_VAL_DMA
bool bool
......
...@@ -121,7 +121,7 @@ config MD_RAID10 ...@@ -121,7 +121,7 @@ config MD_RAID10
config MD_RAID456 config MD_RAID456
tristate "RAID-4/RAID-5/RAID-6 mode" tristate "RAID-4/RAID-5/RAID-6 mode"
depends on BLK_DEV_MD depends on BLK_DEV_MD
select MD_RAID6_PQ select RAID6_PQ
select ASYNC_MEMCPY select ASYNC_MEMCPY
select ASYNC_XOR select ASYNC_XOR
select ASYNC_PQ select ASYNC_PQ
...@@ -165,22 +165,6 @@ config MULTICORE_RAID456 ...@@ -165,22 +165,6 @@ config MULTICORE_RAID456
If unsure, say N. If unsure, say N.
config MD_RAID6_PQ
tristate
config ASYNC_RAID6_TEST
tristate "Self test for hardware accelerated raid6 recovery"
depends on MD_RAID6_PQ
select ASYNC_RAID6_RECOV
---help---
This is a one-shot self test that permutes through the
recovery of all the possible two disk failure scenarios for a
N-disk array. Recovery is performed with the asynchronous
raid6 recovery routines, and will optionally use an offload
engine if one is available.
If unsure, say N.
config MD_MULTIPATH config MD_MULTIPATH
tristate "Multipath I/O support" tristate "Multipath I/O support"
depends on BLK_DEV_MD depends on BLK_DEV_MD
......
...@@ -12,13 +12,6 @@ dm-log-userspace-y \ ...@@ -12,13 +12,6 @@ dm-log-userspace-y \
+= dm-log-userspace-base.o dm-log-userspace-transfer.o += dm-log-userspace-base.o dm-log-userspace-transfer.o
md-mod-y += md.o bitmap.o md-mod-y += md.o bitmap.o
raid456-y += raid5.o raid456-y += raid5.o
raid6_pq-y += raid6algos.o raid6recov.o raid6tables.o \
raid6int1.o raid6int2.o raid6int4.o \
raid6int8.o raid6int16.o raid6int32.o \
raid6altivec1.o raid6altivec2.o raid6altivec4.o \
raid6altivec8.o \
raid6mmx.o raid6sse1.o raid6sse2.o
hostprogs-y += mktables
# Note: link order is important. All raid personalities # Note: link order is important. All raid personalities
# and must come before md.o, as they each initialise # and must come before md.o, as they each initialise
...@@ -29,7 +22,6 @@ obj-$(CONFIG_MD_LINEAR) += linear.o ...@@ -29,7 +22,6 @@ obj-$(CONFIG_MD_LINEAR) += linear.o
obj-$(CONFIG_MD_RAID0) += raid0.o obj-$(CONFIG_MD_RAID0) += raid0.o
obj-$(CONFIG_MD_RAID1) += raid1.o obj-$(CONFIG_MD_RAID1) += raid1.o
obj-$(CONFIG_MD_RAID10) += raid10.o obj-$(CONFIG_MD_RAID10) += raid10.o
obj-$(CONFIG_MD_RAID6_PQ) += raid6_pq.o
obj-$(CONFIG_MD_RAID456) += raid456.o obj-$(CONFIG_MD_RAID456) += raid456.o
obj-$(CONFIG_MD_MULTIPATH) += multipath.o obj-$(CONFIG_MD_MULTIPATH) += multipath.o
obj-$(CONFIG_MD_FAULTY) += faulty.o obj-$(CONFIG_MD_FAULTY) += faulty.o
...@@ -45,75 +37,6 @@ obj-$(CONFIG_DM_MIRROR) += dm-mirror.o dm-log.o dm-region-hash.o ...@@ -45,75 +37,6 @@ obj-$(CONFIG_DM_MIRROR) += dm-mirror.o dm-log.o dm-region-hash.o
obj-$(CONFIG_DM_LOG_USERSPACE) += dm-log-userspace.o obj-$(CONFIG_DM_LOG_USERSPACE) += dm-log-userspace.o
obj-$(CONFIG_DM_ZERO) += dm-zero.o obj-$(CONFIG_DM_ZERO) += dm-zero.o
quiet_cmd_unroll = UNROLL $@
cmd_unroll = $(AWK) -f$(srctree)/$(src)/unroll.awk -vN=$(UNROLL) \
< $< > $@ || ( rm -f $@ && exit 1 )
ifeq ($(CONFIG_ALTIVEC),y)
altivec_flags := -maltivec -mabi=altivec
endif
ifeq ($(CONFIG_DM_UEVENT),y) ifeq ($(CONFIG_DM_UEVENT),y)
dm-mod-objs += dm-uevent.o dm-mod-objs += dm-uevent.o
endif endif
targets += raid6int1.c
$(obj)/raid6int1.c: UNROLL := 1
$(obj)/raid6int1.c: $(src)/raid6int.uc $(src)/unroll.awk FORCE
$(call if_changed,unroll)
targets += raid6int2.c
$(obj)/raid6int2.c: UNROLL := 2
$(obj)/raid6int2.c: $(src)/raid6int.uc $(src)/unroll.awk FORCE
$(call if_changed,unroll)
targets += raid6int4.c
$(obj)/raid6int4.c: UNROLL := 4
$(obj)/raid6int4.c: $(src)/raid6int.uc $(src)/unroll.awk FORCE
$(call if_changed,unroll)
targets += raid6int8.c
$(obj)/raid6int8.c: UNROLL := 8
$(obj)/raid6int8.c: $(src)/raid6int.uc $(src)/unroll.awk FORCE
$(call if_changed,unroll)
targets += raid6int16.c
$(obj)/raid6int16.c: UNROLL := 16
$(obj)/raid6int16.c: $(src)/raid6int.uc $(src)/unroll.awk FORCE
$(call if_changed,unroll)
targets += raid6int32.c
$(obj)/raid6int32.c: UNROLL := 32
$(obj)/raid6int32.c: $(src)/raid6int.uc $(src)/unroll.awk FORCE
$(call if_changed,unroll)
CFLAGS_raid6altivec1.o += $(altivec_flags)
targets += raid6altivec1.c
$(obj)/raid6altivec1.c: UNROLL := 1
$(obj)/raid6altivec1.c: $(src)/raid6altivec.uc $(src)/unroll.awk FORCE
$(call if_changed,unroll)
CFLAGS_raid6altivec2.o += $(altivec_flags)
targets += raid6altivec2.c
$(obj)/raid6altivec2.c: UNROLL := 2
$(obj)/raid6altivec2.c: $(src)/raid6altivec.uc $(src)/unroll.awk FORCE
$(call if_changed,unroll)
CFLAGS_raid6altivec4.o += $(altivec_flags)
targets += raid6altivec4.c
$(obj)/raid6altivec4.c: UNROLL := 4
$(obj)/raid6altivec4.c: $(src)/raid6altivec.uc $(src)/unroll.awk FORCE
$(call if_changed,unroll)
CFLAGS_raid6altivec8.o += $(altivec_flags)
targets += raid6altivec8.c
$(obj)/raid6altivec8.c: UNROLL := 8
$(obj)/raid6altivec8.c: $(src)/raid6altivec.uc $(src)/unroll.awk FORCE
$(call if_changed,unroll)
quiet_cmd_mktable = TABLE $@
cmd_mktable = $(obj)/mktables > $@ || ( rm -f $@ && exit 1 )
targets += raid6tables.c
$(obj)/raid6tables.c: $(obj)/mktables FORCE
$(call if_changed,mktable)
This diff is collapsed.
...@@ -222,6 +222,10 @@ struct bitmap { ...@@ -222,6 +222,10 @@ struct bitmap {
unsigned long file_pages; /* number of pages in the file */ unsigned long file_pages; /* number of pages in the file */
int last_page_size; /* bytes in the last page */ int last_page_size; /* bytes in the last page */
unsigned long logattrs; /* used when filemap_attr doesn't exist
* because we are working with a dirty_log
*/
unsigned long flags; unsigned long flags;
int allclean; int allclean;
...@@ -243,12 +247,14 @@ struct bitmap { ...@@ -243,12 +247,14 @@ struct bitmap {
wait_queue_head_t behind_wait; wait_queue_head_t behind_wait;
struct sysfs_dirent *sysfs_can_clear; struct sysfs_dirent *sysfs_can_clear;
}; };
/* the bitmap API */ /* the bitmap API */
/* these are used only by md/bitmap */ /* these are used only by md/bitmap */
int bitmap_create(mddev_t *mddev); int bitmap_create(mddev_t *mddev);
int bitmap_load(mddev_t *mddev);
void bitmap_flush(mddev_t *mddev); void bitmap_flush(mddev_t *mddev);
void bitmap_destroy(mddev_t *mddev); void bitmap_destroy(mddev_t *mddev);
......
This diff is collapsed.
...@@ -29,6 +29,26 @@ ...@@ -29,6 +29,26 @@
typedef struct mddev_s mddev_t; typedef struct mddev_s mddev_t;
typedef struct mdk_rdev_s mdk_rdev_t; typedef struct mdk_rdev_s mdk_rdev_t;
/* generic plugging support - like that provided with request_queue,
* but does not require a request_queue
*/
struct plug_handle {
void (*unplug_fn)(struct plug_handle *);
struct timer_list unplug_timer;
struct work_struct unplug_work;
unsigned long unplug_flag;
};
#define PLUGGED_FLAG 1
void plugger_init(struct plug_handle *plug,
void (*unplug_fn)(struct plug_handle *));
void plugger_set_plug(struct plug_handle *plug);
int plugger_remove_plug(struct plug_handle *plug);
static inline void plugger_flush(struct plug_handle *plug)
{
del_timer_sync(&plug->unplug_timer);
cancel_work_sync(&plug->unplug_work);
}
/* /*
* MD's 'extended' device * MD's 'extended' device
*/ */
...@@ -125,6 +145,10 @@ struct mddev_s ...@@ -125,6 +145,10 @@ struct mddev_s
int suspended; int suspended;
atomic_t active_io; atomic_t active_io;
int ro; int ro;
int sysfs_active; /* set when sysfs deletes
* are happening, so run/
* takeover/stop are not safe
*/
struct gendisk *gendisk; struct gendisk *gendisk;
...@@ -297,9 +321,14 @@ struct mddev_s ...@@ -297,9 +321,14 @@ struct mddev_s
* hot-adding a bitmap. It should * hot-adding a bitmap. It should
* eventually be settable by sysfs. * eventually be settable by sysfs.
*/ */
/* When md is serving under dm, it might use a
* dirty_log to store the bits.
*/
struct dm_dirty_log *log;
struct mutex mutex; struct mutex mutex;
unsigned long chunksize; unsigned long chunksize;
unsigned long daemon_sleep; /* how many seconds between updates? */ unsigned long daemon_sleep; /* how many jiffies between updates? */
unsigned long max_write_behind; /* write-behind mode */ unsigned long max_write_behind; /* write-behind mode */
int external; int external;
} bitmap_info; } bitmap_info;
...@@ -308,6 +337,8 @@ struct mddev_s ...@@ -308,6 +337,8 @@ struct mddev_s
struct list_head all_mddevs; struct list_head all_mddevs;
struct attribute_group *to_remove; struct attribute_group *to_remove;
struct plug_handle *plug; /* if used by personality */
/* Generic barrier handling. /* Generic barrier handling.
* If there is a pending barrier request, all other * If there is a pending barrier request, all other
* writes are blocked while the devices are flushed. * writes are blocked while the devices are flushed.
...@@ -318,6 +349,7 @@ struct mddev_s ...@@ -318,6 +349,7 @@ struct mddev_s
struct bio *barrier; struct bio *barrier;
atomic_t flush_pending; atomic_t flush_pending;
struct work_struct barrier_work; struct work_struct barrier_work;
struct work_struct event_work; /* used by dm to report failure event */
}; };
...@@ -382,6 +414,18 @@ struct md_sysfs_entry { ...@@ -382,6 +414,18 @@ struct md_sysfs_entry {
}; };
extern struct attribute_group md_bitmap_group; extern struct attribute_group md_bitmap_group;
static inline struct sysfs_dirent *sysfs_get_dirent_safe(struct sysfs_dirent *sd, char *name)
{
if (sd)
return sysfs_get_dirent(sd, NULL, name);
return sd;
}
static inline void sysfs_notify_dirent_safe(struct sysfs_dirent *sd)
{
if (sd)
sysfs_notify_dirent(sd);
}
static inline char * mdname (mddev_t * mddev) static inline char * mdname (mddev_t * mddev)
{ {
return mddev->gendisk ? mddev->gendisk->disk_name : "mdX"; return mddev->gendisk ? mddev->gendisk->disk_name : "mdX";
...@@ -474,5 +518,14 @@ extern int md_integrity_register(mddev_t *mddev); ...@@ -474,5 +518,14 @@ extern int md_integrity_register(mddev_t *mddev);
extern void md_integrity_add_rdev(mdk_rdev_t *rdev, mddev_t *mddev); extern void md_integrity_add_rdev(mdk_rdev_t *rdev, mddev_t *mddev);
extern int strict_strtoul_scaled(const char *cp, unsigned long *res, int scale); extern int strict_strtoul_scaled(const char *cp, unsigned long *res, int scale);
extern void restore_bitmap_write_access(struct file *file); extern void restore_bitmap_write_access(struct file *file);
extern void md_unplug(mddev_t *mddev);
extern void mddev_init(mddev_t *mddev);
extern int md_run(mddev_t *mddev);
extern void md_stop(mddev_t *mddev);
extern void md_stop_writes(mddev_t *mddev);
extern void md_rdev_init(mdk_rdev_t *rdev);
extern void mddev_suspend(mddev_t *mddev);
extern void mddev_resume(mddev_t *mddev);
#endif /* _MD_MD_H */ #endif /* _MD_MD_H */
...@@ -825,11 +825,29 @@ static int make_request(mddev_t *mddev, struct bio * bio) ...@@ -825,11 +825,29 @@ static int make_request(mddev_t *mddev, struct bio * bio)
*/ */
bp = bio_split(bio, bp = bio_split(bio,
chunk_sects - (bio->bi_sector & (chunk_sects - 1)) ); chunk_sects - (bio->bi_sector & (chunk_sects - 1)) );
/* Each of these 'make_request' calls will call 'wait_barrier'.
* If the first succeeds but the second blocks due to the resync
* thread raising the barrier, we will deadlock because the
* IO to the underlying device will be queued in generic_make_request
* and will never complete, so will never reduce nr_pending.
* So increment nr_waiting here so no new raise_barriers will
* succeed, and so the second wait_barrier cannot block.
*/
spin_lock_irq(&conf->resync_lock);
conf->nr_waiting++;
spin_unlock_irq(&conf->resync_lock);
if (make_request(mddev, &bp->bio1)) if (make_request(mddev, &bp->bio1))
generic_make_request(&bp->bio1); generic_make_request(&bp->bio1);
if (make_request(mddev, &bp->bio2)) if (make_request(mddev, &bp->bio2))
generic_make_request(&bp->bio2); generic_make_request(&bp->bio2);
spin_lock_irq(&conf->resync_lock);
conf->nr_waiting--;
wake_up(&conf->wait_barrier);
spin_unlock_irq(&conf->resync_lock);
bio_pair_release(bp); bio_pair_release(bp);
return 0; return 0;
bad_map: bad_map:
......
...@@ -201,11 +201,11 @@ static void __release_stripe(raid5_conf_t *conf, struct stripe_head *sh) ...@@ -201,11 +201,11 @@ static void __release_stripe(raid5_conf_t *conf, struct stripe_head *sh)
if (test_bit(STRIPE_HANDLE, &sh->state)) { if (test_bit(STRIPE_HANDLE, &sh->state)) {
if (test_bit(STRIPE_DELAYED, &sh->state)) { if (test_bit(STRIPE_DELAYED, &sh->state)) {
list_add_tail(&sh->lru, &conf->delayed_list); list_add_tail(&sh->lru, &conf->delayed_list);
blk_plug_device(conf->mddev->queue); plugger_set_plug(&conf->plug);
} else if (test_bit(STRIPE_BIT_DELAY, &sh->state) && } else if (test_bit(STRIPE_BIT_DELAY, &sh->state) &&
sh->bm_seq - conf->seq_write > 0) { sh->bm_seq - conf->seq_write > 0) {
list_add_tail(&sh->lru, &conf->bitmap_list); list_add_tail(&sh->lru, &conf->bitmap_list);
blk_plug_device(conf->mddev->queue); plugger_set_plug(&conf->plug);
} else { } else {
clear_bit(STRIPE_BIT_DELAY, &sh->state); clear_bit(STRIPE_BIT_DELAY, &sh->state);
list_add_tail(&sh->lru, &conf->handle_list); list_add_tail(&sh->lru, &conf->handle_list);
...@@ -434,7 +434,6 @@ static int has_failed(raid5_conf_t *conf) ...@@ -434,7 +434,6 @@ static int has_failed(raid5_conf_t *conf)
} }
static void unplug_slaves(mddev_t *mddev); static void unplug_slaves(mddev_t *mddev);
static void raid5_unplug_device(struct request_queue *q);
static struct stripe_head * static struct stripe_head *
get_active_stripe(raid5_conf_t *conf, sector_t sector, get_active_stripe(raid5_conf_t *conf, sector_t sector,
...@@ -464,7 +463,7 @@ get_active_stripe(raid5_conf_t *conf, sector_t sector, ...@@ -464,7 +463,7 @@ get_active_stripe(raid5_conf_t *conf, sector_t sector,
< (conf->max_nr_stripes *3/4) < (conf->max_nr_stripes *3/4)
|| !conf->inactive_blocked), || !conf->inactive_blocked),
conf->device_lock, conf->device_lock,
raid5_unplug_device(conf->mddev->queue) md_raid5_unplug_device(conf)
); );
conf->inactive_blocked = 0; conf->inactive_blocked = 0;
} else } else
...@@ -1337,10 +1336,14 @@ static int grow_stripes(raid5_conf_t *conf, int num) ...@@ -1337,10 +1336,14 @@ static int grow_stripes(raid5_conf_t *conf, int num)
struct kmem_cache *sc; struct kmem_cache *sc;
int devs = max(conf->raid_disks, conf->previous_raid_disks); int devs = max(conf->raid_disks, conf->previous_raid_disks);
sprintf(conf->cache_name[0], if (conf->mddev->gendisk)
"raid%d-%s", conf->level, mdname(conf->mddev)); sprintf(conf->cache_name[0],
sprintf(conf->cache_name[1], "raid%d-%s", conf->level, mdname(conf->mddev));
"raid%d-%s-alt", conf->level, mdname(conf->mddev)); else
sprintf(conf->cache_name[0],
"raid%d-%p", conf->level, conf->mddev);
sprintf(conf->cache_name[1], "%s-alt", conf->cache_name[0]);
conf->active_name = 0; conf->active_name = 0;
sc = kmem_cache_create(conf->cache_name[conf->active_name], sc = kmem_cache_create(conf->cache_name[conf->active_name],
sizeof(struct stripe_head)+(devs-1)*sizeof(struct r5dev), sizeof(struct stripe_head)+(devs-1)*sizeof(struct r5dev),
...@@ -3614,7 +3617,7 @@ static void raid5_activate_delayed(raid5_conf_t *conf) ...@@ -3614,7 +3617,7 @@ static void raid5_activate_delayed(raid5_conf_t *conf)
list_add_tail(&sh->lru, &conf->hold_list); list_add_tail(&sh->lru, &conf->hold_list);
} }
} else } else
blk_plug_device(conf->mddev->queue); plugger_set_plug(&conf->plug);
} }
static void activate_bit_delay(raid5_conf_t *conf) static void activate_bit_delay(raid5_conf_t *conf)
...@@ -3655,36 +3658,44 @@ static void unplug_slaves(mddev_t *mddev) ...@@ -3655,36 +3658,44 @@ static void unplug_slaves(mddev_t *mddev)
rcu_read_unlock(); rcu_read_unlock();
} }
static void raid5_unplug_device(struct request_queue *q) void md_raid5_unplug_device(raid5_conf_t *conf)
{ {
mddev_t *mddev = q->queuedata;
raid5_conf_t *conf = mddev->private;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&conf->device_lock, flags); spin_lock_irqsave(&conf->device_lock, flags);
if (blk_remove_plug(q)) { if (plugger_remove_plug(&conf->plug)) {
conf->seq_flush++; conf->seq_flush++;
raid5_activate_delayed(conf); raid5_activate_delayed(conf);
} }
md_wakeup_thread(mddev->thread); md_wakeup_thread(conf->mddev->thread);
spin_unlock_irqrestore(&conf->device_lock, flags); spin_unlock_irqrestore(&conf->device_lock, flags);
unplug_slaves(mddev); unplug_slaves(conf->mddev);
} }
EXPORT_SYMBOL_GPL(md_raid5_unplug_device);
static int raid5_congested(void *data, int bits) static void raid5_unplug(struct plug_handle *plug)
{
raid5_conf_t *conf = container_of(plug, raid5_conf_t, plug);
md_raid5_unplug_device(conf);
}
static void raid5_unplug_queue(struct request_queue *q)
{
mddev_t *mddev = q->queuedata;
md_raid5_unplug_device(mddev->private);
}
int md_raid5_congested(mddev_t *mddev, int bits)
{ {
mddev_t *mddev = data;
raid5_conf_t *conf = mddev->private; raid5_conf_t *conf = mddev->private;
/* No difference between reads and writes. Just check /* No difference between reads and writes. Just check
* how busy the stripe_cache is * how busy the stripe_cache is
*/ */
if (mddev_congested(mddev, bits))
return 1;
if (conf->inactive_blocked) if (conf->inactive_blocked)
return 1; return 1;
if (conf->quiesce) if (conf->quiesce)
...@@ -3694,6 +3705,15 @@ static int raid5_congested(void *data, int bits) ...@@ -3694,6 +3705,15 @@ static int raid5_congested(void *data, int bits)
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(md_raid5_congested);
static int raid5_congested(void *data, int bits)
{
mddev_t *mddev = data;
return mddev_congested(mddev, bits) ||
md_raid5_congested(mddev, bits);
}
/* We want read requests to align with chunks where possible, /* We want read requests to align with chunks where possible,
* but write requests don't need to. * but write requests don't need to.
...@@ -4075,7 +4095,7 @@ static int make_request(mddev_t *mddev, struct bio * bi) ...@@ -4075,7 +4095,7 @@ static int make_request(mddev_t *mddev, struct bio * bi)
* add failed due to overlap. Flush everything * add failed due to overlap. Flush everything
* and wait a while * and wait a while
*/ */
raid5_unplug_device(mddev->queue); md_raid5_unplug_device(conf);
release_stripe(sh); release_stripe(sh);
schedule(); schedule();
goto retry; goto retry;
...@@ -4566,23 +4586,15 @@ raid5_show_stripe_cache_size(mddev_t *mddev, char *page) ...@@ -4566,23 +4586,15 @@ raid5_show_stripe_cache_size(mddev_t *mddev, char *page)
return 0; return 0;
} }
static ssize_t int
raid5_store_stripe_cache_size(mddev_t *mddev, const char *page, size_t len) raid5_set_cache_size(mddev_t *mddev, int size)
{ {
raid5_conf_t *conf = mddev->private; raid5_conf_t *conf = mddev->private;
unsigned long new;
int err; int err;
if (len >= PAGE_SIZE) if (size <= 16 || size > 32768)
return -EINVAL; return -EINVAL;
if (!conf) while (size < conf->max_nr_stripes) {
return -ENODEV;
if (strict_strtoul(page, 10, &new))
return -EINVAL;
if (new <= 16 || new > 32768)
return -EINVAL;
while (new < conf->max_nr_stripes) {
if (drop_one_stripe(conf)) if (drop_one_stripe(conf))
conf->max_nr_stripes--; conf->max_nr_stripes--;
else else
...@@ -4591,11 +4603,32 @@ raid5_store_stripe_cache_size(mddev_t *mddev, const char *page, size_t len) ...@@ -4591,11 +4603,32 @@ raid5_store_stripe_cache_size(mddev_t *mddev, const char *page, size_t len)
err = md_allow_write(mddev); err = md_allow_write(mddev);
if (err) if (err)
return err; return err;
while (new > conf->max_nr_stripes) { while (size > conf->max_nr_stripes) {
if (grow_one_stripe(conf)) if (grow_one_stripe(conf))
conf->max_nr_stripes++; conf->max_nr_stripes++;
else break; else break;
} }
return 0;
}
EXPORT_SYMBOL(raid5_set_cache_size);
static ssize_t
raid5_store_stripe_cache_size(mddev_t *mddev, const char *page, size_t len)
{
raid5_conf_t *conf = mddev->private;
unsigned long new;
int err;
if (len >= PAGE_SIZE)
return -EINVAL;
if (!conf)
return -ENODEV;
if (strict_strtoul(page, 10, &new))
return -EINVAL;
err = raid5_set_cache_size(mddev, new);
if (err)
return err;
return len; return len;
} }
...@@ -4958,7 +4991,7 @@ static int only_parity(int raid_disk, int algo, int raid_disks, int max_degraded ...@@ -4958,7 +4991,7 @@ static int only_parity(int raid_disk, int algo, int raid_disks, int max_degraded
static int run(mddev_t *mddev) static int run(mddev_t *mddev)
{ {
raid5_conf_t *conf; raid5_conf_t *conf;
int working_disks = 0, chunk_size; int working_disks = 0;
int dirty_parity_disks = 0; int dirty_parity_disks = 0;
mdk_rdev_t *rdev; mdk_rdev_t *rdev;
sector_t reshape_offset = 0; sector_t reshape_offset = 0;
...@@ -5144,42 +5177,47 @@ static int run(mddev_t *mddev) ...@@ -5144,42 +5177,47 @@ static int run(mddev_t *mddev)
"reshape"); "reshape");
} }
/* read-ahead size must cover two whole stripes, which is
* 2 * (datadisks) * chunksize where 'n' is the number of raid devices
*/
{
int data_disks = conf->previous_raid_disks - conf->max_degraded;
int stripe = data_disks *
((mddev->chunk_sectors << 9) / PAGE_SIZE);
if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
}
/* Ok, everything is just fine now */ /* Ok, everything is just fine now */
if (mddev->to_remove == &raid5_attrs_group) if (mddev->to_remove == &raid5_attrs_group)
mddev->to_remove = NULL; mddev->to_remove = NULL;
else if (sysfs_create_group(&mddev->kobj, &raid5_attrs_group)) else if (mddev->kobj.sd &&
sysfs_create_group(&mddev->kobj, &raid5_attrs_group))
printk(KERN_WARNING printk(KERN_WARNING
"md/raid:%s: failed to create sysfs attributes.\n", "raid5: failed to create sysfs attributes for %s\n",
mdname(mddev)); mdname(mddev));
md_set_array_sectors(mddev, raid5_size(mddev, 0, 0));
mddev->queue->queue_lock = &conf->device_lock; plugger_init(&conf->plug, raid5_unplug);
mddev->plug = &conf->plug;
if (mddev->queue) {
int chunk_size;
/* read-ahead size must cover two whole stripes, which
* is 2 * (datadisks) * chunksize where 'n' is the
* number of raid devices
*/
int data_disks = conf->previous_raid_disks - conf->max_degraded;
int stripe = data_disks *
((mddev->chunk_sectors << 9) / PAGE_SIZE);
if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
mddev->queue->unplug_fn = raid5_unplug_device; blk_queue_merge_bvec(mddev->queue, raid5_mergeable_bvec);
mddev->queue->backing_dev_info.congested_data = mddev;
mddev->queue->backing_dev_info.congested_fn = raid5_congested;
md_set_array_sectors(mddev, raid5_size(mddev, 0, 0)); mddev->queue->backing_dev_info.congested_data = mddev;
mddev->queue->backing_dev_info.congested_fn = raid5_congested;
mddev->queue->queue_lock = &conf->device_lock;
mddev->queue->unplug_fn = raid5_unplug_queue;
blk_queue_merge_bvec(mddev->queue, raid5_mergeable_bvec); chunk_size = mddev->chunk_sectors << 9;
chunk_size = mddev->chunk_sectors << 9; blk_queue_io_min(mddev->queue, chunk_size);
blk_queue_io_min(mddev->queue, chunk_size); blk_queue_io_opt(mddev->queue, chunk_size *
blk_queue_io_opt(mddev->queue, chunk_size * (conf->raid_disks - conf->max_degraded));
(conf->raid_disks - conf->max_degraded));
list_for_each_entry(rdev, &mddev->disks, same_set) list_for_each_entry(rdev, &mddev->disks, same_set)
disk_stack_limits(mddev->gendisk, rdev->bdev, disk_stack_limits(mddev->gendisk, rdev->bdev,
rdev->data_offset << 9); rdev->data_offset << 9);
}
return 0; return 0;
abort: abort:
...@@ -5200,8 +5238,9 @@ static int stop(mddev_t *mddev) ...@@ -5200,8 +5238,9 @@ static int stop(mddev_t *mddev)
md_unregister_thread(mddev->thread); md_unregister_thread(mddev->thread);
mddev->thread = NULL; mddev->thread = NULL;
mddev->queue->backing_dev_info.congested_fn = NULL; if (mddev->queue)
blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/ mddev->queue->backing_dev_info.congested_fn = NULL;
plugger_flush(&conf->plug); /* the unplug fn references 'conf'*/
free_conf(conf); free_conf(conf);
mddev->private = NULL; mddev->private = NULL;
mddev->to_remove = &raid5_attrs_group; mddev->to_remove = &raid5_attrs_group;
...@@ -5545,10 +5584,7 @@ static int raid5_start_reshape(mddev_t *mddev) ...@@ -5545,10 +5584,7 @@ static int raid5_start_reshape(mddev_t *mddev)
sprintf(nm, "rd%d", rdev->raid_disk); sprintf(nm, "rd%d", rdev->raid_disk);
if (sysfs_create_link(&mddev->kobj, if (sysfs_create_link(&mddev->kobj,
&rdev->kobj, nm)) &rdev->kobj, nm))
printk(KERN_WARNING /* Failure here is OK */;
"md/raid:%s: failed to create "
" link %s\n",
mdname(mddev), nm);
} else } else
break; break;
} }
...@@ -5603,7 +5639,7 @@ static void end_reshape(raid5_conf_t *conf) ...@@ -5603,7 +5639,7 @@ static void end_reshape(raid5_conf_t *conf)
/* read-ahead size must cover two whole stripes, which is /* read-ahead size must cover two whole stripes, which is
* 2 * (datadisks) * chunksize where 'n' is the number of raid devices * 2 * (datadisks) * chunksize where 'n' is the number of raid devices
*/ */
{ if (conf->mddev->queue) {
int data_disks = conf->raid_disks - conf->max_degraded; int data_disks = conf->raid_disks - conf->max_degraded;
int stripe = data_disks * ((conf->chunk_sectors << 9) int stripe = data_disks * ((conf->chunk_sectors << 9)
/ PAGE_SIZE); / PAGE_SIZE);
......
...@@ -388,7 +388,7 @@ struct raid5_private_data { ...@@ -388,7 +388,7 @@ struct raid5_private_data {
* two caches. * two caches.
*/ */
int active_name; int active_name;
char cache_name[2][20]; char cache_name[2][32];
struct kmem_cache *slab_cache; /* for allocating stripes */ struct kmem_cache *slab_cache; /* for allocating stripes */
int seq_flush, seq_write; int seq_flush, seq_write;
...@@ -398,6 +398,9 @@ struct raid5_private_data { ...@@ -398,6 +398,9 @@ struct raid5_private_data {
* (fresh device added). * (fresh device added).
* Cleared when a sync completes. * Cleared when a sync completes.
*/ */
struct plug_handle plug;
/* per cpu variables */ /* per cpu variables */
struct raid5_percpu { struct raid5_percpu {
struct page *spare_page; /* Used when checking P/Q in raid6 */ struct page *spare_page; /* Used when checking P/Q in raid6 */
...@@ -497,4 +500,8 @@ static inline int algorithm_is_DDF(int layout) ...@@ -497,4 +500,8 @@ static inline int algorithm_is_DDF(int layout)
{ {
return layout >= 8 && layout <= 10; return layout >= 8 && layout <= 10;
} }
extern int md_raid5_congested(mddev_t *mddev, int bits);
extern void md_raid5_unplug_device(raid5_conf_t *conf);
extern int raid5_set_cache_size(mddev_t *mddev, int size);
#endif #endif
...@@ -7,6 +7,9 @@ config BINARY_PRINTF ...@@ -7,6 +7,9 @@ config BINARY_PRINTF
menu "Library routines" menu "Library routines"
config RAID6_PQ
tristate
config BITREVERSE config BITREVERSE
tristate tristate
......
...@@ -69,6 +69,7 @@ obj-$(CONFIG_ZLIB_DEFLATE) += zlib_deflate/ ...@@ -69,6 +69,7 @@ obj-$(CONFIG_ZLIB_DEFLATE) += zlib_deflate/
obj-$(CONFIG_REED_SOLOMON) += reed_solomon/ obj-$(CONFIG_REED_SOLOMON) += reed_solomon/
obj-$(CONFIG_LZO_COMPRESS) += lzo/ obj-$(CONFIG_LZO_COMPRESS) += lzo/
obj-$(CONFIG_LZO_DECOMPRESS) += lzo/ obj-$(CONFIG_LZO_DECOMPRESS) += lzo/
obj-$(CONFIG_RAID6_PQ) += raid6/
lib-$(CONFIG_DECOMPRESS_GZIP) += decompress_inflate.o lib-$(CONFIG_DECOMPRESS_GZIP) += decompress_inflate.o
lib-$(CONFIG_DECOMPRESS_BZIP2) += decompress_bunzip2.o lib-$(CONFIG_DECOMPRESS_BZIP2) += decompress_bunzip2.o
......
obj-$(CONFIG_RAID6_PQ) += raid6_pq.o
raid6_pq-y += raid6algos.o raid6recov.o raid6tables.o \
raid6int1.o raid6int2.o raid6int4.o \
raid6int8.o raid6int16.o raid6int32.o \
raid6altivec1.o raid6altivec2.o raid6altivec4.o \
raid6altivec8.o \
raid6mmx.o raid6sse1.o raid6sse2.o
hostprogs-y += mktables
quiet_cmd_unroll = UNROLL $@
cmd_unroll = $(AWK) -f$(srctree)/$(src)/unroll.awk -vN=$(UNROLL) \
< $< > $@ || ( rm -f $@ && exit 1 )
ifeq ($(CONFIG_ALTIVEC),y)
altivec_flags := -maltivec -mabi=altivec
endif
targets += raid6int1.c
$(obj)/raid6int1.c: UNROLL := 1
$(obj)/raid6int1.c: $(src)/raid6int.uc $(src)/unroll.awk FORCE
$(call if_changed,unroll)
targets += raid6int2.c
$(obj)/raid6int2.c: UNROLL := 2
$(obj)/raid6int2.c: $(src)/raid6int.uc $(src)/unroll.awk FORCE
$(call if_changed,unroll)
targets += raid6int4.c
$(obj)/raid6int4.c: UNROLL := 4
$(obj)/raid6int4.c: $(src)/raid6int.uc $(src)/unroll.awk FORCE
$(call if_changed,unroll)
targets += raid6int8.c
$(obj)/raid6int8.c: UNROLL := 8
$(obj)/raid6int8.c: $(src)/raid6int.uc $(src)/unroll.awk FORCE
$(call if_changed,unroll)
targets += raid6int16.c
$(obj)/raid6int16.c: UNROLL := 16
$(obj)/raid6int16.c: $(src)/raid6int.uc $(src)/unroll.awk FORCE
$(call if_changed,unroll)
targets += raid6int32.c
$(obj)/raid6int32.c: UNROLL := 32
$(obj)/raid6int32.c: $(src)/raid6int.uc $(src)/unroll.awk FORCE
$(call if_changed,unroll)
CFLAGS_raid6altivec1.o += $(altivec_flags)
targets += raid6altivec1.c
$(obj)/raid6altivec1.c: UNROLL := 1
$(obj)/raid6altivec1.c: $(src)/raid6altivec.uc $(src)/unroll.awk FORCE
$(call if_changed,unroll)
CFLAGS_raid6altivec2.o += $(altivec_flags)
targets += raid6altivec2.c
$(obj)/raid6altivec2.c: UNROLL := 2
$(obj)/raid6altivec2.c: $(src)/raid6altivec.uc $(src)/unroll.awk FORCE
$(call if_changed,unroll)
CFLAGS_raid6altivec4.o += $(altivec_flags)
targets += raid6altivec4.c
$(obj)/raid6altivec4.c: UNROLL := 4
$(obj)/raid6altivec4.c: $(src)/raid6altivec.uc $(src)/unroll.awk FORCE
$(call if_changed,unroll)
CFLAGS_raid6altivec8.o += $(altivec_flags)
targets += raid6altivec8.c
$(obj)/raid6altivec8.c: UNROLL := 8
$(obj)/raid6altivec8.c: $(src)/raid6altivec.uc $(src)/unroll.awk FORCE
$(call if_changed,unroll)
quiet_cmd_mktable = TABLE $@
cmd_mktable = $(obj)/mktables > $@ || ( rm -f $@ && exit 1 )
targets += raid6tables.c
$(obj)/raid6tables.c: $(obj)/mktables FORCE
$(call if_changed,mktable)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment