+ if (OBD_FAIL_CHECK(OBD_FAIL_MDS_SENDPAGE)) {
+ ptlrpc_abort_bulk(desc);
+ RETURN(0);
+ }
+
+ /* limit actual bulk transfer to bulk_timeout seconds */
+ deadline = start + bulk_timeout;
+ if (deadline > req->rq_deadline)
+ deadline = req->rq_deadline;
+
+ do {
+ long timeoutl = deadline - cfs_time_current_sec();
+ cfs_duration_t timeout = timeoutl <= 0 ?
+ CFS_TICK : cfs_time_seconds(timeoutl);
+ time_t rq_deadline;
+
+ *lwi = LWI_TIMEOUT_INTERVAL(timeout, cfs_time_seconds(1),
+ target_bulk_timeout, desc);
+ rc = l_wait_event(desc->bd_waitq,
+ !ptlrpc_server_bulk_active(desc) ||
+ exp->exp_failed ||
+ exp->exp_conn_cnt >
+ lustre_msg_get_conn_cnt(req->rq_reqmsg),
+ lwi);
+ LASSERT(rc == 0 || rc == -ETIMEDOUT);
+ /* Wait again if we changed rq_deadline. */
+ rq_deadline = ACCESS_ONCE(req->rq_deadline);
+ deadline = start + bulk_timeout;
+ if (deadline > rq_deadline)
+ deadline = rq_deadline;
+ } while ((rc == -ETIMEDOUT) &&
+ (deadline > cfs_time_current_sec()));
+
+ if (rc == -ETIMEDOUT) {
+ DEBUG_REQ(D_ERROR, req, "timeout on bulk %s after %ld%+lds",
+ bulk2type(desc), deadline - start,
+ cfs_time_current_sec() - deadline);
+ ptlrpc_abort_bulk(desc);
+ } else if (exp->exp_failed) {
+ DEBUG_REQ(D_ERROR, req, "Eviction on bulk %s",
+ bulk2type(desc));
+ rc = -ENOTCONN;
+ ptlrpc_abort_bulk(desc);
+ } else if (exp->exp_conn_cnt >
+ lustre_msg_get_conn_cnt(req->rq_reqmsg)) {
+ DEBUG_REQ(D_ERROR, req, "Reconnect on bulk %s",
+ bulk2type(desc));
+ /* We don't reply anyway. */
+ rc = -ETIMEDOUT;
+ ptlrpc_abort_bulk(desc);
+ } else if (desc->bd_failure ||
+ desc->bd_nob_transferred != desc->bd_nob) {
+ DEBUG_REQ(D_ERROR, req, "%s bulk %s %d(%d)",
+ desc->bd_failure ? "network error on" : "truncated",
+ bulk2type(desc), desc->bd_nob_transferred,
+ desc->bd_nob);
+ /* XXX Should this be a different errno? */
+ rc = -ETIMEDOUT;
+ } else if (desc->bd_type == BULK_GET_SINK) {
+ rc = sptlrpc_svc_unwrap_bulk(req, desc);
+ }
+
+ RETURN(rc);