aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/block/drbd/drbd_int.h5
-rw-r--r--drivers/block/drbd/drbd_req.c33
2 files changed, 24 insertions, 14 deletions
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h
index 8536fabbf984..52ad1bfce85a 100644
--- a/drivers/block/drbd/drbd_int.h
+++ b/drivers/block/drbd/drbd_int.h
@@ -577,6 +577,11 @@ struct drbd_request {
577 struct bio *master_bio; /* master bio pointer */ 577 struct bio *master_bio; /* master bio pointer */
578 unsigned long rq_state; /* see comments above _req_mod() */ 578 unsigned long rq_state; /* see comments above _req_mod() */
579 unsigned long start_time; 579 unsigned long start_time;
580
581 /* once it hits 0, we may complete the master_bio */
582 atomic_t completion_ref;
583 /* once it hits 0, we may destroy this drbd_request object */
584 struct kref kref;
580}; 585};
581 586
582struct drbd_epoch { 587struct drbd_epoch {
diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c
index 6bac415358d7..ae894af428c1 100644
--- a/drivers/block/drbd/drbd_req.c
+++ b/drivers/block/drbd/drbd_req.c
@@ -85,17 +85,15 @@ static struct drbd_request *drbd_req_new(struct drbd_conf *mdev,
85 INIT_LIST_HEAD(&req->tl_requests); 85 INIT_LIST_HEAD(&req->tl_requests);
86 INIT_LIST_HEAD(&req->w.list); 86 INIT_LIST_HEAD(&req->w.list);
87 87
88 atomic_set(&req->completion_ref, 1);
89 kref_init(&req->kref);
88 return req; 90 return req;
89} 91}
90 92
91static void drbd_req_free(struct drbd_request *req) 93static void drbd_req_destroy(struct kref *kref)
92{
93 mempool_free(req, drbd_request_mempool);
94}
95
96/* rw is bio_data_dir(), only READ or WRITE */
97static void _req_is_done(struct drbd_conf *mdev, struct drbd_request *req, const int rw)
98{ 94{
95 struct drbd_request *req = container_of(kref, struct drbd_request, kref);
96 struct drbd_conf *mdev = req->w.mdev;
99 const unsigned long s = req->rq_state; 97 const unsigned long s = req->rq_state;
100 98
101 /* remove it from the transfer log. 99 /* remove it from the transfer log.
@@ -109,7 +107,7 @@ static void _req_is_done(struct drbd_conf *mdev, struct drbd_request *req, const
109 /* if it was a write, we may have to set the corresponding 107 /* if it was a write, we may have to set the corresponding
110 * bit(s) out-of-sync first. If it had a local part, we need to 108 * bit(s) out-of-sync first. If it had a local part, we need to
111 * release the reference to the activity log. */ 109 * release the reference to the activity log. */
112 if (rw == WRITE) { 110 if (s & RQ_WRITE) {
113 /* Set out-of-sync unless both OK flags are set 111 /* Set out-of-sync unless both OK flags are set
114 * (local only or remote failed). 112 * (local only or remote failed).
115 * Other places where we set out-of-sync: 113 * Other places where we set out-of-sync:
@@ -146,7 +144,7 @@ static void _req_is_done(struct drbd_conf *mdev, struct drbd_request *req, const
146 if (s & RQ_POSTPONED) 144 if (s & RQ_POSTPONED)
147 drbd_restart_request(req); 145 drbd_restart_request(req);
148 else 146 else
149 drbd_req_free(req); 147 mempool_free(req, drbd_request_mempool);
150} 148}
151 149
152static void wake_all_senders(struct drbd_tconn *tconn) { 150static void wake_all_senders(struct drbd_tconn *tconn) {
@@ -196,12 +194,10 @@ static
196void req_may_be_done(struct drbd_request *req) 194void req_may_be_done(struct drbd_request *req)
197{ 195{
198 const unsigned long s = req->rq_state; 196 const unsigned long s = req->rq_state;
199 struct drbd_conf *mdev = req->w.mdev;
200 int rw = req->rq_state & RQ_WRITE ? WRITE : READ;
201 197
202 /* req->master_bio still present means: Not yet completed. 198 /* req->master_bio still present means: Not yet completed.
203 * 199 *
204 * Unless this is RQ_POSTPONED, which will cause _req_is_done() to 200 * Unless this is RQ_POSTPONED, which will cause drbd_req_destroy() to
205 * queue it on the retry workqueue instead of destroying it. 201 * queue it on the retry workqueue instead of destroying it.
206 */ 202 */
207 if (req->master_bio && !(s & RQ_POSTPONED)) 203 if (req->master_bio && !(s & RQ_POSTPONED))
@@ -216,7 +212,7 @@ void req_may_be_done(struct drbd_request *req)
216 /* this is disconnected (local only) operation, 212 /* this is disconnected (local only) operation,
217 * or protocol A, B, or C P_BARRIER_ACK, 213 * or protocol A, B, or C P_BARRIER_ACK,
218 * or killed from the transfer log due to connection loss. */ 214 * or killed from the transfer log due to connection loss. */
219 _req_is_done(mdev, req, rw); 215 kref_put(&req->kref, drbd_req_destroy);
220 } 216 }
221 /* else: network part and not DONE yet. that is 217 /* else: network part and not DONE yet. that is
222 * protocol A, B, or C, barrier ack still pending... */ 218 * protocol A, B, or C, barrier ack still pending... */
@@ -250,6 +246,15 @@ void req_may_be_completed(struct drbd_request *req, struct bio_and_error *m)
250 if (s & RQ_NET_PENDING) 246 if (s & RQ_NET_PENDING)
251 return; 247 return;
252 248
249 /* FIXME
250 * instead of all the RQ_FLAGS, actually use the completion_ref
251 * to decide if this is ready to be completed. */
252 if (req->master_bio) {
253 int complete = atomic_dec_and_test(&req->completion_ref);
254 D_ASSERT(complete != 0);
255 } else
256 D_ASSERT(atomic_read(&req->completion_ref) == 0);
257
253 if (req->master_bio) { 258 if (req->master_bio) {
254 int rw = bio_rw(req->master_bio); 259 int rw = bio_rw(req->master_bio);
255 260
@@ -1113,7 +1118,7 @@ struct drbd_request *find_oldest_request(struct drbd_tconn *tconn)
1113 * and find the oldest not yet completed request */ 1118 * and find the oldest not yet completed request */
1114 struct drbd_request *r; 1119 struct drbd_request *r;
1115 list_for_each_entry(r, &tconn->transfer_log, tl_requests) { 1120 list_for_each_entry(r, &tconn->transfer_log, tl_requests) {
1116 if (r->rq_state & (RQ_NET_PENDING|RQ_LOCAL_PENDING)) 1121 if (atomic_read(&r->completion_ref))
1117 return r; 1122 return r;
1118 } 1123 }
1119 return NULL; 1124 return NULL;