Commit 310e9c85 authored by Jens Axboe's avatar Jens Axboe
Browse files

Merge branch 'md-next' of...

Merge branch 'md-next' of https://git.kernel.org/pub/scm/linux/kernel/git/song/md into for-6.4/block

Pull MD updates from Song:

"- md/bitmap: Optimal last page size, by Jon Derrick
 - Various raid10 fixes, by Yu Kuai and Li Nan
 - md: add error_handlers for raid0 and linear, by Mariusz Tkaczyk"

* 'md-next' of https://git.kernel.org/pub/scm/linux/kernel/git/song/md:
  md/raid5: remove unused working_disks variable
  md/raid10: don't call bio_start_io_acct twice for bio which experienced read error
  md/raid10: fix memleak of md thread
  md/raid10: fix memleak for 'conf->bio_split'
  md/raid10: fix leak of 'r10bio->remaining' for recovery
  md/raid10: don't BUG_ON() in raise_barrier()
  md: fix soft lockup in status_resync
  md: add error_handlers for raid0 and linear
  md: Use optimal I/O size for last bitmap page
  md: Fix types in sb writer
  md: Move sb writer loop to its own function
  md/raid10: Fix typo in comment (replacment -> replacement)
  md: make kobj_type structures constant
  md/raid10: fix null-ptr-deref in raid10_sync_request
  md/raid10: fix task hung in raid10d
parents d2a1d45c 7bc43612
Loading
Loading
Loading
Loading
+83 −60
Original line number Diff line number Diff line
@@ -209,76 +209,99 @@ static struct md_rdev *next_active_rdev(struct md_rdev *rdev, struct mddev *mdde
	return NULL;
}

static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait)
static unsigned int optimal_io_size(struct block_device *bdev,
				    unsigned int last_page_size,
				    unsigned int io_size)
{
	if (bdev_io_opt(bdev) > bdev_logical_block_size(bdev))
		return roundup(last_page_size, bdev_io_opt(bdev));
	return io_size;
}

static unsigned int bitmap_io_size(unsigned int io_size, unsigned int opt_size,
				   sector_t start, sector_t boundary)
{
	if (io_size != opt_size &&
	    start + opt_size / SECTOR_SIZE <= boundary)
		return opt_size;
	if (start + io_size / SECTOR_SIZE <= boundary)
		return io_size;

	/* Overflows boundary */
	return 0;
}

static int __write_sb_page(struct md_rdev *rdev, struct bitmap *bitmap,
			   struct page *page)
{
	struct md_rdev *rdev;
	struct block_device *bdev;
	struct mddev *mddev = bitmap->mddev;
	struct bitmap_storage *store = &bitmap->storage;

restart:
	rdev = NULL;
	while ((rdev = next_active_rdev(rdev, mddev)) != NULL) {
		int size = PAGE_SIZE;
		loff_t offset = mddev->bitmap_info.offset;
	sector_t offset = mddev->bitmap_info.offset;
	sector_t ps, sboff, doff;
	unsigned int size = PAGE_SIZE;
	unsigned int opt_size = PAGE_SIZE;

	bdev = (rdev->meta_bdev) ? rdev->meta_bdev : rdev->bdev;

	if (page->index == store->file_pages - 1) {
			int last_page_size = store->bytes & (PAGE_SIZE-1);
		unsigned int last_page_size = store->bytes & (PAGE_SIZE - 1);

		if (last_page_size == 0)
			last_page_size = PAGE_SIZE;
			size = roundup(last_page_size,
				       bdev_logical_block_size(bdev));
		size = roundup(last_page_size, bdev_logical_block_size(bdev));
		opt_size = optimal_io_size(bdev, last_page_size, size);
	}
		/* Just make sure we aren't corrupting data or
		 * metadata
		 */

	ps = page->index * PAGE_SIZE / SECTOR_SIZE;
	sboff = rdev->sb_start + offset;
	doff = rdev->data_offset;

	/* Just make sure we aren't corrupting data or metadata */
	if (mddev->external) {
		/* Bitmap could be anywhere. */
			if (rdev->sb_start + offset + (page->index
						       * (PAGE_SIZE/512))
			    > rdev->data_offset
			    &&
			    rdev->sb_start + offset
			    < (rdev->data_offset + mddev->dev_sectors
			     + (PAGE_SIZE/512)))
				goto bad_alignment;
		if (sboff + ps > doff &&
		    sboff < (doff + mddev->dev_sectors + PAGE_SIZE / SECTOR_SIZE))
			return -EINVAL;
	} else if (offset < 0) {
		/* DATA  BITMAP METADATA  */
			if (offset
			    + (long)(page->index * (PAGE_SIZE/512))
			    + size/512 > 0)
		size = bitmap_io_size(size, opt_size, offset + ps, 0);
		if (size == 0)
			/* bitmap runs in to metadata */
				goto bad_alignment;
			if (rdev->data_offset + mddev->dev_sectors
			    > rdev->sb_start + offset)
			return -EINVAL;

		if (doff + mddev->dev_sectors > sboff)
			/* data runs in to bitmap */
				goto bad_alignment;
			return -EINVAL;
	} else if (rdev->sb_start < rdev->data_offset) {
		/* METADATA BITMAP DATA */
			if (rdev->sb_start
			    + offset
			    + page->index*(PAGE_SIZE/512) + size/512
			    > rdev->data_offset)
		size = bitmap_io_size(size, opt_size, sboff + ps, doff);
		if (size == 0)
			/* bitmap runs in to data */
				goto bad_alignment;
			return -EINVAL;
	} else {
		/* DATA METADATA BITMAP - no problems */
	}
		md_super_write(mddev, rdev,
			       rdev->sb_start + offset
			       + page->index * (PAGE_SIZE/512),
			       size,
			       page);
	}

