Whamcloud - gitweb
LU-11128 ptlrpc: new request vs disconnect race
[fs/lustre-release.git] / lustre / ptlrpc / client.c
index a3e7ffa..a167146 100644 (file)
@@ -23,7 +23,7 @@
  * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
  * Use is subject to license terms.
  *
- * Copyright (c) 2011, 2016, Intel Corporation.
+ * Copyright (c) 2011, 2017, Intel Corporation.
  */
 /*
  * This file is part of Lustre, http://www.lustre.org/
@@ -34,6 +34,7 @@
 
 #define DEBUG_SUBSYSTEM S_RPC
 
+#include <linux/delay.h>
 #include <obd_support.h>
 #include <obd_class.h>
 #include <lustre_lib.h>
@@ -864,10 +865,37 @@ ptlrpc_request_alloc_internal(struct obd_import *imp,
                               const struct req_format *format)
 {
         struct ptlrpc_request *request;
+       int connect = 0;
 
-        request = __ptlrpc_request_alloc(imp, pool);
-        if (request == NULL)
-                return NULL;
+       request = __ptlrpc_request_alloc(imp, pool);
+       if (request == NULL)
+               return NULL;
+
+       /* initiate connection if needed when the import has been
+        * referenced by the new request to avoid races with disconnect */
+       if (unlikely(imp->imp_state == LUSTRE_IMP_IDLE)) {
+               int rc;
+               CDEBUG_LIMIT(imp->imp_idle_debug,
+                            "%s: reconnect after %llds idle\n",
+                            imp->imp_obd->obd_name, ktime_get_real_seconds() -
+                                                    imp->imp_last_reply_time);
+               spin_lock(&imp->imp_lock);
+               if (imp->imp_state == LUSTRE_IMP_IDLE) {
+                       imp->imp_generation++;
+                       imp->imp_initiated_at = imp->imp_generation;
+                       imp->imp_state =  LUSTRE_IMP_NEW;
+                       connect = 1;
+               }
+               spin_unlock(&imp->imp_lock);
+               if (connect) {
+                       rc = ptlrpc_connect_import(imp);
+                       if (rc < 0) {
+                               ptlrpc_request_free(request);
+                               return NULL;
+                       }
+                       ptlrpc_pinger_add_import(imp);
+               }
+       }
 
         req_capsule_init(&request->rq_pill, request, RCL_CLIENT);
         req_capsule_set(&request->rq_pill, format);
@@ -956,7 +984,6 @@ struct ptlrpc_request_set *ptlrpc_prep_set(void)
        atomic_set(&set->set_remaining, 0);
        spin_lock_init(&set->set_new_req_lock);
        INIT_LIST_HEAD(&set->set_new_requests);
-       INIT_LIST_HEAD(&set->set_cblist);
        set->set_max_inflight = UINT_MAX;
        set->set_producer     = NULL;
        set->set_producer_arg = NULL;
