md: factor out the rdev overlaps check from rdev_size_store
This splits the code into nicely readable chunks and also avoids the refcount inc/dec manipulations. Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Logan Gunthorpe <logang@deltatee.com> Reviewed-by: Hannes Reinecke <hare@suse.de> Signed-off-by: Song Liu <song@kernel.org> Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
parent
33b614e334
commit
2652a1bd2e
@ -3343,14 +3343,33 @@ rdev_size_show(struct md_rdev *rdev, char *page)
|
|||||||
return sprintf(page, "%llu\n", (unsigned long long)rdev->sectors / 2);
|
return sprintf(page, "%llu\n", (unsigned long long)rdev->sectors / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int overlaps(sector_t s1, sector_t l1, sector_t s2, sector_t l2)
|
static int md_rdevs_overlap(struct md_rdev *a, struct md_rdev *b)
|
||||||
{
|
{
|
||||||
/* check if two start/length pairs overlap */
|
/* check if two start/length pairs overlap */
|
||||||
if (s1+l1 <= s2)
|
if (a->data_offset + a->sectors <= b->data_offset)
|
||||||
return 0;
|
return false;
|
||||||
if (s2+l2 <= s1)
|
if (b->data_offset + b->sectors <= a->data_offset)
|
||||||
return 0;
|
return false;
|
||||||
return 1;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool md_rdev_overlaps(struct md_rdev *rdev)
|
||||||
|
{
|
||||||
|
struct mddev *mddev;
|
||||||
|
struct md_rdev *rdev2;
|
||||||
|
|
||||||
|
spin_lock(&all_mddevs_lock);
|
||||||
|
list_for_each_entry(mddev, &all_mddevs, all_mddevs) {
|
||||||
|
rdev_for_each(rdev2, mddev) {
|
||||||
|
if (rdev != rdev2 && rdev->bdev == rdev2->bdev &&
|
||||||
|
md_rdevs_overlap(rdev, rdev2)) {
|
||||||
|
spin_unlock(&all_mddevs_lock);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spin_unlock(&all_mddevs_lock);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int strict_blocks_to_sectors(const char *buf, sector_t *sectors)
|
static int strict_blocks_to_sectors(const char *buf, sector_t *sectors)
|
||||||
@ -3402,46 +3421,21 @@ rdev_size_store(struct md_rdev *rdev, const char *buf, size_t len)
|
|||||||
return -EINVAL; /* component must fit device */
|
return -EINVAL; /* component must fit device */
|
||||||
|
|
||||||
rdev->sectors = sectors;
|
rdev->sectors = sectors;
|
||||||
if (sectors > oldsectors && my_mddev->external) {
|
|
||||||
/* Need to check that all other rdevs with the same
|
/*
|
||||||
* ->bdev do not overlap. 'rcu' is sufficient to walk
|
* Check that all other rdevs with the same bdev do not overlap. This
|
||||||
* the rdev lists safely.
|
* check does not provide a hard guarantee, it just helps avoid
|
||||||
* This check does not provide a hard guarantee, it
|
* dangerous mistakes.
|
||||||
* just helps avoid dangerous mistakes.
|
*/
|
||||||
|
if (sectors > oldsectors && my_mddev->external &&
|
||||||
|
md_rdev_overlaps(rdev)) {
|
||||||
|
/*
|
||||||
|
* Someone else could have slipped in a size change here, but
|
||||||
|
* doing so is just silly. We put oldsectors back because we
|
||||||
|
* know it is safe, and trust userspace not to race with itself.
|
||||||
*/
|
*/
|
||||||
struct mddev *mddev;
|
rdev->sectors = oldsectors;
|
||||||
int overlap = 0;
|
return -EBUSY;
|
||||||
struct list_head *tmp;
|
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
for_each_mddev(mddev, tmp) {
|
|
||||||
struct md_rdev *rdev2;
|
|
||||||
|
|
||||||
rdev_for_each(rdev2, mddev)
|
|
||||||
if (rdev->bdev == rdev2->bdev &&
|
|
||||||
rdev != rdev2 &&
|
|
||||||
overlaps(rdev->data_offset, rdev->sectors,
|
|
||||||
rdev2->data_offset,
|
|
||||||
rdev2->sectors)) {
|
|
||||||
overlap = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (overlap) {
|
|
||||||
mddev_put(mddev);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rcu_read_unlock();
|
|
||||||
if (overlap) {
|
|
||||||
/* Someone else could have slipped in a size
|
|
||||||
* change here, but doing so is just silly.
|
|
||||||
* We put oldsectors back because we *know* it is
|
|
||||||
* safe, and trust userspace not to race with
|
|
||||||
* itself
|
|
||||||
*/
|
|
||||||
rdev->sectors = oldsectors;
|
|
||||||
return -EBUSY;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user