mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	md: fix deadlock between mddev_suspend() and md_write_start()
If mddev_suspend() races with md_write_start() we can deadlock with mddev_suspend() waiting for the request that is currently in md_write_start() to complete the ->make_request() call, and md_write_start() waiting for the metadata to be updated to mark the array as 'dirty'. As metadata updates done by md_check_recovery() only happen then the mddev_lock() can be claimed, and as mddev_suspend() is often called with the lock held, these threads wait indefinitely for each other. We fix this by having md_write_start() abort if mddev_suspend() is happening, and ->make_request() aborts if md_write_start() aborted. md_make_request() can detect this abort, decrease the ->active_io count, and wait for mddev_suspend(). Reported-by: Nix <nix@esperi.org.uk> Fix: 68866e425be2(MD: no sync IO while suspended) Cc: stable@vger.kernel.org Signed-off-by: NeilBrown <neilb@suse.com> Signed-off-by: Shaohua Li <shli@fb.com>
This commit is contained in:
		
							parent
							
								
									63f700aab4
								
							
						
					
					
						commit
						cc27b0c78c
					
				
					 9 changed files with 56 additions and 35 deletions
				
			
		| 
						 | 
					@ -170,7 +170,7 @@ static void add_sector(struct faulty_conf *conf, sector_t start, int mode)
 | 
				
			||||||
		conf->nfaults = n+1;
 | 
							conf->nfaults = n+1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void faulty_make_request(struct mddev *mddev, struct bio *bio)
 | 
					static bool faulty_make_request(struct mddev *mddev, struct bio *bio)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct faulty_conf *conf = mddev->private;
 | 
						struct faulty_conf *conf = mddev->private;
 | 
				
			||||||
	int failit = 0;
 | 
						int failit = 0;
 | 
				
			||||||
