summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr/src/uts/common/brand/lx/io/lx_netlink.c43
-rw-r--r--usr/src/uts/common/brand/lx/os/lx_audit.c2
2 files changed, 42 insertions, 3 deletions
diff --git a/usr/src/uts/common/brand/lx/io/lx_netlink.c b/usr/src/uts/common/brand/lx/io/lx_netlink.c
index 2635d1cae5..bada80ffd9 100644
--- a/usr/src/uts/common/brand/lx/io/lx_netlink.c
+++ b/usr/src/uts/common/brand/lx/io/lx_netlink.c
@@ -416,6 +416,8 @@ typedef struct lx_netlink_sock {
uint32_t lxns_groups; /* group subscriptions */
uint32_t lxns_bufsize; /* buffer size */
uint32_t lxns_flags; /* socket flags */
+ kmutex_t lxns_flowctl_mtx; /* protects lxns_flowctrled */
+ boolean_t lxns_flowctrled; /* sock is flow-controlled */
} lx_netlink_sock_t;
typedef struct lx_netlink_reply {
@@ -1812,15 +1814,40 @@ lx_netlink_au_emit_cb(void *s, uint_t type, const char *msg, uint_t size)
mp->b_wptr += LXNLMSG_ALIGN(size);
}
+ /* As in lx_netlink_reply_sendup, send as T_UNITDATA_IND message. */
if ((mp1 = lx_netlink_alloc_mp1(lxsock)) == NULL) {
freeb(mp);
return (ENOMEM);
}
- /* As in lx_netlink_reply_sendup, send as T_UNITDATA_IND message. */
mp1->b_cont = mp;
+
+ /*
+ * If the socket is currently flow-controlled, do not allow further
+ * data to be sent out. Messages of the NLMSG_DONE type, triggered by
+ * passing msg == NULL, are excempt from this restriction.
+ */
+ mutex_enter(&lxsock->lxns_flowctl_mtx);
+ if (lxsock->lxns_flowctrled && msg != NULL) {
+ mutex_exit(&lxsock->lxns_flowctl_mtx);
+ freemsg(mp1);
+ return (ENOSPC);
+ }
+
lxsock->lxns_upcalls->su_recv(lxsock->lxns_uphandle, mp1,
msgdsize(mp1), 0, &error, NULL);
+ /*
+ * The socket indicated that it is now flow-controlled. That said, it
+ * still queued the last message, so indicated success (but track the
+ * flow-controlled state).
+ */
+ if (error == ENOSPC) {
+ lxsock->lxns_flowctrled = B_TRUE;
+ lx_netlink_flowctrld++;
+ error = 0;
+ }
+ mutex_exit(&lxsock->lxns_flowctl_mtx);
+
return (error);
}
@@ -1989,6 +2016,16 @@ lx_netlink_send(sock_lower_handle_t handle, mblk_t *mp,
return (rval);
}
+static void
+lx_netlink_clr_flowctrl(sock_lower_handle_t handle)
+{
+ lx_netlink_sock_t *lxsock = (lx_netlink_sock_t *)handle;
+
+ mutex_enter(&lxsock->lxns_flowctl_mtx);
+ lxsock->lxns_flowctrled = B_FALSE;
+ mutex_exit(&lxsock->lxns_flowctl_mtx);
+}
+
/*ARGSUSED*/
static int
lx_netlink_close(sock_lower_handle_t handle, int flags, cred_t *cr)
@@ -2011,6 +2048,7 @@ lx_netlink_close(sock_lower_handle_t handle, int flags, cred_t *cr)
(void) ldi_close(lxsock->lxns_iphandle, FREAD, kcred);
(void) ldi_close(lxsock->lxns_ip6handle, FREAD, kcred);
+ mutex_destroy(&lxsock->lxns_flowctl_mtx);
kmem_free(lxsock, sizeof (lx_netlink_sock_t));
return (0);
@@ -2031,7 +2069,7 @@ static sock_downcalls_t sock_lx_netlink_downcalls = {
NULL, /* sd_recv_uio */
NULL, /* sd_poll */
sock_shutdown_notsupp, /* sd_shutdown */
- sock_clr_flowctrl_notsupp, /* sd_setflowctrl */
+ lx_netlink_clr_flowctrl, /* sd_clr_flowctrl */
sock_ioctl_notsupp, /* sd_ioctl */
lx_netlink_close /* sd_close */
};
@@ -2085,6 +2123,7 @@ lx_netlink_create(int family, int type, int proto,
lxsock->lxns_ip6handle = handle6;
lxsock->lxns_bufsize = lx_netlink_bufsize;
lxsock->lxns_proto = proto;
+ mutex_init(&lxsock->lxns_flowctl_mtx, NULL, MUTEX_DEFAULT, NULL);
mutex_enter(&lx_netlink_lock);
diff --git a/usr/src/uts/common/brand/lx/os/lx_audit.c b/usr/src/uts/common/brand/lx/os/lx_audit.c
index e87dc30883..65b8d35e41 100644
--- a/usr/src/uts/common/brand/lx/os/lx_audit.c
+++ b/usr/src/uts/common/brand/lx/os/lx_audit.c
@@ -402,7 +402,7 @@ lx_audit_worker(void *a)
err = lx_audit_emit_syscall_event(rp->lxar_type,
asp->lxast_sock, rp->lxar_msg);
- if (err != ENOMEM) {
+ if (err != ENOMEM && err != ENOSPC) {
kmem_free(rp->lxar_msg, LX_AUDIT_MESSAGE_TEXT_MAX);
kmem_free(rp, sizeof (lx_audit_record_t));
} else {