	if (wait && md_super_wait(mddev) < 0)
		goto restart;
	md_super_write(mddev, rdev, sboff + ps, (int) size, page);
	return 0;
}

 bad_alignment:
	return -EINVAL;
static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait)
{
	struct md_rdev *rdev;
	struct mddev *mddev = bitmap->mddev;
	int ret;

	do {
		rdev = NULL;
		while ((rdev = next_active_rdev(rdev, mddev)) != NULL) {
			ret = __write_sb_page(rdev, bitmap, page);
			if (ret)
				return ret;
		}
	} while (wait && md_super_wait(mddev) < 0);

	return 0;
}

static void md_bitmap_file_kick(struct bitmap *bitmap);
+13 −1
Original line number Diff line number Diff line
@@ -223,7 +223,8 @@ static bool linear_make_request(struct mddev *mddev, struct bio *bio)
		     bio_sector < start_sector))
		goto out_of_bounds;

	if (unlikely(is_mddev_broken(tmp_dev->rdev, "linear"))) {
	if (unlikely(is_rdev_broken(tmp_dev->rdev))) {
		md_error(mddev, tmp_dev->rdev);
		bio_io_error(bio);
		return true;
	}
@@ -270,6 +271,16 @@ static void linear_status (struct seq_file *seq, struct mddev *mddev)
	seq_printf(seq, " %dk rounding", mddev->chunk_sectors / 2);
}

static void linear_error(struct mddev *mddev, struct md_rdev *rdev)
{
	if (!test_and_set_bit(MD_BROKEN, &mddev->flags)) {
		char *md_name = mdname(mddev);

		pr_crit("md/linear%s: Disk failure on %pg detected, failing array.\n",
			md_name, rdev->bdev);
	}
}

static void linear_quiesce(struct mddev *mddev, int state)
{
}
@@ -286,6 +297,7 @@ static struct md_personality linear_personality =
	.hot_add_disk	= linear_add,
	.size		= linear_size,
	.quiesce	= linear_quiesce,
	.error_handler	= linear_error,
};

static int __init linear_init (void)
+15 −12
Original line number Diff line number Diff line
@@ -78,7 +78,7 @@
static LIST_HEAD(pers_list);
static DEFINE_SPINLOCK(pers_lock);

static struct kobj_type md_ktype;
static const struct kobj_type md_ktype;