| 
						 | 
					@ -182,7 +182,7 @@ static void faulty_make_request(struct mddev *mddev, struct bio *bio)
 | 
				
			||||||
			 * just fail immediately
 | 
								 * just fail immediately
 | 
				
			||||||
			 */
 | 
								 */
 | 
				
			||||||
			bio_io_error(bio);
 | 
								bio_io_error(bio);
 | 
				
			||||||
			return;
 | 
								return true;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (check_sector(conf, bio->bi_iter.bi_sector,
 | 
							if (check_sector(conf, bio->bi_iter.bi_sector,
 | 
				
			||||||
| 
						 | 
					@ -224,6 +224,7 @@ static void faulty_make_request(struct mddev *mddev, struct bio *bio)
 | 
				
			||||||
		bio->bi_bdev = conf->rdev->bdev;
 | 
							bio->bi_bdev = conf->rdev->bdev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	generic_make_request(bio);
 | 
						generic_make_request(bio);
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void faulty_status(struct seq_file *seq, struct mddev *mddev)
 | 
					static void faulty_status(struct seq_file *seq, struct mddev *mddev)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -245,7 +245,7 @@ static void linear_free(struct mddev *mddev, void *priv)
 | 
				
			||||||
	kfree(conf);
 | 
						kfree(conf);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void linear_make_request(struct mddev *mddev, struct bio *bio)
 | 
					static bool linear_make_request(struct mddev *mddev, struct bio *bio)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	char b[BDEVNAME_SIZE];
 | 
						char b[BDEVNAME_SIZE];
 | 
				
			||||||
	struct dev_info *tmp_dev;
 | 
						struct dev_info *tmp_dev;
 | 
				
			||||||
| 
						 | 
					@ -254,7 +254,7 @@ static void linear_make_request(struct mddev *mddev, struct bio *bio)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (unlikely(bio->bi_opf & REQ_PREFLUSH)) {
 | 
						if (unlikely(bio->bi_opf & REQ_PREFLUSH)) {
 | 
				
			||||||
		md_flush_request(mddev, bio);
 | 
							md_flush_request(mddev, bio);
 | 
				
			||||||
		return;
 | 
							return true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tmp_dev = which_dev(mddev, bio_sector);
 | 
						tmp_dev = which_dev(mddev, bio_sector);
 | 
				
			||||||
| 
						 | 
					@ -292,7 +292,7 @@ static void linear_make_request(struct mddev *mddev, struct bio *bio)
 | 
				
			||||||
		mddev_check_write_zeroes(mddev, bio);
 | 
							mddev_check_write_zeroes(mddev, bio);
 | 
				
			||||||
		generic_make_request(bio);
 | 
							generic_make_request(bio);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return;
 | 
						return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out_of_bounds:
 | 
					out_of_bounds:
 | 
				
			||||||
	pr_err("md/linear:%s: make_request: Sector %llu out of bounds on dev %s: %llu sectors, offset %llu\n",
 | 
						pr_err("md/linear:%s: make_request: Sector %llu out of bounds on dev %s: %llu sectors, offset %llu\n",
 | 
				
			||||||
| 
						 | 
					@ -302,6 +302,7 @@ static void linear_make_request(struct mddev *mddev, struct bio *bio)
 | 
				
			||||||
	       (unsigned long long)tmp_dev->rdev->sectors,
 | 
						       (unsigned long long)tmp_dev->rdev->sectors,
 | 
				
			||||||
	       (unsigned long long)start_sector);
 | 
						       (unsigned long long)start_sector);
 | 
				
			||||||
	bio_io_error(bio);
 | 
						bio_io_error(bio);
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void linear_status (struct seq_file *seq, struct mddev *mddev)
 | 
					static void linear_status (struct seq_file *seq, struct mddev *mddev)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -277,7 +277,7 @@ static blk_qc_t md_make_request(struct request_queue *q, struct bio *bio)
 | 
				
			||||||
		bio_endio(bio);
 | 
							bio_endio(bio);
 | 
				
			||||||
		return BLK_QC_T_NONE;
 | 
							return BLK_QC_T_NONE;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	smp_rmb(); /* Ensure implications of  'active' are visible */
 | 
					check_suspended:
 | 
				
			||||||
	rcu_read_lock();
 | 
						rcu_read_lock();
 | 
				
			||||||
	if (mddev->suspended) {
 | 
						if (mddev->suspended) {
 | 
				
			||||||
		DEFINE_WAIT(__wait);
 | 
							DEFINE_WAIT(__wait);
 | 
				
			||||||
| 
						 | 
					@ -302,7 +302,11 @@ static blk_qc_t md_make_request(struct request_queue *q, struct bio *bio)
 | 
				
			||||||
	sectors = bio_sectors(bio);
 | 
						sectors = bio_sectors(bio);
 | 
				
			||||||
	/* bio could be mergeable after passing to underlayer */
 | 
						/* bio could be mergeable after passing to underlayer */
 | 
				
			||||||
	bio->bi_opf &= ~REQ_NOMERGE;
 | 
						bio->bi_opf &= ~REQ_NOMERGE;
 | 
				
			||||||
	mddev->pers->make_request(mddev, bio);
 | 
						if (!mddev->pers->make_request(mddev, bio)) {
 | 
				
			||||||
 | 
							atomic_dec(&mddev->active_io);
 | 
				
			||||||
 | 
							wake_up(&mddev->sb_wait);
 | 
				
			||||||
 | 
							goto check_suspended;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cpu = part_stat_lock();
 | 
						cpu = part_stat_lock();
 | 
				
			||||||
	part_stat_inc(cpu, &mddev->gendisk->part0, ios[rw]);
 | 
						part_stat_inc(cpu, &mddev->gendisk->part0, ios[rw]);
 | 
				
			||||||
| 
						 | 
					@ -327,6 +331,7 @@ void mddev_suspend(struct mddev *mddev)
 | 
				
			||||||
	if (mddev->suspended++)
 | 
						if (mddev->suspended++)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	synchronize_rcu();
 | 
						synchronize_rcu();
 | 
				
			||||||
 | 
						wake_up(&mddev->sb_wait);
 | 
				
			||||||
	wait_event(mddev->sb_wait, atomic_read(&mddev->active_io) == 0);
 | 
						wait_event(mddev->sb_wait, atomic_read(&mddev->active_io) == 0);
 | 
				
			||||||
	mddev->pers->quiesce(mddev, 1);
 | 
						mddev->pers->quiesce(mddev, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7950,12 +7955,14 @@ EXPORT_SYMBOL(md_done_sync);
 | 
				
			||||||
 * If we need to update some array metadata (e.g. 'active' flag
 | 
					 * If we need to update some array metadata (e.g. 'active' flag
 | 
				
			||||||
 * in superblock) before writing, schedule a superblock update
 | 
					 * in superblock) before writing, schedule a superblock update
 | 
				
			||||||
 * and wait for it to complete.
 | 
					 * and wait for it to complete.
 | 
				
			||||||
 | 
					 * A return value of 'false' means that the write wasn't recorded
 | 
				
			||||||
 | 
					 * and cannot proceed as the array is being suspend.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void md_write_start(struct mddev *mddev, struct bio *bi)
 | 
					bool md_write_start(struct mddev *mddev, struct bio *bi)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int did_change = 0;
 | 
						int did_change = 0;
 | 
				
			||||||
	if (bio_data_dir(bi) != WRITE)
 | 
						if (bio_data_dir(bi) != WRITE)
 | 
				
			||||||
		return;
 | 
							return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	BUG_ON(mddev->ro == 1);
 | 
						BUG_ON(mddev->ro == 1);
 | 
				
			||||||
	if (mddev->ro == 2) {
 | 
						if (mddev->ro == 2) {
 | 
				
			||||||
| 
						 | 
					@ -7987,7 +7994,12 @@ void md_write_start(struct mddev *mddev, struct bio *bi)
 | 
				
			||||||
	if (did_change)
 | 
						if (did_change)
 | 
				
			||||||
		sysfs_notify_dirent_safe(mddev->sysfs_state);
 | 
							sysfs_notify_dirent_safe(mddev->sysfs_state);
 | 
				
			||||||
	wait_event(mddev->sb_wait,
 | 
						wait_event(mddev->sb_wait,
 | 
				
			||||||
		   !test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags));
 | 
							   !test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags) && !mddev->suspended);
 | 
				
			||||||
 | 
						if (test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags)) {
 | 
				
			||||||
 | 
							percpu_ref_put(&mddev->writes_pending);
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(md_write_start);
 | 
					EXPORT_SYMBOL(md_write_start);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -510,7 +510,7 @@ struct md_personality
 | 
				
			||||||
	int level;
 | 
						int level;
 | 
				
			||||||
	struct list_head list;
 | 
						struct list_head list;
 | 
				
			||||||
	struct module *owner;
 | 
						struct module *owner;
 | 
				
			||||||
	void (*make_request)(struct mddev *mddev, struct bio *bio);
 | 
						bool (*make_request)(struct mddev *mddev, struct bio *bio);
 | 
				
			||||||
	int (*run)(struct mddev *mddev);
 | 
						int (*run)(struct mddev *mddev);
 | 
				
			||||||
	void (*free)(struct mddev *mddev, void *priv);
 | 
						void (*free)(struct mddev *mddev, void *priv);
 | 
				
			||||||
	void (*status)(struct seq_file *seq, struct mddev *mddev);
 | 
						void (*status)(struct seq_file *seq, struct mddev *mddev);
 | 
				
			||||||
| 
						 | 
					@ -649,7 +649,7 @@ extern void md_wakeup_thread(struct md_thread *thread);
 | 
				
			||||||
extern void md_check_recovery(struct mddev *mddev);
 | 
					extern void md_check_recovery(struct mddev *mddev);
 | 
				
			||||||
extern void md_reap_sync_thread(struct mddev *mddev);
 | 
					extern void md_reap_sync_thread(struct mddev *mddev);
 | 
				
			||||||
extern int mddev_init_writes_pending(struct mddev *mddev);
 | 
					extern int mddev_init_writes_pending(struct mddev *mddev);
 | 
				
			||||||
extern void md_write_start(struct mddev *mddev, struct bio *bi);
 | 
					extern bool md_write_start(struct mddev *mddev, struct bio *bi);
 | 
				
			||||||
extern void md_write_inc(struct mddev *mddev, struct bio *bi);
 | 
					extern void md_write_inc(struct mddev *mddev, struct bio *bi);
 | 
				
			||||||
extern void md_write_end(struct mddev *mddev);
 | 
					extern void md_write_end(struct mddev *mddev);
 | 
				
			||||||
extern void md_done_sync(struct mddev *mddev, int blocks, int ok);
 | 
					extern void md_done_sync(struct mddev *mddev, int blocks, int ok);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -106,7 +106,7 @@ static void multipath_end_request(struct bio *bio)
 | 
				
			||||||
	rdev_dec_pending(rdev, conf->mddev);
 | 
						rdev_dec_pending(rdev, conf->mddev);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void multipath_make_request(struct mddev *mddev, struct bio * bio)
 | 
					static bool multipath_make_request(struct mddev *mddev, struct bio * bio)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mpconf *conf = mddev->private;
 | 
						struct mpconf *conf = mddev->private;
 | 
				
			||||||
	struct multipath_bh * mp_bh;
 | 
						struct multipath_bh * mp_bh;
 | 
				
			||||||
| 
						 | 
					@ -114,7 +114,7 @@ static void multipath_make_request(struct mddev *mddev, struct bio * bio)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (unlikely(bio->bi_opf & REQ_PREFLUSH)) {
 | 
						if (unlikely(bio->bi_opf & REQ_PREFLUSH)) {
 | 
				
			||||||
		md_flush_request(mddev, bio);
 | 
							md_flush_request(mddev, bio);
 | 
				
			||||||
		return;
 | 
							return true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mp_bh = mempool_alloc(conf->pool, GFP_NOIO);
 | 
						mp_bh = mempool_alloc(conf->pool, GFP_NOIO);
 | 
				
			||||||
| 
						 | 
					@ -126,7 +126,7 @@ static void multipath_make_request(struct mddev *mddev, struct bio * bio)
 | 
				
			||||||
	if (mp_bh->path < 0) {
 | 
						if (mp_bh->path < 0) {
 | 
				
			||||||
		bio_io_error(bio);
 | 
							bio_io_error(bio);
 | 
				
			||||||
		mempool_free(mp_bh, conf->pool);
 | 
							mempool_free(mp_bh, conf->pool);
 | 
				
			||||||
		return;
 | 
							return true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	multipath = conf->multipaths + mp_bh->path;
 | 
						multipath = conf->multipaths + mp_bh->path;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -141,7 +141,7 @@ static void multipath_make_request(struct mddev *mddev, struct bio * bio)
 | 
				
			||||||
	mddev_check_writesame(mddev, &mp_bh->bio);
 | 
						mddev_check_writesame(mddev, &mp_bh->bio);
 | 
				
			||||||
	mddev_check_write_zeroes(mddev, &mp_bh->bio);
 | 
						mddev_check_write_zeroes(mddev, &mp_bh->bio);
 | 
				
			||||||
	generic_make_request(&mp_bh->bio);
 | 
						generic_make_request(&mp_bh->bio);
 | 
				
			||||||
	return;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void multipath_status(struct seq_file *seq, struct mddev *mddev)
 | 
					static void multipath_status(struct seq_file *seq, struct mddev *mddev)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -548,7 +548,7 @@ static void raid0_handle_discard(struct mddev *mddev, struct bio *bio)
 | 
				
			||||||
	bio_endio(bio);
 | 
						bio_endio(bio);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void raid0_make_request(struct mddev *mddev, struct bio *bio)
 | 
					static bool raid0_make_request(struct mddev *mddev, struct bio *bio)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct strip_zone *zone;
 | 
						struct strip_zone *zone;
 | 
				
			||||||
	struct md_rdev *tmp_dev;
 | 
						struct md_rdev *tmp_dev;
 | 
				
			||||||
| 
						 | 
					@ -559,12 +559,12 @@ static void raid0_make_request(struct mddev *mddev, struct bio *bio)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (unlikely(bio->bi_opf & REQ_PREFLUSH)) {
 | 
						if (unlikely(bio->bi_opf & REQ_PREFLUSH)) {
 | 
				
			||||||
		md_flush_request(mddev, bio);
 | 
							md_flush_request(mddev, bio);
 | 
				
			||||||
		return;
 | 
							return true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (unlikely((bio_op(bio) == REQ_OP_DISCARD))) {
 | 
						if (unlikely((bio_op(bio) == REQ_OP_DISCARD))) {
 | 
				
			||||||
		raid0_handle_discard(mddev, bio);
 | 
							raid0_handle_discard(mddev, bio);
 | 
				
			||||||
		return;
 | 
							return true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bio_sector = bio->bi_iter.bi_sector;
 | 
						bio_sector = bio->bi_iter.bi_sector;
 | 
				
			||||||
| 
						 | 
					@ -599,6 +599,7 @@ static void raid0_make_request(struct mddev *mddev, struct bio *bio)
 | 
				
			||||||
	mddev_check_writesame(mddev, bio);
 | 
						mddev_check_writesame(mddev, bio);
 | 
				
			||||||
	mddev_check_write_zeroes(mddev, bio);
 | 
						mddev_check_write_zeroes(mddev, bio);
 | 
				
			||||||
	generic_make_request(bio);
 | 
						generic_make_request(bio);
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void raid0_status(struct seq_file *seq, struct mddev *mddev)
 | 
					static void raid0_status(struct seq_file *seq, struct mddev *mddev)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1321,7 +1321,6 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
 | 
				
			||||||
	 * Continue immediately if no resync is active currently.
 | 
						 * Continue immediately if no resync is active currently.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	md_write_start(mddev, bio); /* wait on superblock update early */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((bio_end_sector(bio) > mddev->suspend_lo &&
 | 
						if ((bio_end_sector(bio) > mddev->suspend_lo &&
 | 
				
			||||||
	    bio->bi_iter.bi_sector < mddev->suspend_hi) ||
 | 
						    bio->bi_iter.bi_sector < mddev->suspend_hi) ||
 | 
				
			||||||
| 
						 | 
					@ -1550,13 +1549,13 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
 | 
				
			||||||
	wake_up(&conf->wait_barrier);
 | 
						wake_up(&conf->wait_barrier);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void raid1_make_request(struct mddev *mddev, struct bio *bio)
 | 
					static bool raid1_make_request(struct mddev *mddev, struct bio *bio)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	sector_t sectors;
 | 
						sector_t sectors;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (unlikely(bio->bi_opf & REQ_PREFLUSH)) {
 | 
						if (unlikely(bio->bi_opf & REQ_PREFLUSH)) {
 | 
				
			||||||
		md_flush_request(mddev, bio);
 | 
							md_flush_request(mddev, bio);
 | 
				
			||||||
		return;
 | 
							return true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
| 
						 | 
					@ -1571,8 +1570,12 @@ static void raid1_make_request(struct mddev *mddev, struct bio *bio)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (bio_data_dir(bio) == READ)
 | 
						if (bio_data_dir(bio) == READ)
 | 
				
			||||||
		raid1_read_request(mddev, bio, sectors, NULL);
 | 
							raid1_read_request(mddev, bio, sectors, NULL);
 | 
				
			||||||
	else
 | 
						else {
 | 
				
			||||||
 | 
							if (!md_write_start(mddev,bio))
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
		raid1_write_request(mddev, bio, sectors);
 | 
							raid1_write_request(mddev, bio, sectors);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void raid1_status(struct seq_file *seq, struct mddev *mddev)
 | 
					static void raid1_status(struct seq_file *seq, struct mddev *mddev)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1303,8 +1303,6 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
 | 
				
			||||||
	sector_t sectors;
 | 
						sector_t sectors;
 | 
				
			||||||
	int max_sectors;
 | 
						int max_sectors;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	md_write_start(mddev, bio);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Register the new request and wait if the reconstruction
 | 
						 * Register the new request and wait if the reconstruction
 | 
				
			||||||
	 * thread has put up a bar for new requests.
 | 
						 * thread has put up a bar for new requests.
 | 
				
			||||||
| 
						 | 
					@ -1525,7 +1523,7 @@ static void __make_request(struct mddev *mddev, struct bio *bio, int sectors)
 | 
				
			||||||
		raid10_write_request(mddev, bio, r10_bio);
 | 
							raid10_write_request(mddev, bio, r10_bio);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void raid10_make_request(struct mddev *mddev, struct bio *bio)
 | 
					static bool raid10_make_request(struct mddev *mddev, struct bio *bio)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct r10conf *conf = mddev->private;
 | 
						struct r10conf *conf = mddev->private;
 | 
				
			||||||
	sector_t chunk_mask = (conf->geo.chunk_mask & conf->prev.chunk_mask);
 | 
						sector_t chunk_mask = (conf->geo.chunk_mask & conf->prev.chunk_mask);
 | 
				
			||||||
| 
						 | 
					@ -1534,9 +1532,12 @@ static void raid10_make_request(struct mddev *mddev, struct bio *bio)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (unlikely(bio->bi_opf & REQ_PREFLUSH)) {
 | 
						if (unlikely(bio->bi_opf & REQ_PREFLUSH)) {
 | 
				
			||||||
		md_flush_request(mddev, bio);
 | 
							md_flush_request(mddev, bio);
 | 
				
			||||||
		return;
 | 
							return true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!md_write_start(mddev, bio))
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * If this request crosses a chunk boundary, we need to split
 | 
						 * If this request crosses a chunk boundary, we need to split
 | 
				
			||||||
	 * it.
 | 
						 * it.
 | 
				
			||||||
| 
						 | 
					@ -1553,6 +1554,7 @@ static void raid10_make_request(struct mddev *mddev, struct bio *bio)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* In case raid10d snuck in to freeze_array */
 | 
						/* In case raid10d snuck in to freeze_array */
 | 
				
			||||||
	wake_up(&conf->wait_barrier);
 | 
						wake_up(&conf->wait_barrier);
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void raid10_status(struct seq_file *seq, struct mddev *mddev)
 | 
					static void raid10_status(struct seq_file *seq, struct mddev *mddev)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5479,7 +5479,6 @@ static void make_discard_request(struct mddev *mddev, struct bio *bi)
 | 
				
			||||||
	last_sector = bi->bi_iter.bi_sector + (bi->bi_iter.bi_size>>9);
 | 
						last_sector = bi->bi_iter.bi_sector + (bi->bi_iter.bi_size>>9);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bi->bi_next = NULL;
 | 
						bi->bi_next = NULL;
 | 
				
			||||||
	md_write_start(mddev, bi);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	stripe_sectors = conf->chunk_sectors *
 | 
						stripe_sectors = conf->chunk_sectors *
 | 
				
			||||||
		(conf->raid_disks - conf->max_degraded);
 | 
							(conf->raid_disks - conf->max_degraded);
 | 
				
			||||||
| 
						 | 
					@ -5549,11 +5548,10 @@ static void make_discard_request(struct mddev *mddev, struct bio *bi)
 | 
				
			||||||
		release_stripe_plug(mddev, sh);
 | 
							release_stripe_plug(mddev, sh);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	md_write_end(mddev);
 | 
					 | 
				
			||||||
	bio_endio(bi);
 | 
						bio_endio(bi);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void raid5_make_request(struct mddev *mddev, struct bio * bi)
 | 
					static bool raid5_make_request(struct mddev *mddev, struct bio * bi)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct r5conf *conf = mddev->private;
 | 
						struct r5conf *conf = mddev->private;
 | 
				
			||||||
	int dd_idx;
 | 
						int dd_idx;
 | 
				
			||||||
| 
						 | 
					@ -5569,10 +5567,10 @@ static void raid5_make_request(struct mddev *mddev, struct bio * bi)
 | 
				
			||||||
		int ret = r5l_handle_flush_request(conf->log, bi);
 | 
							int ret = r5l_handle_flush_request(conf->log, bi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (ret == 0)
 | 
							if (ret == 0)
 | 
				
			||||||
			return;
 | 
								return true;
 | 
				
			||||||
		if (ret == -ENODEV) {
 | 
							if (ret == -ENODEV) {
 | 
				
			||||||
			md_flush_request(mddev, bi);
 | 
								md_flush_request(mddev, bi);
 | 
				
			||||||
			return;
 | 
								return true;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		/* ret == -EAGAIN, fallback */
 | 
							/* ret == -EAGAIN, fallback */
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
| 
						 | 
					@ -5582,6 +5580,8 @@ static void raid5_make_request(struct mddev *mddev, struct bio * bi)
 | 
				
			||||||
		do_flush = bi->bi_opf & REQ_PREFLUSH;
 | 
							do_flush = bi->bi_opf & REQ_PREFLUSH;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!md_write_start(mddev, bi))
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * If array is degraded, better not do chunk aligned read because
 | 
						 * If array is degraded, better not do chunk aligned read because
 | 
				
			||||||
	 * later we might have to read it again in order to reconstruct
 | 
						 * later we might have to read it again in order to reconstruct
 | 
				
			||||||
| 
						 | 
					@ -5591,18 +5591,18 @@ static void raid5_make_request(struct mddev *mddev, struct bio * bi)
 | 
				
			||||||
	    mddev->reshape_position == MaxSector) {
 | 
						    mddev->reshape_position == MaxSector) {
 | 
				
			||||||
		bi = chunk_aligned_read(mddev, bi);
 | 
							bi = chunk_aligned_read(mddev, bi);
 | 
				
			||||||
		if (!bi)
 | 
							if (!bi)
 | 
				
			||||||
			return;
 | 
								return true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (unlikely(bio_op(bi) == REQ_OP_DISCARD)) {
 | 
						if (unlikely(bio_op(bi) == REQ_OP_DISCARD)) {
 | 
				
			||||||
		make_discard_request(mddev, bi);
 | 
							make_discard_request(mddev, bi);
 | 
				
			||||||
		return;
 | 
							md_write_end(mddev);
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	logical_sector = bi->bi_iter.bi_sector & ~((sector_t)STRIPE_SECTORS-1);
 | 
						logical_sector = bi->bi_iter.bi_sector & ~((sector_t)STRIPE_SECTORS-1);
 | 
				
			||||||
	last_sector = bio_end_sector(bi);
 | 
						last_sector = bio_end_sector(bi);
 | 
				
			||||||
	bi->bi_next = NULL;
 | 
						bi->bi_next = NULL;
 | 
				
			||||||
	md_write_start(mddev, bi);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	prepare_to_wait(&conf->wait_for_overlap, &w, TASK_UNINTERRUPTIBLE);
 | 
						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) {
 | 
				
			||||||
| 
						 | 
					@ -5740,6 +5740,7 @@ static void raid5_make_request(struct mddev *mddev, struct bio * bi)
 | 
				
			||||||
	if (rw == WRITE)
 | 
						if (rw == WRITE)
 | 
				
			||||||
		md_write_end(mddev);
 | 
							md_write_end(mddev);
 | 
				
			||||||
	bio_endio(bi);
 | 
						bio_endio(bi);
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static sector_t raid5_size(struct mddev *mddev, sector_t sectors, int raid_disks);
 | 
					static sector_t raid5_size(struct mddev *mddev, sector_t sectors, int raid_disks);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue