Whamcloud - gitweb
LU-9679 lnet: tidy lnet_discover and fix mem accounting bug. 44/38644/3
authorMr NeilBrown <neilb@suse.de>
Sun, 17 May 2020 23:21:27 +0000 (09:21 +1000)
committerOleg Drokin <green@whamcloud.com>
Wed, 27 May 2020 05:04:08 +0000 (05:04 +0000)
A recent patch introduce a memory accounting bug because "n_ids"
can change between the ALLOC call and the FREE call.

With this patch we fix that by ensuring n_ids doesn't change - the
current change is not needed.
Also:
 - discard 'max_intf' var.  It is always exactly lnet_interfaces_max,
   so just use that directly.
 - only copy back the number of interfaces found
 - report the number of interfaces actually copied.
 - Move the copy_to_user until after all locks and references are
   dropped so there is no need to re-take any locks.

Test-Parameters: trivial
Fixes: b1f6f3becedc ("LU-9679 libcfs: Add CFS_ALLOC_PTR_ARRAY and free")
Signed-off-by: Mr NeilBrown <neilb@suse.de>
Change-Id: Ib807ca4ce5235b28e7ae11d90e1942aff4454cfc
Reviewed-on: https://review.whamcloud.com/38644
Tested-by: jenkins <devops@whamcloud.com>
Reviewed-by: Shaun Tancheff <shaun.tancheff@hpe.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Chris Horn <chris.horn@hpe.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
lnet/lnet/api-ni.c

index 41b14f2..05c0cb3 100644 (file)
@@ -4257,7 +4257,6 @@ lnet_discover(struct lnet_process_id id, __u32 force,
        int cpt;
        int i;
        int rc;
        int cpt;
        int i;
        int rc;
-       int max_intf = lnet_interfaces_max;
 
        if (n_ids <= 0 ||
            id.nid == LNET_NID_ANY)
 
        if (n_ids <= 0 ||
            id.nid == LNET_NID_ANY)
@@ -4267,11 +4266,11 @@ lnet_discover(struct lnet_process_id id, __u32 force,
                id.pid = LNET_PID_LUSTRE;
 
        /*
                id.pid = LNET_PID_LUSTRE;
 
        /*
-        * if the user buffer has more space than the max_intf
-        * then only fill it up to max_intf
+        * If the user buffer has more space than the lnet_interfaces_max,
+        * then only fill it up to lnet_interfaces_max.
         */
         */
-       if (n_ids > max_intf)
-               n_ids = max_intf;
+       if (n_ids > lnet_interfaces_max)
+               n_ids = lnet_interfaces_max;
 
        CFS_ALLOC_PTR_ARRAY(buf, n_ids);
        if (!buf)
 
        CFS_ALLOC_PTR_ARRAY(buf, n_ids);
        if (!buf)
@@ -4299,11 +4298,6 @@ lnet_discover(struct lnet_process_id id, __u32 force,
        if (rc)
                goto out_decref;
 
        if (rc)
                goto out_decref;
 
-       /* Peer may have changed. */
-       lp = lpni->lpni_peer_net->lpn_peer;
-       if (lp->lp_nnis < n_ids)
-               n_ids = lp->lp_nnis;
-
        i = 0;
        p = NULL;
        while ((p = lnet_get_next_peer_ni_locked(lp, NULL, p)) != NULL) {
        i = 0;
        p = NULL;
        while ((p = lnet_get_next_peer_ni_locked(lp, NULL, p)) != NULL) {
@@ -4312,20 +4306,16 @@ lnet_discover(struct lnet_process_id id, __u32 force,
                if (++i >= n_ids)
                        break;
        }
                if (++i >= n_ids)
                        break;
        }
+       rc = i;
 
 
-       lnet_net_unlock(cpt);
-
-       rc = -EFAULT;
-       if (copy_to_user(ids, buf, n_ids * sizeof(*buf)))
-               goto out_relock;
-       rc = n_ids;
-out_relock:
-       lnet_net_lock(cpt);
 out_decref:
        lnet_peer_ni_decref_locked(lpni);
 out:
        lnet_net_unlock(cpt);
 
 out_decref:
        lnet_peer_ni_decref_locked(lpni);
 out:
        lnet_net_unlock(cpt);
 
+       if (rc >= 0)
+               if (copy_to_user(ids, buf, rc * sizeof(*buf)))
+                       rc = -EFAULT;
        CFS_FREE_PTR_ARRAY(buf, n_ids);
 
        return rc;
        CFS_FREE_PTR_ARRAY(buf, n_ids);
 
        return rc;