Commit 7f873078 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'md/3.15' of git://neil.brown.name/md

Pull md updates from Neil Brown:
 "Just a few md patches for the 3.15 merge window.

  Not much happening in md/raid at the moment.  Just a few bug fixes
  (one for -stable) and a couple of performance tweaks"

* tag 'md/3.15' of git://neil.brown.name/md:
  raid5: get_active_stripe avoids device_lock
  raid5: make_request does less prepare wait
  md: avoid oops on unload if some process is in poll or select.
  md/raid1: r1buf_pool_alloc: free allocate pages when subsequent allocation fails.
  md/bitmap: don't abuse i_writecount for bitmap files.
parents 3e8072d4 e240c183
...@@ -1988,7 +1988,6 @@ location_store(struct mddev *mddev, const char *buf, size_t len) ...@@ -1988,7 +1988,6 @@ location_store(struct mddev *mddev, const char *buf, size_t len)
if (mddev->bitmap_info.file) { if (mddev->bitmap_info.file) {
struct file *f = mddev->bitmap_info.file; struct file *f = mddev->bitmap_info.file;
mddev->bitmap_info.file = NULL; mddev->bitmap_info.file = NULL;
restore_bitmap_write_access(f);
fput(f); fput(f);
} }
} else { } else {
......
...@@ -5181,32 +5181,6 @@ static int restart_array(struct mddev *mddev) ...@@ -5181,32 +5181,6 @@ static int restart_array(struct mddev *mddev)
return 0; return 0;
} }
/* similar to deny_write_access, but accounts for our holding a reference
* to the file ourselves */
static int deny_bitmap_write_access(struct file * file)
{
struct inode *inode = file->f_mapping->host;
spin_lock(&inode->i_lock);
if (atomic_read(&inode->i_writecount) > 1) {
spin_unlock(&inode->i_lock);
return -ETXTBSY;
}
atomic_set(&inode->i_writecount, -1);
spin_unlock(&inode->i_lock);
return 0;
}
void restore_bitmap_write_access(struct file *file)
{
struct inode *inode = file->f_mapping->host;
spin_lock(&inode->i_lock);
atomic_set(&inode->i_writecount, 1);
spin_unlock(&inode->i_lock);
}
static void md_clean(struct mddev *mddev) static void md_clean(struct mddev *mddev)
{ {
mddev->array_sectors = 0; mddev->array_sectors = 0;
...@@ -5427,7 +5401,6 @@ static int do_md_stop(struct mddev * mddev, int mode, ...@@ -5427,7 +5401,6 @@ static int do_md_stop(struct mddev * mddev, int mode,
bitmap_destroy(mddev); bitmap_destroy(mddev);
if (mddev->bitmap_info.file) { if (mddev->bitmap_info.file) {
restore_bitmap_write_access(mddev->bitmap_info.file);
fput(mddev->bitmap_info.file); fput(mddev->bitmap_info.file);
mddev->bitmap_info.file = NULL; mddev->bitmap_info.file = NULL;
} }
...@@ -5979,7 +5952,7 @@ static int hot_add_disk(struct mddev * mddev, dev_t dev) ...@@ -5979,7 +5952,7 @@ static int hot_add_disk(struct mddev * mddev, dev_t dev)
static int set_bitmap_file(struct mddev *mddev, int fd) static int set_bitmap_file(struct mddev *mddev, int fd)
{ {
int err; int err = 0;
if (mddev->pers) { if (mddev->pers) {
if (!mddev->pers->quiesce) if (!mddev->pers->quiesce)
...@@ -5991,6 +5964,7 @@ static int set_bitmap_file(struct mddev *mddev, int fd) ...@@ -5991,6 +5964,7 @@ static int set_bitmap_file(struct mddev *mddev, int fd)
if (fd >= 0) { if (fd >= 0) {
struct inode *inode;
if (mddev->bitmap) if (mddev->bitmap)
return -EEXIST; /* cannot add when bitmap is present */ return -EEXIST; /* cannot add when bitmap is present */
mddev->bitmap_info.file = fget(fd); mddev->bitmap_info.file = fget(fd);
...@@ -6001,10 +5975,21 @@ static int set_bitmap_file(struct mddev *mddev, int fd) ...@@ -6001,10 +5975,21 @@ static int set_bitmap_file(struct mddev *mddev, int fd)
return -EBADF; return -EBADF;
} }
err = deny_bitmap_write_access(mddev->bitmap_info.file); inode = mddev->bitmap_info.file->f_mapping->host;
if (err) { if (!S_ISREG(inode->i_mode)) {
printk(KERN_ERR "%s: error: bitmap file must be a regular file\n",
mdname(mddev));
err = -EBADF;
} else if (!(mddev->bitmap_info.file->f_mode & FMODE_WRITE)) {
printk(KERN_ERR "%s: error: bitmap file must open for write\n",
mdname(mddev));
err = -EBADF;
} else if (atomic_read(&inode->i_writecount) != 1) {
printk(KERN_ERR "%s: error: bitmap file is already in use\n", printk(KERN_ERR "%s: error: bitmap file is already in use\n",
mdname(mddev)); mdname(mddev));
err = -EBUSY;
}
if (err) {
fput(mddev->bitmap_info.file); fput(mddev->bitmap_info.file);
mddev->bitmap_info.file = NULL; mddev->bitmap_info.file = NULL;
return err; return err;
...@@ -6027,10 +6012,8 @@ static int set_bitmap_file(struct mddev *mddev, int fd) ...@@ -6027,10 +6012,8 @@ static int set_bitmap_file(struct mddev *mddev, int fd)
mddev->pers->quiesce(mddev, 0); mddev->pers->quiesce(mddev, 0);
} }
if (fd < 0) { if (fd < 0) {
if (mddev->bitmap_info.file) { if (mddev->bitmap_info.file)
restore_bitmap_write_access(mddev->bitmap_info.file);
fput(mddev->bitmap_info.file); fput(mddev->bitmap_info.file);
}
mddev->bitmap_info.file = NULL; mddev->bitmap_info.file = NULL;
} }
...@@ -7182,11 +7165,14 @@ static int md_seq_open(struct inode *inode, struct file *file) ...@@ -7182,11 +7165,14 @@ static int md_seq_open(struct inode *inode, struct file *file)
return error; return error;
} }
static int md_unloading;
static unsigned int mdstat_poll(struct file *filp, poll_table *wait) static unsigned int mdstat_poll(struct file *filp, poll_table *wait)
{ {
struct seq_file *seq = filp->private_data; struct seq_file *seq = filp->private_data;
int mask; int mask;
if (md_unloading)
return POLLIN|POLLRDNORM|POLLERR|POLLPRI;;
poll_wait(filp, &md_event_waiters, wait); poll_wait(filp, &md_event_waiters, wait);
/* always allow read */ /* always allow read */
...@@ -8672,6 +8658,7 @@ static __exit void md_exit(void) ...@@ -8672,6 +8658,7 @@ static __exit void md_exit(void)
{ {
struct mddev *mddev; struct mddev *mddev;
struct list_head *tmp; struct list_head *tmp;
int delay = 1;
blk_unregister_region(MKDEV(MD_MAJOR,0), 1U << MINORBITS); blk_unregister_region(MKDEV(MD_MAJOR,0), 1U << MINORBITS);
blk_unregister_region(MKDEV(mdp_major,0), 1U << MINORBITS); blk_unregister_region(MKDEV(mdp_major,0), 1U << MINORBITS);
...@@ -8680,7 +8667,19 @@ static __exit void md_exit(void) ...@@ -8680,7 +8667,19 @@ static __exit void md_exit(void)
unregister_blkdev(mdp_major, "mdp"); unregister_blkdev(mdp_major, "mdp");
unregister_reboot_notifier(&md_notifier); unregister_reboot_notifier(&md_notifier);
unregister_sysctl_table(raid_table_header); unregister_sysctl_table(raid_table_header);
/* We cannot unload the modules while some process is
* waiting for us in select() or poll() - wake them up
*/
md_unloading = 1;
while (waitqueue_active(&md_event_waiters)) {
/* not safe to leave yet */
wake_up(&md_event_waiters);
msleep(delay);
delay += delay;
}
remove_proc_entry("mdstat", NULL); remove_proc_entry("mdstat", NULL);
for_each_mddev(mddev, tmp) { for_each_mddev(mddev, tmp) {
export_array(mddev); export_array(mddev);
mddev->hold_active = 0; mddev->hold_active = 0;
......
...@@ -605,7 +605,6 @@ extern int md_check_no_bitmap(struct mddev *mddev); ...@@ -605,7 +605,6 @@ extern int md_check_no_bitmap(struct mddev *mddev);
extern int md_integrity_register(struct mddev *mddev); extern int md_integrity_register(struct mddev *mddev);
extern void md_integrity_add_rdev(struct md_rdev *rdev, struct mddev *mddev); extern void md_integrity_add_rdev(struct md_rdev *rdev, struct mddev *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 mddev_init(struct mddev *mddev); extern void mddev_init(struct mddev *mddev);
extern int md_run(struct mddev *mddev); extern int md_run(struct mddev *mddev);
......
...@@ -97,6 +97,7 @@ static void * r1buf_pool_alloc(gfp_t gfp_flags, void *data) ...@@ -97,6 +97,7 @@ static void * r1buf_pool_alloc(gfp_t gfp_flags, void *data)
struct pool_info *pi = data; struct pool_info *pi = data;
struct r1bio *r1_bio; struct r1bio *r1_bio;
struct bio *bio; struct bio *bio;
int need_pages;
int i, j; int i, j;
r1_bio = r1bio_pool_alloc(gfp_flags, pi); r1_bio = r1bio_pool_alloc(gfp_flags, pi);
...@@ -119,15 +120,15 @@ static void * r1buf_pool_alloc(gfp_t gfp_flags, void *data) ...@@ -119,15 +120,15 @@ static void * r1buf_pool_alloc(gfp_t gfp_flags, void *data)
* RESYNC_PAGES for each bio. * RESYNC_PAGES for each bio.
*/ */
if (test_bit(MD_RECOVERY_REQUESTED, &pi->mddev->recovery)) if (test_bit(MD_RECOVERY_REQUESTED, &pi->mddev->recovery))
j = pi->raid_disks; need_pages = pi->raid_disks;
else else
j = 1; need_pages = 1;
while(j--) { for (j = 0; j < need_pages; j++) {
bio = r1_bio->bios[j]; bio = r1_bio->bios[j];
bio->bi_vcnt = RESYNC_PAGES; bio->bi_vcnt = RESYNC_PAGES;
if (bio_alloc_pages(bio, gfp_flags)) if (bio_alloc_pages(bio, gfp_flags))
goto out_free_bio; goto out_free_pages;
} }
/* If not user-requests, copy the page pointers to all bios */ /* If not user-requests, copy the page pointers to all bios */
if (!test_bit(MD_RECOVERY_REQUESTED, &pi->mddev->recovery)) { if (!test_bit(MD_RECOVERY_REQUESTED, &pi->mddev->recovery)) {
...@@ -141,6 +142,14 @@ static void * r1buf_pool_alloc(gfp_t gfp_flags, void *data) ...@@ -141,6 +142,14 @@ static void * r1buf_pool_alloc(gfp_t gfp_flags, void *data)
return r1_bio; return r1_bio;
out_free_pages:
while (--j >= 0) {
struct bio_vec *bv;
bio_for_each_segment_all(bv, r1_bio->bios[j], i)
__free_page(bv->bv_page);
}
out_free_bio: out_free_bio:
while (++j < pi->raid_disks) while (++j < pi->raid_disks)
bio_put(r1_bio->bios[j]); bio_put(r1_bio->bios[j]);
......
...@@ -679,14 +679,9 @@ get_active_stripe(struct r5conf *conf, sector_t sector, ...@@ -679,14 +679,9 @@ get_active_stripe(struct r5conf *conf, sector_t sector,
init_stripe(sh, sector, previous); init_stripe(sh, sector, previous);
atomic_inc(&sh->count); atomic_inc(&sh->count);
} }
} else { } else if (!atomic_inc_not_zero(&sh->count)) {
spin_lock(&conf->device_lock); spin_lock(&conf->device_lock);
if (atomic_read(&sh->count)) { if (!atomic_read(&sh->count)) {
BUG_ON(!list_empty(&sh->lru)
&& !test_bit(STRIPE_EXPANDING, &sh->state)
&& !test_bit(STRIPE_ON_UNPLUG_LIST, &sh->state)
);
} else {
if (!test_bit(STRIPE_HANDLE, &sh->state)) if (!test_bit(STRIPE_HANDLE, &sh->state))
atomic_inc(&conf->active_stripes); atomic_inc(&conf->active_stripes);
BUG_ON(list_empty(&sh->lru) && BUG_ON(list_empty(&sh->lru) &&
...@@ -4552,6 +4547,8 @@ static void make_request(struct mddev *mddev, struct bio * bi) ...@@ -4552,6 +4547,8 @@ static void make_request(struct mddev *mddev, struct bio * bi)
struct stripe_head *sh; struct stripe_head *sh;
const int rw = bio_data_dir(bi); const int rw = bio_data_dir(bi);
int remaining; int remaining;
DEFINE_WAIT(w);
bool do_prepare;
if (unlikely(bi->bi_rw & REQ_FLUSH)) { if (unlikely(bi->bi_rw & REQ_FLUSH)) {
md_flush_request(mddev, bi); md_flush_request(mddev, bi);
...@@ -4575,15 +4572,18 @@ static void make_request(struct mddev *mddev, struct bio * bi) ...@@ -4575,15 +4572,18 @@ static void make_request(struct mddev *mddev, struct bio * bi)
bi->bi_next = NULL; bi->bi_next = NULL;
bi->bi_phys_segments = 1; /* over-loaded to count active stripes */ bi->bi_phys_segments = 1; /* over-loaded to count active stripes */
prepare_to_wait(&conf->wait_for_overlap, &w, TASK_UNINTERRUPTIBLE);
for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) { for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) {
DEFINE_WAIT(w);
int previous; int previous;
int seq; int seq;
do_prepare = false;
retry: retry:
seq = read_seqcount_begin(&conf->gen_lock); seq = read_seqcount_begin(&conf->gen_lock);
previous = 0; previous = 0;
prepare_to_wait(&conf->wait_for_overlap, &w, TASK_UNINTERRUPTIBLE); if (do_prepare)
prepare_to_wait(&conf->wait_for_overlap, &w,
TASK_UNINTERRUPTIBLE);
if (unlikely(conf->reshape_progress != MaxSector)) { if (unlikely(conf->reshape_progress != MaxSector)) {
/* spinlock is needed as reshape_progress may be /* spinlock is needed as reshape_progress may be
* 64bit on a 32bit platform, and so it might be * 64bit on a 32bit platform, and so it might be
...@@ -4604,6 +4604,7 @@ static void make_request(struct mddev *mddev, struct bio * bi) ...@@ -4604,6 +4604,7 @@ static void make_request(struct mddev *mddev, struct bio * bi)
: logical_sector >= conf->reshape_safe) { : logical_sector >= conf->reshape_safe) {
spin_unlock_irq(&conf->device_lock); spin_unlock_irq(&conf->device_lock);
schedule(); schedule();
do_prepare = true;
goto retry; goto retry;
} }
} }
...@@ -4640,6 +4641,7 @@ static void make_request(struct mddev *mddev, struct bio * bi) ...@@ -4640,6 +4641,7 @@ static void make_request(struct mddev *mddev, struct bio * bi)
if (must_retry) { if (must_retry) {
release_stripe(sh); release_stripe(sh);
schedule(); schedule();
do_prepare = true;
goto retry; goto retry;
} }
} }
...@@ -4663,8 +4665,10 @@ static void make_request(struct mddev *mddev, struct bio * bi) ...@@ -4663,8 +4665,10 @@ static void make_request(struct mddev *mddev, struct bio * bi)
prepare_to_wait(&conf->wait_for_overlap, prepare_to_wait(&conf->wait_for_overlap,
&w, TASK_INTERRUPTIBLE); &w, TASK_INTERRUPTIBLE);
if (logical_sector >= mddev->suspend_lo && if (logical_sector >= mddev->suspend_lo &&
logical_sector < mddev->suspend_hi) logical_sector < mddev->suspend_hi) {
schedule(); schedule();
do_prepare = true;
}
goto retry; goto retry;
} }
...@@ -4677,9 +4681,9 @@ static void make_request(struct mddev *mddev, struct bio * bi) ...@@ -4677,9 +4681,9 @@ static void make_request(struct mddev *mddev, struct bio * bi)
md_wakeup_thread(mddev->thread); md_wakeup_thread(mddev->thread);
release_stripe(sh); release_stripe(sh);
schedule(); schedule();
do_prepare = true;
goto retry; goto retry;
} }
finish_wait(&conf->wait_for_overlap, &w);
set_bit(STRIPE_HANDLE, &sh->state); set_bit(STRIPE_HANDLE, &sh->state);
clear_bit(STRIPE_DELAYED, &sh->state); clear_bit(STRIPE_DELAYED, &sh->state);
if ((bi->bi_rw & REQ_SYNC) && if ((bi->bi_rw & REQ_SYNC) &&
...@@ -4689,10 +4693,10 @@ static void make_request(struct mddev *mddev, struct bio * bi) ...@@ -4689,10 +4693,10 @@ static void make_request(struct mddev *mddev, struct bio * bi)
} else { } else {
/* cannot get stripe for read-ahead, just give-up */ /* cannot get stripe for read-ahead, just give-up */
clear_bit(BIO_UPTODATE, &bi->bi_flags); clear_bit(BIO_UPTODATE, &bi->bi_flags);
finish_wait(&conf->wait_for_overlap, &w);
break; break;
} }
} }
finish_wait(&conf->wait_for_overlap, &w);
remaining = raid5_dec_bi_active_stripes(bi); remaining = raid5_dec_bi_active_stripes(bi);
if (remaining == 0) { if (remaining == 0) {
......
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