md/raid1: introduce wait_for_serialization

Previously, we call check_and_add_serial when serialization is
enabled for write IO, but it could allocate and free memory
back and forth.

Now, let's just get an element from memory pool with the new
function, then insert node to rb tree if no collision happens.

Signed-off-by: Guoqing Jiang <guoqing.jiang@cloud.ionos.com>
Signed-off-by: Song Liu <songliubraving@fb.com>
This commit is contained in:
Guoqing Jiang 2019-12-23 10:49:02 +01:00 committed by Song Liu
parent 025471f9f5
commit d0d2d8ba04

View File

@ -56,32 +56,43 @@ static void lower_barrier(struct r1conf *conf, sector_t sector_nr);
INTERVAL_TREE_DEFINE(struct serial_info, node, sector_t, _subtree_last, INTERVAL_TREE_DEFINE(struct serial_info, node, sector_t, _subtree_last,
START, LAST, static inline, raid1_rb); START, LAST, static inline, raid1_rb);
static int check_and_add_serial(struct md_rdev *rdev, sector_t lo, sector_t hi) static int check_and_add_serial(struct md_rdev *rdev, struct r1bio *r1_bio,
struct serial_info *si, int idx)
{ {
struct serial_info *si;
unsigned long flags; unsigned long flags;
int ret = 0; int ret = 0;
struct mddev *mddev = rdev->mddev; sector_t lo = r1_bio->sector;
int idx = sector_to_idx(lo); sector_t hi = lo + r1_bio->sectors;
struct serial_in_rdev *serial = &rdev->serial[idx]; struct serial_in_rdev *serial = &rdev->serial[idx];
si = mempool_alloc(mddev->serial_info_pool, GFP_NOIO);
spin_lock_irqsave(&serial->serial_lock, flags); spin_lock_irqsave(&serial->serial_lock, flags);
/* collision happened */ /* collision happened */
if (raid1_rb_iter_first(&serial->serial_rb, lo, hi)) if (raid1_rb_iter_first(&serial->serial_rb, lo, hi))
ret = -EBUSY; ret = -EBUSY;
if (!ret) { else {
si->start = lo; si->start = lo;
si->last = hi; si->last = hi;
raid1_rb_insert(si, &serial->serial_rb); raid1_rb_insert(si, &serial->serial_rb);
} else }
mempool_free(si, mddev->serial_info_pool);
spin_unlock_irqrestore(&serial->serial_lock, flags); spin_unlock_irqrestore(&serial->serial_lock, flags);
return ret; return ret;
} }
static void wait_for_serialization(struct md_rdev *rdev, struct r1bio *r1_bio)
{
struct mddev *mddev = rdev->mddev;
struct serial_info *si;
int idx = sector_to_idx(r1_bio->sector);
struct serial_in_rdev *serial = &rdev->serial[idx];
if (WARN_ON(!mddev->serial_info_pool))
return;
si = mempool_alloc(mddev->serial_info_pool, GFP_NOIO);
wait_event(serial->serial_io_wait,
check_and_add_serial(rdev, r1_bio, si, idx) == 0);
}
static void remove_serial(struct md_rdev *rdev, sector_t lo, sector_t hi) static void remove_serial(struct md_rdev *rdev, sector_t lo, sector_t hi)
{ {
struct serial_info *si; struct serial_info *si;
@ -1342,7 +1353,6 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
struct raid1_plug_cb *plug = NULL; struct raid1_plug_cb *plug = NULL;
int first_clone; int first_clone;
int max_sectors; int max_sectors;
sector_t lo, hi;
if (mddev_is_clustered(mddev) && if (mddev_is_clustered(mddev) &&
md_cluster_ops->area_resyncing(mddev, WRITE, md_cluster_ops->area_resyncing(mddev, WRITE,
@ -1370,8 +1380,6 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
r1_bio = alloc_r1bio(mddev, bio); r1_bio = alloc_r1bio(mddev, bio);
r1_bio->sectors = max_write_sectors; r1_bio->sectors = max_write_sectors;
lo = r1_bio->sector;
hi = r1_bio->sector + r1_bio->sectors;
if (conf->pending_count >= max_queued_requests) { if (conf->pending_count >= max_queued_requests) {
md_wakeup_thread(mddev->thread); md_wakeup_thread(mddev->thread);
@ -1488,8 +1496,6 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
for (i = 0; i < disks; i++) { for (i = 0; i < disks; i++) {
struct bio *mbio = NULL; struct bio *mbio = NULL;
struct md_rdev *rdev = conf->mirrors[i].rdev; struct md_rdev *rdev = conf->mirrors[i].rdev;
int idx = sector_to_idx(lo);
struct serial_in_rdev *serial = &rdev->serial[idx];
if (!r1_bio->bios[i]) if (!r1_bio->bios[i])
continue; continue;
@ -1518,14 +1524,11 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
if (r1_bio->behind_master_bio) { if (r1_bio->behind_master_bio) {
if (test_bit(CollisionCheck, &rdev->flags)) if (test_bit(CollisionCheck, &rdev->flags))
wait_event(serial->serial_io_wait, wait_for_serialization(rdev, r1_bio);
check_and_add_serial(rdev, lo, hi)
== 0);
if (test_bit(WriteMostly, &rdev->flags)) if (test_bit(WriteMostly, &rdev->flags))
atomic_inc(&r1_bio->behind_remaining); atomic_inc(&r1_bio->behind_remaining);
} else if (mddev->serialize_policy) } else if (mddev->serialize_policy)
wait_event(serial->serial_io_wait, wait_for_serialization(rdev, r1_bio);
check_and_add_serial(rdev, lo, hi) == 0);
r1_bio->bios[i] = mbio; r1_bio->bios[i] = mbio;