datapath: Change ODP_PORT_LIST semantics.
authorBen Pfaff <blp@nicira.com>
Wed, 17 Jun 2009 21:28:07 +0000 (14:28 -0700)
committerBen Pfaff <blp@nicira.com>
Mon, 6 Jul 2009 16:07:24 +0000 (09:07 -0700)
Until now, ODP_PORT_LIST has reported the number of ports actually copied
out.  It's better for the caller, however, if it reports the number of
ports that were available to be copied out.

datapath/datapath.c
lib/dpif.c

index e545cda0518a0aaae3b46bd3f8bc766a79da296c..14779a60ff41bbc24d0ee5072f74cc8dfcdd20d9 100644 (file)
@@ -1260,7 +1260,7 @@ list_ports(struct datapath *dp, struct odp_portvec __user *pvp)
                                break;
                }
        }
-       return put_user(idx, &pvp->n_ports);
+       return put_user(dp->n_ports, &pvp->n_ports);
 }
 
 /* RCU callback for freeing a dp_port_group */
index e0e5f36425529163626066ea44ae90964e22d65a..85d05bb714ce61df9078aa8654f71a183c02dab7 100644 (file)
@@ -337,33 +337,48 @@ dpif_port_get_name(struct dpif *dpif, uint16_t port_no,
 
 int
 dpif_port_list(const struct dpif *dpif,
-               struct odp_port **ports, size_t *n_ports)
+               struct odp_port **portsp, size_t *n_portsp)
 {
-    struct odp_portvec pv;
-    struct odp_stats stats;
+    struct odp_port *ports;
+    size_t n_ports;
     int error;
 
-    do {
+    for (;;) {
+        struct odp_stats stats;
+        struct odp_portvec pv;
+
         error = dpif_get_dp_stats(dpif, &stats);
         if (error) {
-            goto error;
+            goto exit;
         }
 
-        *ports = xcalloc(1, stats.n_ports * sizeof **ports);
-        pv.ports = *ports;
+        ports = xcalloc(stats.n_ports, sizeof *ports);
+        pv.ports = ports;
         pv.n_ports = stats.n_ports;
         error = do_ioctl(dpif, ODP_PORT_LIST, "ODP_PORT_LIST", &pv);
         if (error) {
-            free(*ports);
-            goto error;
+            /* Hard error. */
+            free(ports);
+            goto exit;
+        } else if (pv.n_ports <= stats.n_ports) {
+            /* Success. */
+            error = 0;
+            n_ports = pv.n_ports;
+            goto exit;
+        } else {
+            /* Soft error: port count increased behind our back.  Try again. */
+            free(ports);
         }
-    } while (pv.n_ports != stats.n_ports);
-    *n_ports = pv.n_ports;
-    return 0;
+    }
 
-error:
-    *ports = NULL;
-    *n_ports = 0;
+exit:
+    if (error) {
+        *portsp = NULL;
+        *n_portsp = 0;
+    } else {
+        *portsp = ports;
+        *n_portsp = n_ports;
+    }
     return error;
 }