@@ -1052,33 +1079,13 @@ void ptlrpc_set_destroy(struct ptlrpc_request_set *set)
 EXPORT_SYMBOL(ptlrpc_set_destroy);
 
 /**
- * Add a callback function \a fn to the set.
- * This function would be called when all requests on this set are completed.
- * The function will be passed \a data argument.
- */
-int ptlrpc_set_add_cb(struct ptlrpc_request_set *set,
-                      set_interpreter_func fn, void *data)
-{
-       struct ptlrpc_set_cbdata *cbdata;
-
-       OBD_ALLOC_PTR(cbdata);
-       if (cbdata == NULL)
-               RETURN(-ENOMEM);
-
-       cbdata->psc_interpret = fn;
-       cbdata->psc_data = data;
-       list_add_tail(&cbdata->psc_item, &set->set_cblist);
-
-       RETURN(0);
-}
-
-/**
  * Add a new request to the general purpose request set.
  * Assumes request reference from the caller.
  */
 void ptlrpc_set_add_req(struct ptlrpc_request_set *set,
                         struct ptlrpc_request *req)
 {
+       LASSERT(req->rq_import->imp_state != LUSTRE_IMP_IDLE);
        LASSERT(list_empty(&req->rq_set_chain));
 
        if (req->rq_allow_intr)
@@ -1190,7 +1197,9 @@ static int ptlrpc_import_delay_req(struct obd_import *imp,
                if (atomic_read(&imp->imp_inval_count) != 0) {
                         DEBUG_REQ(D_ERROR, req, "invalidate in flight");
                         *status = -EIO;
-               } else if (req->rq_no_delay) {
+               } else if (req->rq_no_delay &&
+                          imp->imp_generation != imp->imp_initiated_at) {
+                       /* ignore nodelay for requests initiating connections */
                         *status = -EWOULDBLOCK;
                } else if (req->rq_allow_replay &&
                          (imp->imp_state == LUSTRE_IMP_REPLAY ||
@@ -1619,8 +1628,7 @@ static int ptlrpc_send_new_req(struct ptlrpc_request *req)
               " %s:%s:%d:%llu:%s:%d\n", current_comm(),
               imp->imp_obd->obd_uuid.uuid,
               lustre_msg_get_status(req->rq_reqmsg), req->rq_xid,
-              libcfs_nid2str(imp->imp_connection->c_peer.nid),
-              lustre_msg_get_opc(req->rq_reqmsg));
+              obd_import_nid2str(imp), lustre_msg_get_opc(req->rq_reqmsg));
 
         rc = ptl_send_rpc(req, 0);
        if (rc == -ENOMEM) {
@@ -1874,8 +1882,11 @@ int ptlrpc_check_set(const struct lu_env *env, struct ptlrpc_request_set *set)
                                        spin_unlock(&imp->imp_lock);
                                        GOTO(interpret, req->rq_status);
                                }
+                               /* ignore on just initiated connections */
                                if (ptlrpc_no_resend(req) &&
-                                   !req->rq_wait_ctx) {
+                                   !req->rq_wait_ctx &&
+                                   imp->imp_generation !=
+                                   imp->imp_initiated_at) {
                                        req->rq_status = -ENOTCONN;
                                        ptlrpc_rqphase_move(req,
                                                            RQ_PHASE_INTERPRET);
@@ -2044,7 +2055,7 @@ int ptlrpc_check_set(const struct lu_env *env, struct ptlrpc_request_set *set)
                               imp->imp_obd->obd_uuid.uuid,
                               lustre_msg_get_status(req->rq_reqmsg),
                               req->rq_xid,
-                              libcfs_nid2str(imp->imp_connection->c_peer.nid),
+                              obd_import_nid2str(imp),
                               lustre_msg_get_opc(req->rq_reqmsg));
 
                spin_lock(&imp->imp_lock);
@@ -2339,7 +2350,7 @@ int ptlrpc_set_wait(struct ptlrpc_request_set *set)
                 /* wait until all complete, interrupted, or an in-flight
                  * req times out */
                CDEBUG(D_RPCTRACE, "set %p going to sleep for %lld seconds\n",
-                       set, timeout);
+                       set, timeout);
 
                if ((timeout == 0 && !signal_pending(current)) ||
                    set->set_allow_intr)
@@ -2411,25 +2422,7 @@ int ptlrpc_set_wait(struct ptlrpc_request_set *set)
                         rc = req->rq_status;
         }
 
-        if (set->set_interpret != NULL) {
-                int (*interpreter)(struct ptlrpc_request_set *set,void *,int) =
-                        set->set_interpret;
-                rc = interpreter (set, set->set_arg, rc);
-        } else {
-                struct ptlrpc_set_cbdata *cbdata, *n;
-                int err;
-
-               list_for_each_entry_safe(cbdata, n,
-                                         &set->set_cblist, psc_item) {
-                       list_del_init(&cbdata->psc_item);
-                        err = cbdata->psc_interpret(set, cbdata->psc_data, rc);
-                        if (err && !rc)
-                                rc = err;
-                        OBD_FREE_PTR(cbdata);
-                }
-        }
-
-        RETURN(rc);
+       RETURN(rc);
 }
 EXPORT_SYMBOL(ptlrpc_set_wait);
 
@@ -2685,8 +2678,11 @@ void ptlrpc_request_committed(struct ptlrpc_request *req, int force)
                return;
        }
 
-       if (force || req->rq_transno <= imp->imp_peer_committed_transno)
+       if (force || req->rq_transno <= imp->imp_peer_committed_transno) {
+               if (imp->imp_replay_cursor == &req->rq_replay_list)
+                       imp->imp_replay_cursor = req->rq_replay_list.next;
                ptlrpc_free_request(req);
+       }
 
        spin_unlock(&imp->imp_lock);
 }
@@ -2798,7 +2794,7 @@ void ptlrpc_cleanup_client(struct obd_import *imp)
  */
 void ptlrpc_resend_req(struct ptlrpc_request *req)
 {
-        DEBUG_REQ(D_HA, req, "going to resend");
+       DEBUG_REQ(D_HA, req, "going to resend");
        spin_lock(&req->rq_lock);
 
        /* Request got reply but linked to the import list still.
@@ -2809,14 +2805,13 @@ void ptlrpc_resend_req(struct ptlrpc_request *req)
                return;
        }
 
-        lustre_msg_set_handle(req->rq_reqmsg, &(struct lustre_handle){ 0 });
-        req->rq_status = -EAGAIN;
+       req->rq_status = -EAGAIN;
 
-        req->rq_resend = 1;
-        req->rq_net_err = 0;
-        req->rq_timedout = 0;
+       req->rq_resend = 1;
+       req->rq_net_err = 0;
+       req->rq_timedout = 0;
 
-        ptlrpc_client_wake_req(req);
+       ptlrpc_client_wake_req(req);
        spin_unlock(&req->rq_lock);
 }