diff options
-rw-r--r-- | drivers/block/drbd/drbd_req.c | 20 |
1 files changed, 14 insertions, 6 deletions
diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 09803d0d5207..4c7fee1a5a85 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c | |||
@@ -1086,11 +1086,13 @@ drbd_request_prepare(struct drbd_device *device, struct bio *bio, unsigned long | |||
1086 | 1086 | ||
1087 | static void drbd_send_and_submit(struct drbd_device *device, struct drbd_request *req) | 1087 | static void drbd_send_and_submit(struct drbd_device *device, struct drbd_request *req) |
1088 | { | 1088 | { |
1089 | struct drbd_resource *resource = device->resource; | ||
1089 | const int rw = bio_rw(req->master_bio); | 1090 | const int rw = bio_rw(req->master_bio); |
1090 | struct bio_and_error m = { NULL, }; | 1091 | struct bio_and_error m = { NULL, }; |
1091 | bool no_remote = false; | 1092 | bool no_remote = false; |
1093 | bool submit_private_bio = false; | ||
1092 | 1094 | ||
1093 | spin_lock_irq(&device->resource->req_lock); | 1095 | spin_lock_irq(&resource->req_lock); |
1094 | if (rw == WRITE) { | 1096 | if (rw == WRITE) { |
1095 | /* This may temporarily give up the req_lock, | 1097 | /* This may temporarily give up the req_lock, |
1096 | * but will re-aquire it before it returns here. | 1098 | * but will re-aquire it before it returns here. |
@@ -1152,9 +1154,7 @@ static void drbd_send_and_submit(struct drbd_device *device, struct drbd_request | |||
1152 | /* needs to be marked within the same spinlock */ | 1154 | /* needs to be marked within the same spinlock */ |
1153 | _req_mod(req, TO_BE_SUBMITTED); | 1155 | _req_mod(req, TO_BE_SUBMITTED); |
1154 | /* but we need to give up the spinlock to submit */ | 1156 | /* but we need to give up the spinlock to submit */ |
1155 | spin_unlock_irq(&device->resource->req_lock); | 1157 | submit_private_bio = true; |
1156 | drbd_submit_req_private_bio(req); | ||
1157 | spin_lock_irq(&device->resource->req_lock); | ||
1158 | } else if (no_remote) { | 1158 | } else if (no_remote) { |
1159 | nodata: | 1159 | nodata: |
1160 | if (__ratelimit(&drbd_ratelimit_state)) | 1160 | if (__ratelimit(&drbd_ratelimit_state)) |
@@ -1167,8 +1167,16 @@ nodata: | |||
1167 | out: | 1167 | out: |
1168 | if (drbd_req_put_completion_ref(req, &m, 1)) | 1168 | if (drbd_req_put_completion_ref(req, &m, 1)) |
1169 | kref_put(&req->kref, drbd_req_destroy); | 1169 | kref_put(&req->kref, drbd_req_destroy); |
1170 | spin_unlock_irq(&device->resource->req_lock); | 1170 | spin_unlock_irq(&resource->req_lock); |
1171 | 1171 | ||
1172 | /* Even though above is a kref_put(), this is safe. | ||
1173 | * As long as we still need to submit our private bio, | ||
1174 | * we hold a completion ref, and the request cannot disappear. | ||
1175 | * If however this request did not even have a private bio to submit | ||
1176 | * (e.g. remote read), req may already be invalid now. | ||
1177 | * That's why we cannot check on req->private_bio. */ | ||
1178 | if (submit_private_bio) | ||
1179 | drbd_submit_req_private_bio(req); | ||
1172 | if (m.bio) | 1180 | if (m.bio) |
1173 | complete_master_bio(device, &m); | 1181 | complete_master_bio(device, &m); |
1174 | } | 1182 | } |