struct md_cluster_operations *md_cluster_ops;
EXPORT_SYMBOL(md_cluster_ops);
@@ -3597,7 +3597,7 @@ static const struct sysfs_ops rdev_sysfs_ops = {
	.show		= rdev_attr_show,
	.store		= rdev_attr_store,
};
static struct kobj_type rdev_ktype = {
static const struct kobj_type rdev_ktype = {
	.release	= rdev_free,
	.sysfs_ops	= &rdev_sysfs_ops,
	.default_groups	= rdev_default_groups,
@@ -5555,7 +5555,7 @@ static const struct sysfs_ops md_sysfs_ops = {
	.show	= md_attr_show,
	.store	= md_attr_store,
};
static struct kobj_type md_ktype = {
static const struct kobj_type md_ktype = {
	.release	= md_kobj_release,
	.sysfs_ops	= &md_sysfs_ops,
	.default_groups	= md_attr_groups,
@@ -7974,6 +7974,9 @@ void md_error(struct mddev *mddev, struct md_rdev *rdev)
		return;
	mddev->pers->error_handler(mddev, rdev);

	if (mddev->pers->level == 0 || mddev->pers->level == LEVEL_LINEAR)
		return;

	if (mddev->degraded && !test_bit(MD_BROKEN, &mddev->flags))
		set_bit(MD_RECOVERY_RECOVER, &mddev->recovery);
	sysfs_notify_dirent_safe(rdev->sysfs_state);
@@ -8029,16 +8032,16 @@ static int status_resync(struct seq_file *seq, struct mddev *mddev)
	} else if (resync > max_sectors) {
		resync = max_sectors;
	} else {
		resync -= atomic_read(&mddev->recovery_active);
		if (resync < MD_RESYNC_ACTIVE) {
		res = atomic_read(&mddev->recovery_active);
		/*
			 * Resync has started, but the subtraction has
			 * yielded one of the special values. Force it
			 * to active to ensure the status reports an
			 * active resync.
		 * Resync has started, but the subtraction has overflowed or
		 * yielded one of the special values. Force it to active to
		 * ensure the status reports an active resync.
		 */
		if (resync < res || resync - res < MD_RESYNC_ACTIVE)
			resync = MD_RESYNC_ACTIVE;
		}
		else
			resync -= res;
	}

	if (resync == MD_RESYNC_NONE) {
+2 −8
Original line number Diff line number Diff line
@@ -790,15 +790,9 @@ extern void mddev_destroy_serial_pool(struct mddev *mddev, struct md_rdev *rdev,
struct md_rdev *md_find_rdev_nr_rcu(struct mddev *mddev, int nr);
struct md_rdev *md_find_rdev_rcu(struct mddev *mddev, dev_t dev);

static inline bool is_mddev_broken(struct md_rdev *rdev, const char *md_type)
static inline bool is_rdev_broken(struct md_rdev *rdev)
{
	if (!disk_live(rdev->bdev->bd_disk)) {
		if (!test_and_set_bit(MD_BROKEN, &rdev->mddev->flags))
			pr_warn("md: %s: %s array has a missing/failed member\n",
				mdname(rdev->mddev), md_type);
		return true;
	}
	return false;
	return !disk_live(rdev->bdev->bd_disk);
}

static inline void rdev_dec_pending(struct md_rdev *rdev, struct mddev *mddev)
+13 −1
Original line number Diff line number Diff line
@@ -569,8 +569,9 @@ static bool raid0_make_request(struct mddev *mddev, struct bio *bio)
		return true;
	}

	if (unlikely(is_mddev_broken(tmp_dev, "raid0"))) {
	if (unlikely(is_rdev_broken(tmp_dev))) {
		bio_io_error(bio);
		md_error(mddev, tmp_dev);
		return true;
	}

@@ -592,6 +593,16 @@ static void raid0_status(struct seq_file *seq, struct mddev *mddev)
	return;
}

static void raid0_error(struct mddev *mddev, struct md_rdev *rdev)
{
	if (!test_and_set_bit(MD_BROKEN, &mddev->flags)) {
		char *md_name = mdname(mddev);

		pr_crit("md/raid0%s: Disk failure on %pg detected, failing array.\n",
			md_name, rdev->bdev);
	}
}

static void *raid0_takeover_raid45(struct mddev *mddev)
{
	struct md_rdev *rdev;
@@ -767,6 +778,7 @@ static struct md_personality raid0_personality=
	.size		= raid0_size,
	.takeover	= raid0_takeover,
	.quiesce	= raid0_quiesce,
	.error_handler	= raid0_error,
};

static int __init raid0_init (void)
Loading