diff options
-rw-r--r-- | drivers/block/drbd/drbd_int.h | 5 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_req.c | 33 |
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 | ||
582 | struct drbd_epoch { | 587 | struct 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 | ||
91 | static void drbd_req_free(struct drbd_request *req) | 93 | static 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 */ | ||
97 | static 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 | ||
152 | static void wake_all_senders(struct drbd_tconn *tconn) { | 150 | static void wake_all_senders(struct drbd_tconn *tconn) { |
@@ -196,12 +194,10 @@ static | |||
196 | void req_may_be_done(struct drbd_request *req) | 194 | void 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; |