datapath: Add NULL check for mask pointer.
[cascardo/ovs.git] / lib / netlink-socket.c
index 93757cf..670d0a9 100644 (file)
@@ -338,7 +338,7 @@ nl_sock_recv__(struct nl_sock *sock, struct ofpbuf *buf, bool wait)
         error = (retval < 0 ? errno
                  : retval == 0 ? ECONNRESET /* not possible? */
                  : nlmsghdr->nlmsg_len != UINT32_MAX ? 0
-                 : -retval);
+                 : retval);
     } while (error == EINTR);
     if (error) {
         if (error == ENOBUFS) {
@@ -702,18 +702,18 @@ nl_sock_drain(struct nl_sock *sock)
 void
 nl_dump_start(struct nl_dump *dump, int protocol, const struct ofpbuf *request)
 {
-    int status = nl_pool_alloc(protocol, &dump->sock);
-
-    if (status) {
-        return;
-    }
+    int status;
 
     nl_msg_nlmsghdr(request)->nlmsg_flags |= NLM_F_DUMP | NLM_F_ACK;
-    status = nl_sock_send__(dump->sock, request,
-                            nl_sock_allocate_seq(dump->sock, 1), true);
+    status = nl_pool_alloc(protocol, &dump->sock);
+    if (!status) {
+        status = nl_sock_send__(dump->sock, request,
+                                nl_sock_allocate_seq(dump->sock, 1), true);
+    }
     atomic_init(&dump->status, status << 1);
     dump->nl_seq = nl_msg_nlmsghdr(request)->nlmsg_seq;
     dump->status_seq = seq_create();
+    ovs_mutex_init(&dump->mutex);
 }
 
 /* Attempts to retrieve another reply from 'dump' into 'buffer'. 'dump' must
@@ -756,7 +756,15 @@ nl_dump_next(struct nl_dump *dump, struct ofpbuf *reply, struct ofpbuf *buffer)
             return false;
         }
 
+        /* Take the mutex here to avoid an in-kernel race.  If two threads try
+         * to read from a Netlink dump socket at once, then the socket error
+         * can be set to EINVAL, which will be encountered on the next recv on
+         * that socket, which could be anywhere due to the way that we pool
+         * Netlink sockets.  Serializing the recv calls avoids the issue. */
+        ovs_mutex_lock(&dump->mutex);
         retval = nl_sock_recv__(dump->sock, buffer, false);
+        ovs_mutex_unlock(&dump->mutex);
+
         if (retval) {
             ofpbuf_clear(buffer);
             if (retval == EAGAIN) {
@@ -848,6 +856,7 @@ nl_dump_done(struct nl_dump *dump)
     }
     nl_pool_release(dump->sock);
     seq_destroy(dump->status_seq);
+    ovs_mutex_destroy(&dump->mutex);
     return status >> 1;
 }