Commit 844a6ae7 authored by Lars Ellenberg's avatar Lars Ellenberg Committed by Philipp Reisner

drbd: add lists to find oldest pending requests

Adding requests to per-device fifo lists as soon as possible after
allocating them leaves a simple list_first_entry_or_null() to find the
oldest request, regardless what it is still waiting for.
Signed-off-by: default avatarPhilipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: default avatarLars Ellenberg <lars.ellenberg@linbit.com>
parent e5f891b2
...@@ -318,6 +318,10 @@ struct drbd_request { ...@@ -318,6 +318,10 @@ struct drbd_request {
struct list_head tl_requests; /* ring list in the transfer log */ struct list_head tl_requests; /* ring list in the transfer log */
struct bio *master_bio; /* master bio pointer */ struct bio *master_bio; /* master bio pointer */
/* see struct drbd_device */
struct list_head req_pending_master_completion;
struct list_head req_pending_local;
/* for generic IO accounting */ /* for generic IO accounting */
unsigned long start_jif; unsigned long start_jif;
...@@ -738,7 +742,7 @@ struct submit_worker { ...@@ -738,7 +742,7 @@ struct submit_worker {
struct workqueue_struct *wq; struct workqueue_struct *wq;
struct work_struct worker; struct work_struct worker;
spinlock_t lock; /* protected by ..->resource->req_lock */
struct list_head writes; struct list_head writes;
}; };
...@@ -795,6 +799,11 @@ struct drbd_device { ...@@ -795,6 +799,11 @@ struct drbd_device {
struct rb_root read_requests; struct rb_root read_requests;
struct rb_root write_requests; struct rb_root write_requests;
/* for statistics and timeouts */
/* [0] read, [1] write */
struct list_head pending_master_completion[2];
struct list_head pending_completion[2];
/* use checksums for *this* resync */ /* use checksums for *this* resync */
bool use_csums; bool use_csums;
/* blocks to resync in this run [unit BM_BLOCK_SIZE] */ /* blocks to resync in this run [unit BM_BLOCK_SIZE] */
......
...@@ -1934,6 +1934,10 @@ void drbd_init_set_defaults(struct drbd_device *device) ...@@ -1934,6 +1934,10 @@ void drbd_init_set_defaults(struct drbd_device *device)
INIT_LIST_HEAD(&device->resync_work.list); INIT_LIST_HEAD(&device->resync_work.list);
INIT_LIST_HEAD(&device->unplug_work.list); INIT_LIST_HEAD(&device->unplug_work.list);
INIT_LIST_HEAD(&device->bm_io_work.w.list); INIT_LIST_HEAD(&device->bm_io_work.w.list);
INIT_LIST_HEAD(&device->pending_master_completion[0]);
INIT_LIST_HEAD(&device->pending_master_completion[1]);
INIT_LIST_HEAD(&device->pending_completion[0]);
INIT_LIST_HEAD(&device->pending_completion[1]);
device->resync_work.cb = w_resync_timer; device->resync_work.cb = w_resync_timer;
device->unplug_work.cb = w_send_write_hint; device->unplug_work.cb = w_send_write_hint;
...@@ -2268,6 +2272,8 @@ static void do_retry(struct work_struct *ws) ...@@ -2268,6 +2272,8 @@ static void do_retry(struct work_struct *ws)
} }
} }
/* called via drbd_req_put_completion_ref(),
* holds resource->req_lock */
void drbd_restart_request(struct drbd_request *req) void drbd_restart_request(struct drbd_request *req)
{ {
unsigned long flags; unsigned long flags;
...@@ -2687,7 +2693,6 @@ static int init_submitter(struct drbd_device *device) ...@@ -2687,7 +2693,6 @@ static int init_submitter(struct drbd_device *device)
return -ENOMEM; return -ENOMEM;
INIT_WORK(&device->submit.worker, do_submit); INIT_WORK(&device->submit.worker, do_submit);
spin_lock_init(&device->submit.lock);
INIT_LIST_HEAD(&device->submit.writes); INIT_LIST_HEAD(&device->submit.writes);
return 0; return 0;
} }
......
...@@ -84,6 +84,8 @@ static struct drbd_request *drbd_req_new(struct drbd_device *device, ...@@ -84,6 +84,8 @@ static struct drbd_request *drbd_req_new(struct drbd_device *device,
INIT_LIST_HEAD(&req->tl_requests); INIT_LIST_HEAD(&req->tl_requests);
INIT_LIST_HEAD(&req->w.list); INIT_LIST_HEAD(&req->w.list);
INIT_LIST_HEAD(&req->req_pending_master_completion);
INIT_LIST_HEAD(&req->req_pending_local);
/* one reference to be put by __drbd_make_request */ /* one reference to be put by __drbd_make_request */
atomic_set(&req->completion_ref, 1); atomic_set(&req->completion_ref, 1);
...@@ -120,12 +122,14 @@ void drbd_req_destroy(struct kref *kref) ...@@ -120,12 +122,14 @@ void drbd_req_destroy(struct kref *kref)
return; return;
} }
/* remove it from the transfer log. /* If called from mod_rq_state (expected normal case) or
* well, only if it had been there in the first * drbd_send_and_submit (the less likely normal path), this holds the
* place... if it had not (local only or conflicting * req_lock, and req->tl_requests will typicaly be on ->transfer_log,
* and never sent), it should still be "empty" as * though it may be still empty (never added to the transfer log).
* initialized in drbd_req_new(), so we can list_del() it *
* here unconditionally */ * If called from do_retry(), we do NOT hold the req_lock, but we are
* still allowed to unconditionally list_del(&req->tl_requests),
* because it will be on a local on-stack list only. */
list_del_init(&req->tl_requests); list_del_init(&req->tl_requests);
/* finally remove the request from the conflict detection /* finally remove the request from the conflict detection
...@@ -312,8 +316,15 @@ void drbd_req_complete(struct drbd_request *req, struct bio_and_error *m) ...@@ -312,8 +316,15 @@ void drbd_req_complete(struct drbd_request *req, struct bio_and_error *m)
if (req->i.waiting) if (req->i.waiting)
wake_up(&device->misc_wait); wake_up(&device->misc_wait);
/* Either we are about to complete to upper layers,
* or we will restart this request.
* In either case, the request object will be destroyed soon,
* so better remove it from all lists. */
list_del_init(&req->req_pending_master_completion);
} }
/* still holds resource->req_lock */
static int drbd_req_put_completion_ref(struct drbd_request *req, struct bio_and_error *m, int put) static int drbd_req_put_completion_ref(struct drbd_request *req, struct bio_and_error *m, int put)
{ {
struct drbd_device *device = req->device; struct drbd_device *device = req->device;
...@@ -400,6 +411,7 @@ static void mod_rq_state(struct drbd_request *req, struct bio_and_error *m, ...@@ -400,6 +411,7 @@ static void mod_rq_state(struct drbd_request *req, struct bio_and_error *m,
++k_put; ++k_put;
else else
++c_put; ++c_put;
list_del_init(&req->req_pending_local);
} }
if ((s & RQ_NET_PENDING) && (clear & RQ_NET_PENDING)) { if ((s & RQ_NET_PENDING) && (clear & RQ_NET_PENDING)) {
...@@ -1070,9 +1082,11 @@ drbd_submit_req_private_bio(struct drbd_request *req) ...@@ -1070,9 +1082,11 @@ drbd_submit_req_private_bio(struct drbd_request *req)
static void drbd_queue_write(struct drbd_device *device, struct drbd_request *req) static void drbd_queue_write(struct drbd_device *device, struct drbd_request *req)
{ {
spin_lock(&device->submit.lock); spin_lock_irq(&device->resource->req_lock);
list_add_tail(&req->tl_requests, &device->submit.writes); list_add_tail(&req->tl_requests, &device->submit.writes);
spin_unlock(&device->submit.lock); list_add_tail(&req->req_pending_master_completion,
&device->pending_master_completion[1 /* WRITE */]);
spin_unlock_irq(&device->resource->req_lock);
queue_work(device->submit.wq, &device->submit.worker); queue_work(device->submit.wq, &device->submit.worker);
} }
...@@ -1186,8 +1200,15 @@ static void drbd_send_and_submit(struct drbd_device *device, struct drbd_request ...@@ -1186,8 +1200,15 @@ static void drbd_send_and_submit(struct drbd_device *device, struct drbd_request
no_remote = true; no_remote = true;
} }
/* If it took the fast path in drbd_request_prepare, add it here.
* The slow path has added it already. */
if (list_empty(&req->req_pending_master_completion))
list_add_tail(&req->req_pending_master_completion,
&device->pending_master_completion[rw == WRITE]);
if (req->private_bio) { if (req->private_bio) {
/* needs to be marked within the same spinlock */ /* needs to be marked within the same spinlock */
list_add_tail(&req->req_pending_local,
&device->pending_completion[rw == WRITE]);
_req_mod(req, TO_BE_SUBMITTED); _req_mod(req, TO_BE_SUBMITTED);
/* but we need to give up the spinlock to submit */ /* but we need to give up the spinlock to submit */
submit_private_bio = true; submit_private_bio = true;
...@@ -1278,9 +1299,9 @@ void do_submit(struct work_struct *ws) ...@@ -1278,9 +1299,9 @@ void do_submit(struct work_struct *ws)
struct drbd_request *req, *tmp; struct drbd_request *req, *tmp;
for (;;) { for (;;) {
spin_lock(&device->submit.lock); spin_lock_irq(&device->resource->req_lock);
list_splice_tail_init(&device->submit.writes, &incoming); list_splice_tail_init(&device->submit.writes, &incoming);
spin_unlock(&device->submit.lock); spin_unlock_irq(&device->resource->req_lock);
submit_fast_path(device, &incoming); submit_fast_path(device, &incoming);
if (list_empty(&incoming)) if (list_empty(&incoming))
...@@ -1304,9 +1325,9 @@ void do_submit(struct work_struct *ws) ...@@ -1304,9 +1325,9 @@ void do_submit(struct work_struct *ws)
if (list_empty(&device->submit.writes)) if (list_empty(&device->submit.writes))
break; break;
spin_lock(&device->submit.lock); spin_lock_irq(&device->resource->req_lock);
list_splice_tail_init(&device->submit.writes, &more_incoming); list_splice_tail_init(&device->submit.writes, &more_incoming);
spin_unlock(&device->submit.lock); spin_unlock_irq(&device->resource->req_lock);
if (list_empty(&more_incoming)) if (list_empty(&more_incoming))
break; break;
......
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