Whamcloud - gitweb
LU-14296 lnet: use an unbound cred in kiblnd_resolve_addr()
[fs/lustre-release.git] / lnet / klnds / o2iblnd / o2iblnd_cb.c
index 0424a13..6bf2b24 100644 (file)
@@ -588,6 +588,7 @@ kiblnd_fmr_map_tx(struct kib_net *net, struct kib_tx *tx,
                return -EPROTONOSUPPORT;
        }
 
+#ifdef HAVE_FMR_POOL_API
        /*
         * FMR does not support gaps but the tx has gaps then
         * we should make sure that the number of fragments we'll be sending
@@ -606,6 +607,7 @@ kiblnd_fmr_map_tx(struct kib_net *net, struct kib_tx *tx,
                        return -EFBIG;
                }
        }
+#endif
 
        fps = net->ibn_fmr_ps[cpt];
        rc = kiblnd_fmr_pool_map(fps, tx, rd, nob, 0, &tx->tx_fmr);
@@ -624,11 +626,17 @@ kiblnd_fmr_map_tx(struct kib_net *net, struct kib_tx *tx,
         * for FastReg or FMR with no gaps we can accumulate all
         * the fragments in one FastReg or FMR fragment.
         */
-       if (((dev->ibd_dev_caps & IBLND_DEV_CAPS_FMR_ENABLED) && !tx->tx_gaps) ||
+       if (
+#ifdef HAVE_FMR_POOL_API
+           ((dev->ibd_dev_caps & IBLND_DEV_CAPS_FMR_ENABLED)
+            && !tx->tx_gaps) ||
+#endif
            (dev->ibd_dev_caps & IBLND_DEV_CAPS_FASTREG_ENABLED)) {
                /* FMR requires zero based address */
+#ifdef HAVE_FMR_POOL_API
                if (dev->ibd_dev_caps & IBLND_DEV_CAPS_FMR_ENABLED)
                        rd->rd_frags[0].rf_addr &= ~hdev->ibh_page_mask;
+#endif
                rd->rd_frags[0].rf_nob = nob;
                rd->rd_nfrags = 1;
        } else {
@@ -649,7 +657,11 @@ kiblnd_fmr_map_tx(struct kib_net *net, struct kib_tx *tx,
 static void
 kiblnd_unmap_tx(struct kib_tx *tx)
 {
-       if (tx->tx_fmr.fmr_pfmr || tx->tx_fmr.fmr_frd)
+       if (
+#ifdef HAVE_FMR_POOL_API
+               tx->tx_fmr.fmr_pfmr ||
+#endif
+               tx->tx_fmr.fmr_frd)
                kiblnd_fmr_pool_unmap(&tx->tx_fmr, tx->tx_status);
 
        if (tx->tx_nfrags != 0) {
@@ -676,8 +688,11 @@ kiblnd_find_rd_dma_mr(struct lnet_ni *ni, struct kib_rdma_desc *rd)
         * dead in the water and fail the operation.
         */
        if (tunables->lnd_map_on_demand &&
-           (net->ibn_dev->ibd_dev_caps & IBLND_DEV_CAPS_FASTREG_ENABLED ||
-            net->ibn_dev->ibd_dev_caps & IBLND_DEV_CAPS_FMR_ENABLED))
+           (net->ibn_dev->ibd_dev_caps & IBLND_DEV_CAPS_FASTREG_ENABLED
+#ifdef HAVE_FMR_POOL_API
+            || net->ibn_dev->ibd_dev_caps & IBLND_DEV_CAPS_FMR_ENABLED
+#endif
+       ))
                return NULL;
 
        /*
@@ -874,16 +889,15 @@ __must_hold(&conn->ibc_lock)
         * from the first send; hence the ++ rather than = below. */
        tx->tx_sending++;
        list_add(&tx->tx_list, &conn->ibc_active_txs);
-       tx->tx_on_activeq = ktime_get();
-
-       /* I'm still holding ibc_lock! */
-       if (conn->ibc_state != IBLND_CONN_ESTABLISHED) {
-               rc = -ECONNABORTED;
-       } else if (tx->tx_pool->tpo_pool.po_failed ||
-               conn->ibc_hdev != tx->tx_pool->tpo_hdev) {
-               /* close_conn will launch failover */
-               rc = -ENETDOWN;
-       } else {
+
+        /* I'm still holding ibc_lock! */
+        if (conn->ibc_state != IBLND_CONN_ESTABLISHED) {
+                rc = -ECONNABORTED;
+        } else if (tx->tx_pool->tpo_pool.po_failed ||
+                 conn->ibc_hdev != tx->tx_pool->tpo_hdev) {
+                /* close_conn will launch failover */
+                rc = -ENETDOWN;
+        } else {
                struct kib_fast_reg_descriptor *frd = tx->tx_fmr.fmr_frd;
                struct ib_send_wr *bad = &tx->tx_wrq[tx->tx_nwrq - 1].wr;
                struct ib_send_wr *wr  = &tx->tx_wrq[0].wr;
@@ -1294,10 +1308,11 @@ kiblnd_queue_tx(struct kib_tx *tx, struct kib_conn *conn)
        spin_unlock(&conn->ibc_lock);
 }
 
-static int kiblnd_resolve_addr(struct rdma_cm_id *cmid,
-                               struct sockaddr_in *srcaddr,
-                               struct sockaddr_in *dstaddr,
-                               int timeout_ms)
+static int
+kiblnd_resolve_addr_cap(struct rdma_cm_id *cmid,
+                       struct sockaddr_in *srcaddr,
+                       struct sockaddr_in *dstaddr,
+                       int timeout_ms)
 {
         unsigned short port;
         int rc;
@@ -1327,8 +1342,36 @@ static int kiblnd_resolve_addr(struct rdma_cm_id *cmid,
                 }
         }
 
-        CERROR("Failed to bind to a free privileged port\n");
-        return rc;
+       CERROR("cannot bind to a free privileged port: rc = %d\n", rc);
+
+       return rc;
+}
+
+static int
+kiblnd_resolve_addr(struct rdma_cm_id *cmid,
+                   struct sockaddr_in *srcaddr,
+                   struct sockaddr_in *dstaddr,
+                   int timeout_ms)
+{
+       const struct cred *old_creds = NULL;
+       struct cred *new_creds;
+       int rc;
+
+       if (!capable(CAP_NET_BIND_SERVICE)) {
+               new_creds = prepare_kernel_cred(NULL);
+               if (!new_creds)
+                       return -ENOMEM;
+
+               cap_raise(new_creds->cap_effective, CAP_NET_BIND_SERVICE);
+               old_creds = override_creds(new_creds);
+       }
+
+       rc = kiblnd_resolve_addr_cap(cmid, srcaddr, dstaddr, timeout_ms);
+
+       if (old_creds)
+               revert_creds(old_creds);
+
+       return rc;
 }
 
 static void
@@ -1890,7 +1933,7 @@ kiblnd_recv(struct lnet_ni *ni, void *private, struct lnet_msg *lntmsg,
 int
 kiblnd_thread_start(int (*fn)(void *arg), void *arg, char *name)
 {
-       struct task_struct *task = kthread_run(fn, arg, name);
+       struct task_struct *task = kthread_run(fn, arg, "%s", name);
 
        if (IS_ERR(task))
                return PTR_ERR(task);
@@ -2048,15 +2091,12 @@ void
 kiblnd_abort_txs(struct kib_conn *conn, struct list_head *txs)
 {
        LIST_HEAD(zombies);
-       struct list_head        *tmp;
-       struct list_head        *nxt;
+       struct kib_tx *nxt;
        struct kib_tx *tx;
 
        spin_lock(&conn->ibc_lock);
 
-       list_for_each_safe(tmp, nxt, txs) {
-               tx = list_entry(tmp, struct kib_tx, tx_list);
-
+       list_for_each_entry_safe(tx, nxt, txs, tx_list) {
                if (txs == &conn->ibc_active_txs) {
                        LASSERT(!tx->tx_queued);
                        LASSERT(tx->tx_waiting ||
@@ -2093,6 +2133,10 @@ kiblnd_abort_txs(struct kib_conn *conn, struct list_head *txs)
                if (tx->tx_sending == 0) {
                        tx->tx_queued = 0;
                        list_move(&tx->tx_list, &zombies);
+               } else {
+                       /* keep tx until cq destroy */
+                       list_move(&tx->tx_list, &conn->ibc_zombie_txs);
+                       conn->ibc_waits ++;
                }
        }
 
@@ -2107,6 +2151,31 @@ kiblnd_abort_txs(struct kib_conn *conn, struct list_head *txs)
        kiblnd_txlist_done(&zombies, -ECONNABORTED, LNET_MSG_STATUS_OK);
 }
 
+static int
+kiblnd_tx_may_discard(struct kib_conn *conn)
+{
+       int rc = 0;
+       struct kib_tx *nxt;
+       struct kib_tx *tx;
+
+       spin_lock(&conn->ibc_lock);
+
+       list_for_each_entry_safe(tx, nxt, &conn->ibc_zombie_txs, tx_list) {
+               if (tx->tx_sending > 0 && tx->tx_lntmsg[0] &&
+                   lnet_md_discarded(tx->tx_lntmsg[0]->msg_md)) {
+                       tx->tx_sending --;
+                       if (tx->tx_sending == 0) {
+                               kiblnd_conn_decref(tx->tx_conn);
+                               tx->tx_conn = NULL;
+                               rc = 1;
+                       }
+               }
+       }
+
+       spin_unlock(&conn->ibc_lock);
+       return rc;
+}
+
 static void
 kiblnd_finalise_conn(struct kib_conn *conn)
 {
@@ -2183,8 +2252,12 @@ kiblnd_peer_connect_failed(struct kib_peer_ni *peer_ni, int active,
        CNETERR("Deleting messages for %s: connection failed\n",
                libcfs_nid2str(peer_ni->ibp_nid));
 
-       kiblnd_txlist_done(&zombies, error,
-                          LNET_MSG_STATUS_LOCAL_DROPPED);
+       if (error == -EHOSTUNREACH || error == -ETIMEDOUT)
+               kiblnd_txlist_done(&zombies, error,
+                                  LNET_MSG_STATUS_NETWORK_TIMEOUT);
+       else
+               kiblnd_txlist_done(&zombies, error,
+                                  LNET_MSG_STATUS_LOCAL_DROPPED);
 }
 
 static void
@@ -2208,22 +2281,25 @@ kiblnd_connreq_done(struct kib_conn *conn, int status)
                 (conn->ibc_state == IBLND_CONN_PASSIVE_WAIT &&
                  peer_ni->ibp_accepting > 0));
 
-        LIBCFS_FREE(conn->ibc_connvars, sizeof(*conn->ibc_connvars));
-        conn->ibc_connvars = NULL;
+       LIBCFS_FREE(conn->ibc_connvars, sizeof(*conn->ibc_connvars));
+       conn->ibc_connvars = NULL;
 
-        if (status != 0) {
-                /* failed to establish connection */
-                kiblnd_peer_connect_failed(peer_ni, active, status);
-                kiblnd_finalise_conn(conn);
-                return;
-        }
+       if (status != 0) {
+               /* failed to establish connection */
+               kiblnd_peer_connect_failed(peer_ni, active, status);
+               kiblnd_finalise_conn(conn);
+               return;
+       }
 
-        /* connection established */
+       /* connection established */
        write_lock_irqsave(&kiblnd_data.kib_global_lock, flags);
 
+       /* reset retry count */
+       peer_ni->ibp_retries = 0;
+
        conn->ibc_last_send = ktime_get();
-        kiblnd_set_conn_state(conn, IBLND_CONN_ESTABLISHED);
-        kiblnd_peer_alive(peer_ni);
+       kiblnd_set_conn_state(conn, IBLND_CONN_ESTABLISHED);
+       kiblnd_peer_alive(peer_ni);
 
        /* Add conn to peer_ni's list and nuke any dangling conns from a different
         * peer_ni instance... */
@@ -2297,7 +2373,11 @@ kiblnd_reject(struct rdma_cm_id *cmid, struct kib_rej *rej)
 {
         int          rc;
 
+#ifdef HAVE_RDMA_REJECT_4ARGS
+       rc = rdma_reject(cmid, rej, sizeof(*rej), IB_CM_REJ_CONSUMER_DEFINED);
+#else
         rc = rdma_reject(cmid, rej, sizeof(*rej));
+#endif
 
         if (rc != 0)
                 CWARN("Error %d sending reject\n", rc);
@@ -2665,10 +2745,15 @@ kiblnd_check_reconnect(struct kib_conn *conn, int version,
                goto out;
        }
 
-        switch (why) {
-        default:
-                reason = "Unknown";
-                break;
+       if (peer_ni->ibp_retries > *kiblnd_tunables.kib_retry_count) {
+               reason = "retry count exceeded due to no listener";
+               goto out;
+       }
+
+       switch (why) {
+       default:
+               reason = "Unknown";
+               break;
 
        case IBLND_REJECT_RDMA_FRAGS: {
                struct lnet_ioctl_config_o2iblnd_tunables *tunables;
@@ -2762,13 +2847,14 @@ kiblnd_rejected(struct kib_conn *conn, int reason, void *priv, int priv_nob)
                                       IBLND_REJECT_CONN_STALE, NULL);
                break;
 
-        case IB_CM_REJ_INVALID_SERVICE_ID:
+       case IB_CM_REJ_INVALID_SERVICE_ID:
+               peer_ni->ibp_retries++;
                kiblnd_check_reconnect(conn, IBLND_MSG_VERSION, 0,
                                       IBLND_REJECT_INVALID_SRV_ID, NULL);
-                CNETERR("%s rejected: no listener at %d\n",
-                        libcfs_nid2str(peer_ni->ibp_nid),
-                        *kiblnd_tunables.kib_service);
-                break;
+               CNETERR("%s rejected: no listener at %d\n",
+                       libcfs_nid2str(peer_ni->ibp_nid),
+                       *kiblnd_tunables.kib_service);
+               break;
 
         case IB_CM_REJ_CONSUMER_DEFINED:
                if (priv_nob >= offsetof(struct kib_rej, ibr_padding)) {
@@ -3228,8 +3314,6 @@ kiblnd_check_txs_locked(struct kib_conn *conn, struct list_head *txs)
 {
        struct kib_tx *tx;
        struct list_head *ttmp;
-       bool active_txs = strcmp(kiblnd_queue2str(conn, txs),
-                                "active_txs") == 0;
 
        list_for_each(ttmp, txs) {
                tx = list_entry(ttmp, struct kib_tx, tx_list);
@@ -3241,31 +3325,15 @@ kiblnd_check_txs_locked(struct kib_conn *conn, struct list_head *txs)
                        LASSERT(tx->tx_waiting || tx->tx_sending != 0);
                }
 
-               if (ktime_compare(ktime_get(), tx->tx_deadline) < 0)
-                       continue;
-
-               if (!active_txs) {
-                       CERROR("Timed out tx: %s, "
-                              "outstanding RDMA time: %lld sec\n",
+               if (ktime_compare(ktime_get(), tx->tx_deadline) >= 0) {
+                       CERROR("Timed out tx: %s(WSQ:%d%d%d), %lld seconds\n",
                               kiblnd_queue2str(conn, txs),
-                              *kiblnd_tunables.kib_timeout +
-                              (ktime_ms_delta(ktime_get(),
-                                              tx->tx_deadline) / MSEC_PER_SEC));
-               } else {
-                       CERROR("Timed out tx: %s, time in internal queue: %lld "
-                              "sec, time in active queue: %lld sec,"
-                              " outstanding RDMA time: %lld sec\n",
-                              kiblnd_queue2str(conn, txs),
-                              ktime_ms_delta(tx->tx_deadline,
-                                             tx->tx_on_activeq) / MSEC_PER_SEC,
+                              tx->tx_waiting, tx->tx_sending, tx->tx_queued,
+                              kiblnd_timeout() +
                               ktime_ms_delta(ktime_get(),
-                                             tx->tx_on_activeq) / MSEC_PER_SEC,
-                              *kiblnd_tunables.kib_timeout +
-                              (ktime_ms_delta(ktime_get(),
-                                              tx->tx_deadline) / MSEC_PER_SEC));
+                                             tx->tx_deadline) / MSEC_PER_SEC);
+                       return 1;
                }
-
-               return 1;
        }
 
        return 0;
@@ -3354,7 +3422,7 @@ kiblnd_check_conns (int idx)
 
        if (!list_empty(&timedout_txs))
                kiblnd_txlist_done(&timedout_txs, -ETIMEDOUT,
-                                  LNET_MSG_STATUS_LOCAL_TIMEOUT);
+                                  LNET_MSG_STATUS_NETWORK_TIMEOUT);
 
        /* Handle timeout by closing the whole
         * connection. We can only be sure RDMA activity
@@ -3462,6 +3530,7 @@ kiblnd_connd (void *arg)
                }
 
                if (!list_empty(&kiblnd_data.kib_connd_conns)) {
+                       int wait;
                        conn = list_entry(kiblnd_data.kib_connd_conns.next,
                                          struct kib_conn, ibc_list);
                        list_del(&conn->ibc_list);
@@ -3470,9 +3539,15 @@ kiblnd_connd (void *arg)
                        dropped_lock = 1;
 
                        kiblnd_disconnect_conn(conn);
-                       kiblnd_conn_decref(conn);
+                       wait = conn->ibc_waits;
+                       if (wait == 0) /* keep ref for connd_wait, see below */
+                               kiblnd_conn_decref(conn);
 
                        spin_lock_irqsave(lock, flags);
+
+                       if (wait)
+                               list_add_tail(&conn->ibc_list,
+                                             &kiblnd_data.kib_connd_waits);
                 }
 
                while (reconn < KIB_RECONN_BREAK) {
@@ -3500,6 +3575,22 @@ kiblnd_connd (void *arg)
                        spin_lock_irqsave(lock, flags);
                }
 
+               if (!list_empty(&kiblnd_data.kib_connd_waits)) {
+                       conn = list_entry(kiblnd_data.kib_connd_waits.next,
+                                         struct kib_conn, ibc_list);
+                       list_del(&conn->ibc_list);
+                       spin_unlock_irqrestore(lock, flags);
+
+                       dropped_lock = kiblnd_tx_may_discard(conn);
+                       if (dropped_lock)
+                               kiblnd_conn_decref(conn);
+
+                       spin_lock_irqsave(lock, flags);
+                       if (dropped_lock == 0)
+                               list_add_tail(&conn->ibc_list,
+                                             &kiblnd_data.kib_connd_waits);
+               }
+
                 /* careful with the jiffy wrap... */
                 timeout = (int)(deadline - jiffies);
                 if (timeout <= 0) {
@@ -3676,7 +3767,6 @@ kiblnd_scheduler(void *arg)
        unsigned long           flags;
        struct ib_wc            wc;
        int                     did_something;
-       int                     busy_loops = 0;
        int                     rc;
 
        init_waitqueue_entry(&wait, current);
@@ -3694,11 +3784,10 @@ kiblnd_scheduler(void *arg)
        spin_lock_irqsave(&sched->ibs_lock, flags);
 
        while (!kiblnd_data.kib_shutdown) {
-               if (busy_loops++ >= IBLND_RESCHED) {
+               if (need_resched()) {
                        spin_unlock_irqrestore(&sched->ibs_lock, flags);
 
                        cond_resched();
-                       busy_loops = 0;
 
                        spin_lock_irqsave(&sched->ibs_lock, flags);
                }
@@ -3794,7 +3883,6 @@ kiblnd_scheduler(void *arg)
                spin_unlock_irqrestore(&sched->ibs_lock, flags);
 
                schedule();
-               busy_loops = 0;
 
                remove_wait_queue(&sched->ibs_waitq, &wait);
                set_current_state(TASK_RUNNING);