wake_up(&req->w.mdev->misc_wait);
}
+static
+void req_may_be_done(struct drbd_request *req)
+{
+ const unsigned long s = req->rq_state;
+ struct drbd_conf *mdev = req->w.mdev;
+ int rw = req->rq_state & RQ_WRITE ? WRITE : READ;
+
+ /* req->master_bio still present means: Not yet completed.
+ *
+ * Unless this is RQ_POSTPONED, which will cause _req_is_done() to
+ * queue it on the retry workqueue instead of destroying it.
+ */
+ if (req->master_bio && !(s & RQ_POSTPONED))
+ return;
+
+ /* Local still pending, even though master_bio is already completed?
+ * may happen for RQ_LOCAL_ABORTED requests. */
+ if (s & RQ_LOCAL_PENDING)
+ return;
+
+ if ((s & RQ_NET_MASK) == 0 || (s & RQ_NET_DONE)) {
+ /* this is disconnected (local only) operation,
+ * or protocol A, B, or C P_BARRIER_ACK,
+ * or killed from the transfer log due to connection loss. */
+ _req_is_done(mdev, req, rw);
+ }
+ /* else: network part and not DONE yet. that is
+ * protocol A, B, or C, barrier ack still pending... */
+}
+
/* Helper for __req_mod().
* Set m->bio to the master bio, if it is fit to be completed,
* or leave it alone (it is initialized to NULL in __req_mod),
* if it has already been completed, or cannot be completed yet.
* If m->bio is set, the error status to be returned is placed in m->error.
*/
-void _req_may_be_done(struct drbd_request *req, struct bio_and_error *m)
+static
+void req_may_be_completed(struct drbd_request *req, struct bio_and_error *m)
{
const unsigned long s = req->rq_state;
struct drbd_conf *mdev = req->w.mdev;
D_ASSERT(s & RQ_NET_DONE);
}
}
-
- if (s & RQ_LOCAL_PENDING)
- return;
-
- if ((s & RQ_NET_MASK) == 0 || (s & RQ_NET_DONE)) {
- /* this is disconnected (local only) operation,
- * or protocol A, B, or C P_BARRIER_ACK,
- * or killed from the transfer log due to connection loss. */
- _req_is_done(mdev, req, rw);
- }
- /* else: network part and not DONE yet. that is
- * protocol A, B, or C, barrier ack still pending... */
+ req_may_be_done(req);
}
-static void _req_may_be_done_not_susp(struct drbd_request *req, struct bio_and_error *m)
+static void req_may_be_completed_not_susp(struct drbd_request *req, struct bio_and_error *m)
{
struct drbd_conf *mdev = req->w.mdev;
if (!drbd_suspended(mdev))
- _req_may_be_done(req, m);
+ req_may_be_completed(req, m);
}
/* obviously this could be coded as many single functions
req->rq_state &= ~RQ_LOCAL_PENDING;
maybe_wakeup_conflicting_requests(req);
- _req_may_be_done_not_susp(req, m);
+ req_may_be_completed_not_susp(req, m);
put_ldev(mdev);
break;
case ABORT_DISK_IO:
req->rq_state |= RQ_LOCAL_ABORTED;
if (req->rq_state & RQ_WRITE)
- _req_may_be_done_not_susp(req, m);
+ req_may_be_completed_not_susp(req, m);
else
goto goto_queue_for_net_read;
break;
__drbd_chk_io_error(mdev, false);
maybe_wakeup_conflicting_requests(req);
- _req_may_be_done_not_susp(req, m);
+ req_may_be_completed_not_susp(req, m);
put_ldev(mdev);
break;
/* it is legal to fail READA */
req->rq_state |= RQ_LOCAL_COMPLETED;
req->rq_state &= ~RQ_LOCAL_PENDING;
- _req_may_be_done_not_susp(req, m);
+ req_may_be_completed_not_susp(req, m);
put_ldev(mdev);
break;
/* no point in retrying if there is no good remote data,
* or we have no connection. */
if (mdev->state.pdsk != D_UP_TO_DATE) {
- _req_may_be_done_not_susp(req, m);
+ req_may_be_completed_not_susp(req, m);
break;
}
/* from __drbd_make_request
* or from bio_endio during read io-error recovery */
- /* so we can verify the handle in the answer packet
- * corresponding hlist_del is in _req_may_be_done() */
+ /* So we can verify the handle in the answer packet.
+ * Corresponding drbd_remove_request_interval is in
+ * req_may_be_completed() */
D_ASSERT(drbd_interval_empty(&req->i));
drbd_insert_interval(&mdev->read_requests, &req->i);
/* assert something? */
/* from __drbd_make_request only */
- /* corresponding hlist_del is in _req_may_be_done() */
+ /* Corresponding drbd_remove_request_interval is in
+ * req_may_be_completed() */
D_ASSERT(drbd_interval_empty(&req->i));
drbd_insert_interval(&mdev->write_requests, &req->i);
req->rq_state &= ~RQ_NET_QUEUED;
/* if we did it right, tl_clear should be scheduled only after
* this, so this should not be necessary! */
- _req_may_be_done_not_susp(req, m);
+ req_may_be_completed_not_susp(req, m);
break;
case HANDED_OVER_TO_NETWORK:
}
req->rq_state &= ~RQ_NET_QUEUED;
req->rq_state |= RQ_NET_SENT;
- _req_may_be_done_not_susp(req, m);
+ req_may_be_completed_not_susp(req, m);
break;
case OOS_HANDED_TO_NETWORK:
* as far as this connection is concerned. */
req->rq_state &= ~RQ_NET_QUEUED;
req->rq_state |= RQ_NET_DONE;
- _req_may_be_done_not_susp(req, m);
+ req_may_be_completed_not_susp(req, m);
break;
case CONNECTION_LOST_WHILE_PENDING:
if (!(req->rq_state & RQ_NET_QUEUED)) {
if (p)
goto goto_read_retry_local;
- _req_may_be_done(req, m); /* Allowed while state.susp */
+ req_may_be_completed(req, m); /* Allowed while state.susp */
}
break;
atomic_sub(req->i.size >> 9, &mdev->ap_in_flight);
req->rq_state &= ~RQ_NET_PENDING;
maybe_wakeup_conflicting_requests(req);
- _req_may_be_done_not_susp(req, m);
+ req_may_be_completed_not_susp(req, m);
break;
case POSTPONE_WRITE:
D_ASSERT(req->rq_state & RQ_NET_PENDING);
req->rq_state |= RQ_POSTPONED;
maybe_wakeup_conflicting_requests(req);
- _req_may_be_done_not_susp(req, m);
+ req_may_be_completed_not_susp(req, m);
break;
case NEG_ACKED:
goto goto_read_retry_local;
maybe_wakeup_conflicting_requests(req);
- _req_may_be_done_not_susp(req, m);
+ req_may_be_completed_not_susp(req, m);
/* else: done by HANDED_OVER_TO_NETWORK */
break;
goto_read_retry_local:
if (!drbd_may_do_local_read(mdev, req->i.sector, req->i.size)) {
- _req_may_be_done_not_susp(req, m);
+ req_may_be_completed_not_susp(req, m);
break;
}
D_ASSERT(!(req->rq_state & RQ_LOCAL_PENDING));
if (!(req->rq_state & RQ_LOCAL_COMPLETED))
break;
- _req_may_be_done(req, m); /* Allowed while state.susp */
+ req_may_be_completed(req, m); /* Allowed while state.susp */
break;
case RESTART_FROZEN_DISK_IO:
case RESEND:
/* If RQ_NET_OK is already set, we got a P_WRITE_ACK or P_RECV_ACK
before the connection loss (B&C only); only P_BARRIER_ACK was missing.
- Trowing them out of the TL here by pretending we got a BARRIER_ACK
- We ensure that the peer was not rebooted */
+ Throwing them out of the TL here by pretending we got a BARRIER_ACK.
+ During connection handshake, we ensure that the peer was not rebooted. */
if (!(req->rq_state & RQ_NET_OK)) {
if (req->w.cb) {
drbd_queue_work(&mdev->tconn->data.work, &req->w);
if (!(req->rq_state & (RQ_EXP_RECEIVE_ACK | RQ_EXP_WRITE_ACK)))
atomic_sub(req->i.size>>9, &mdev->ap_in_flight);
}
- _req_may_be_done(req, m); /* Allowed while state.susp */
+ req_may_be_done(req); /* Allowed while state.susp */
break;
case DATA_RECEIVED:
dec_ap_pending(mdev);
req->rq_state &= ~RQ_NET_PENDING;
req->rq_state |= (RQ_NET_OK|RQ_NET_DONE);
- _req_may_be_done_not_susp(req, m);
+ req_may_be_completed_not_susp(req, m);
break;
};