Commit 5e472264 authored by Andreas Gruenbacher's avatar Andreas Gruenbacher Committed by Philipp Reisner

drbd: _req_conflicts(): Get rid of the epoch_entries tree

Instead of keeping a separate tree for local and remote write requests
for finding requests and for conflict detection, use the same tree for
both purposes.  Introduce a flag to allow distinguishing the two
possible types of entries in this tree.
Signed-off-by: default avatarPhilipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: default avatarLars Ellenberg <lars.ellenberg@linbit.com>
parent 53840641
...@@ -1045,9 +1045,6 @@ struct drbd_conf { ...@@ -1045,9 +1045,6 @@ struct drbd_conf {
struct list_head read_ee; /* IO in progress (any read) */ struct list_head read_ee; /* IO in progress (any read) */
struct list_head net_ee; /* zero-copy network send in progress */ struct list_head net_ee; /* zero-copy network send in progress */
/* Interval tree of pending remote write requests (struct drbd_epoch_entry) */
struct rb_root epoch_entries;
/* this one is protected by ee_lock, single thread */ /* this one is protected by ee_lock, single thread */
struct drbd_epoch_entry *last_write_w_barrier; struct drbd_epoch_entry *last_write_w_barrier;
......
...@@ -9,6 +9,7 @@ struct drbd_interval { ...@@ -9,6 +9,7 @@ struct drbd_interval {
sector_t sector; /* start sector of the interval */ sector_t sector; /* start sector of the interval */
unsigned int size; /* size in bytes */ unsigned int size; /* size in bytes */
sector_t end; /* highest interval end in subtree */ sector_t end; /* highest interval end in subtree */
int local:1 /* local or remote request? */;
int waiting:1; int waiting:1;
}; };
......
...@@ -3450,7 +3450,6 @@ struct drbd_conf *drbd_new_device(unsigned int minor) ...@@ -3450,7 +3450,6 @@ struct drbd_conf *drbd_new_device(unsigned int minor)
goto out_no_tl; goto out_no_tl;
mdev->read_requests = RB_ROOT; mdev->read_requests = RB_ROOT;
mdev->write_requests = RB_ROOT; mdev->write_requests = RB_ROOT;
mdev->epoch_entries = RB_ROOT;
mdev->current_epoch = kzalloc(sizeof(struct drbd_epoch), GFP_KERNEL); mdev->current_epoch = kzalloc(sizeof(struct drbd_epoch), GFP_KERNEL);
if (!mdev->current_epoch) if (!mdev->current_epoch)
......
...@@ -336,6 +336,7 @@ struct drbd_epoch_entry *drbd_alloc_ee(struct drbd_conf *mdev, ...@@ -336,6 +336,7 @@ struct drbd_epoch_entry *drbd_alloc_ee(struct drbd_conf *mdev,
drbd_clear_interval(&e->i); drbd_clear_interval(&e->i);
e->i.size = data_size; e->i.size = data_size;
e->i.sector = sector; e->i.sector = sector;
e->i.local = false;
e->i.waiting = false; e->i.waiting = false;
e->epoch = NULL; e->epoch = NULL;
...@@ -1508,7 +1509,7 @@ find_request(struct drbd_conf *mdev, struct rb_root *root, u64 id, ...@@ -1508,7 +1509,7 @@ find_request(struct drbd_conf *mdev, struct rb_root *root, u64 id,
/* Request object according to our peer */ /* Request object according to our peer */
req = (struct drbd_request *)(unsigned long)id; req = (struct drbd_request *)(unsigned long)id;
if (drbd_contains_interval(root, sector, &req->i)) if (drbd_contains_interval(root, sector, &req->i) && req->i.local)
return req; return req;
if (!missing_ok) { if (!missing_ok) {
dev_err(DEV, "%s: failed to find request %lu, sector %llus\n", func, dev_err(DEV, "%s: failed to find request %lu, sector %llus\n", func,
...@@ -1788,17 +1789,12 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd, ...@@ -1788,17 +1789,12 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd,
/* conflict detection and handling: /* conflict detection and handling:
* 1. wait on the sequence number, * 1. wait on the sequence number,
* in case this data packet overtook ACK packets. * in case this data packet overtook ACK packets.
* 2. check our interval trees for conflicting requests: * 2. check for conflicting write requests.
* we only need to check the write_requests tree; the
* epoch_entries tree cannot contain any overlaps because
* they were already eliminated on the submitting node.
* *
* Note: for two_primaries, we are protocol C, * Note: for two_primaries, we are protocol C,
* so there cannot be any request that is DONE * so there cannot be any request that is DONE
* but still on the transfer log. * but still on the transfer log.
* *
* unconditionally add to the epoch_entries tree.
*
* if no conflicting request is found: * if no conflicting request is found:
* submit. * submit.
* *
...@@ -1823,12 +1819,9 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd, ...@@ -1823,12 +1819,9 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd,
spin_lock_irq(&mdev->tconn->req_lock); spin_lock_irq(&mdev->tconn->req_lock);
drbd_insert_interval(&mdev->epoch_entries, &e->i);
first = 1; first = 1;
for (;;) { for (;;) {
struct drbd_interval *i; struct drbd_interval *i;
struct drbd_request *req2;
int have_unacked = 0; int have_unacked = 0;
int have_conflict = 0; int have_conflict = 0;
prepare_to_wait(&mdev->misc_wait, &wait, prepare_to_wait(&mdev->misc_wait, &wait,
...@@ -1836,18 +1829,23 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd, ...@@ -1836,18 +1829,23 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd,
i = drbd_find_overlap(&mdev->write_requests, sector, size); i = drbd_find_overlap(&mdev->write_requests, sector, size);
if (i) { if (i) {
req2 = container_of(i, struct drbd_request, i);
/* only ALERT on first iteration, /* only ALERT on first iteration,
* we may be woken up early... */ * we may be woken up early... */
if (first) if (first)
dev_alert(DEV, "%s[%u] Concurrent local write detected!" dev_alert(DEV, "%s[%u] Concurrent %s write detected!"
" new: %llus +%u; pending: %llus +%u\n", " new: %llus +%u; pending: %llus +%u\n",
current->comm, current->pid, current->comm, current->pid,
i->local ? "local" : "remote",
(unsigned long long)sector, size, (unsigned long long)sector, size,
(unsigned long long)req2->i.sector, req2->i.size); (unsigned long long)i->sector, i->size);
if (i->local) {
struct drbd_request *req2;
req2 = container_of(i, struct drbd_request, i);
if (req2->rq_state & RQ_NET_PENDING) if (req2->rq_state & RQ_NET_PENDING)
++have_unacked; ++have_unacked;
}
++have_conflict; ++have_conflict;
} }
if (!have_conflict) if (!have_conflict)
...@@ -1873,7 +1871,6 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd, ...@@ -1873,7 +1871,6 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd,
} }
if (signal_pending(current)) { if (signal_pending(current)) {
drbd_remove_epoch_entry_interval(mdev, e);
spin_unlock_irq(&mdev->tconn->req_lock); spin_unlock_irq(&mdev->tconn->req_lock);
finish_wait(&mdev->misc_wait, &wait); finish_wait(&mdev->misc_wait, &wait);
goto out_interrupted; goto out_interrupted;
...@@ -1896,6 +1893,8 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd, ...@@ -1896,6 +1893,8 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd,
spin_lock_irq(&mdev->tconn->req_lock); spin_lock_irq(&mdev->tconn->req_lock);
} }
finish_wait(&mdev->misc_wait, &wait); finish_wait(&mdev->misc_wait, &wait);
drbd_insert_interval(&mdev->write_requests, &e->i);
} }
list_add(&e->w.list, &mdev->active_ee); list_add(&e->w.list, &mdev->active_ee);
......
...@@ -74,6 +74,7 @@ static struct drbd_request *drbd_req_new(struct drbd_conf *mdev, ...@@ -74,6 +74,7 @@ static struct drbd_request *drbd_req_new(struct drbd_conf *mdev,
drbd_clear_interval(&req->i); drbd_clear_interval(&req->i);
req->i.sector = bio_src->bi_sector; req->i.sector = bio_src->bi_sector;
req->i.size = bio_src->bi_size; req->i.size = bio_src->bi_size;
req->i.local = true;
req->i.waiting = false; req->i.waiting = false;
INIT_LIST_HEAD(&req->tl_requests); INIT_LIST_HEAD(&req->tl_requests);
...@@ -317,8 +318,6 @@ static void _req_may_be_done_not_susp(struct drbd_request *req, struct bio_and_e ...@@ -317,8 +318,6 @@ static void _req_may_be_done_not_susp(struct drbd_request *req, struct bio_and_e
* to happen, but this is the rationale why we also have to check for * to happen, but this is the rationale why we also have to check for
* conflicting requests with local origin, and why we have to do so regardless * conflicting requests with local origin, and why we have to do so regardless
* of whether we allowed multiple primaries. * of whether we allowed multiple primaries.
*
* In case we only have one primary, the epoch_entries tree is empty.
*/ */
static int _req_conflicts(struct drbd_request *req) static int _req_conflicts(struct drbd_request *req)
{ {
...@@ -334,35 +333,16 @@ static int _req_conflicts(struct drbd_request *req) ...@@ -334,35 +333,16 @@ static int _req_conflicts(struct drbd_request *req)
i = drbd_find_overlap(&mdev->write_requests, sector, size); i = drbd_find_overlap(&mdev->write_requests, sector, size);
if (i) { if (i) {
struct drbd_request *req2 = dev_alert(DEV, "%s[%u] Concurrent %s write detected! "
container_of(i, struct drbd_request, i);
dev_alert(DEV, "%s[%u] Concurrent local write detected! "
"[DISCARD L] new: %llus +%u; " "[DISCARD L] new: %llus +%u; "
"pending: %llus +%u\n", "pending: %llus +%u\n",
current->comm, current->pid, current->comm, current->pid,
i->local ? "local" : "remote",
(unsigned long long)sector, size, (unsigned long long)sector, size,
(unsigned long long)req2->i.sector, req2->i.size); (unsigned long long)i->sector, i->size);
goto out_conflict; goto out_conflict;
} }
if (!RB_EMPTY_ROOT(&mdev->epoch_entries)) {
/* check for overlapping requests with remote origin */
i = drbd_find_overlap(&mdev->epoch_entries, sector, size);
if (i) {
struct drbd_epoch_entry *e =
container_of(i, struct drbd_epoch_entry, i);
dev_alert(DEV, "%s[%u] Concurrent remote write detected!"
" [DISCARD L] new: %llus +%u; "
"pending: %llus +%u\n",
current->comm, current->pid,
(unsigned long long)sector, size,
(unsigned long long)e->i.sector, e->i.size);
goto out_conflict;
}
}
/* this is like it should be, and what we expected. /* this is like it should be, and what we expected.
* our users do behave after all... */ * our users do behave after all... */
put_net_conf(mdev->tconn); put_net_conf(mdev->tconn);
......
...@@ -123,7 +123,7 @@ static void drbd_endio_write_sec_final(struct drbd_epoch_entry *e) __releases(lo ...@@ -123,7 +123,7 @@ static void drbd_endio_write_sec_final(struct drbd_epoch_entry *e) __releases(lo
list_add_tail(&e->w.list, &mdev->done_ee); list_add_tail(&e->w.list, &mdev->done_ee);
/* /*
* Do not remove from the epoch_entries tree here: we did not send the * Do not remove from the write_requests tree here: we did not send the
* Ack yet and did not wake possibly waiting conflicting requests. * Ack yet and did not wake possibly waiting conflicting requests.
* Removed from the tree from "drbd_process_done_ee" within the * Removed from the tree from "drbd_process_done_ee" within the
* appropriate w.cb (e_end_block/e_end_resync_block) or from * appropriate w.cb (e_end_block/e_end_resync_block) or from
......
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