Page MenuHomeFreeBSD

D48569.diff
No OneTemporary

D48569.diff

diff --git a/include/rpc/svc.h b/include/rpc/svc.h
--- a/include/rpc/svc.h
+++ b/include/rpc/svc.h
@@ -461,6 +461,13 @@
*/
extern SVCXPRT *svc_nl_create(const char *);
+/*
+ * Arguments to SVC_CONTROL(svc_nl)
+ */
+enum {
+ SVCNL_GET_XIDKEY = 1, /* obtain pthread specific key for xid */
+};
+
/*
* Memory based rpc (for speed check and testing)
*/
diff --git a/lib/libc/rpc/svc_nl.c b/lib/libc/rpc/svc_nl.c
--- a/lib/libc/rpc/svc_nl.c
+++ b/lib/libc/rpc/svc_nl.c
@@ -28,6 +28,7 @@
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
+#include <pthread.h>
#include <rpc/rpc.h>
#include <rpc/clnt_nl.h>
@@ -37,6 +38,7 @@
#include <netlink/netlink_snl_generic.h>
#include "rpc_com.h"
+#include "libc_private.h"
/*
* RPC server to serve a kernel RPC client(s) over netlink(4). See clnt_nl.c
@@ -54,6 +56,7 @@
static enum xprt_stat svc_nl_stat(SVCXPRT *);
static bool_t svc_nl_getargs(SVCXPRT *, xdrproc_t, void *);
static bool_t svc_nl_freeargs(SVCXPRT *, xdrproc_t, void *);
+static bool_t svc_nl_control(SVCXPRT *, const u_int, void *);
static struct xp_ops nl_ops = {
.xp_recv = svc_nl_recv,
@@ -63,11 +66,15 @@
.xp_freeargs = svc_nl_freeargs,
.xp_destroy = svc_nl_destroy,
};
+static struct xp_ops2 nl_ops2 = {
+ .xp_control = svc_nl_control,
+};
struct nl_softc {
struct snl_state snl;
XDR xdrs;
struct nlmsghdr *hdr;
+ pthread_key_t xidkey;
size_t mlen;
enum xprt_stat stat;
uint32_t xid;
@@ -108,9 +115,15 @@
sc->stat = XPRT_IDLE,
sc->family = family;
+ if (__isthreaded &&
+ (pthread_key_create(&sc->xidkey, NULL) != 0 ||
+ pthread_setspecific(sc->xidkey, &sc->xid) != 0))
+ goto fail;
+
xprt->xp_fd = sc->snl.fd,
xprt->xp_p1 = sc,
xprt->xp_ops = &nl_ops,
+ xprt->xp_ops2 = &nl_ops2,
xprt->xp_rtaddr = (struct netbuf){
.maxlen = sizeof(struct sockaddr_nl),
.len = sizeof(struct sockaddr_nl),
@@ -208,26 +221,62 @@
return (FALSE);
}
+/*
+ * Reenterable reply method. Note that both the softc and xprt are declared
+ * const. The qualifier for xprt is commented out to match the library
+ * prototype. If doing any substantial changes to the function please
+ * temporarily uncomment the const for xprt and check your changes.
+ *
+ * Applications that want to use svc_nl_reply in a spawned thread context
+ * should do the following hacks in self:
+ * 1) - Create xprt with svc_nl_create() with libc in threaded mode, e.g.
+ * at least one pthread_create() shall happen before svc_nl_create().
+ * - After xprt creation query it for the pthread_key_t with the
+ * SVCNL_GET_XIDKEY control and save this key.
+ * 2) In the RPC function body that wants to become multithreaded:
+ * - Make a copy of the arguments and of the xid with help of
+ * pthread_getspecific() using the key.
+ * - pthread_create() the worker function, pointing it at the copy of
+ * arguments and xid.
+ * - return FALSE, so that RPC generated code doesn't do anything.
+ * 3) In the spawned thread:
+ * - Use arguments provided in the copy by the parent.
+ * - Allocate appropriately typed result on stack.
+ * - *** do the actual work ***
+ * - Populate the on-stack result same way as pointed result is populated
+ * in a regular RPC function.
+ * - Point the thread specific storage to the copy of xid provided by the
+ * parent with help of pthread_setspecific().
+ * - Call svc_sendreply() just like the rpcgen(1) generated code does.
+ *
+ * If all done correctly svc_nl_reply() will use thread specific xid for
+ * a call that was processed asynchronously and most recent xid when entered
+ * synchronously. So you can make only some methods of your application
+ * reentrable, keeping others as is.
+ */
+
static bool_t
-svc_nl_reply(SVCXPRT *xprt, struct rpc_msg *msg)
+svc_nl_reply(/* const */ SVCXPRT *xprt, struct rpc_msg *msg)
{
- struct nl_softc *sc = xprt->xp_p1;
+ const struct nl_softc *sc = xprt->xp_p1;
struct snl_state snl;
struct snl_writer nw;
+ XDR xdrs;
struct nlattr *body;
bool_t rv;
- msg->rm_xid = sc->xid;
+ msg->rm_xid = __isthreaded ?
+ *(uint32_t *)pthread_getspecific(sc->xidkey) :
+ sc->xid;
if (__predict_false(!snl_clone(&snl, &sc->snl)))
return (FALSE);
- snl_init_writer(&sc->snl, &nw);
+ snl_init_writer(&snl, &nw);
snl_create_genl_msg_request(&nw, sc->family, RPCNL_REPLY);
snl_add_msg_attr_u32(&nw, RPCNL_REPLY_GROUP, sc->group);
body = snl_reserve_msg_attr_raw(&nw, RPCNL_REPLY_BODY, RPC_MAXDATASIZE);
- xdrmem_create(&sc->xdrs, (char *)(body + 1), RPC_MAXDATASIZE,
- XDR_ENCODE);
+ xdrmem_create(&xdrs, (char *)(body + 1), RPC_MAXDATASIZE, XDR_ENCODE);
if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
@@ -240,28 +289,28 @@
msg->acpted_rply.ar_results.proc = (xdrproc_t) xdr_void;
msg->acpted_rply.ar_results.where = NULL;
- pos = xdr_getpos(&sc->xdrs);
- if (!xdr_replymsg(&sc->xdrs, msg) ||
- !SVCAUTH_WRAP(&SVC_AUTH(xprt), &sc->xdrs, xdr_proc,
+ pos = xdr_getpos(&xdrs);
+ if (!xdr_replymsg(&xdrs, msg) ||
+ !SVCAUTH_WRAP(&SVC_AUTH(xprt), &xdrs, xdr_proc,
xdr_where)) {
- xdr_setpos(&sc->xdrs, pos);
+ xdr_setpos(&xdrs, pos);
rv = FALSE;
} else
rv = TRUE;
} else
- rv = xdr_replymsg(&sc->xdrs, msg);
+ rv = xdr_replymsg(&xdrs, msg);
if (rv) {
/* snl_finalize_msg() really doesn't work for us */
- body->nla_len = sizeof(struct nlattr) + xdr_getpos(&sc->xdrs);
+ body->nla_len = sizeof(struct nlattr) + xdr_getpos(&xdrs);
nw.hdr->nlmsg_len = ((char *)body - (char *)nw.hdr) +
body->nla_len;
nw.hdr->nlmsg_type = sc->family;
nw.hdr->nlmsg_flags = NLM_F_REQUEST;
- nw.hdr->nlmsg_seq = sc->xid;
+ nw.hdr->nlmsg_seq = msg->rm_xid;
if (write(xprt->xp_fd, nw.hdr, nw.hdr->nlmsg_len) !=
nw.hdr->nlmsg_len)
- DIE(sc);
+ DIE(__DECONST(struct nl_softc *, sc));
}
snl_free(&snl);
@@ -269,6 +318,29 @@
return (rv);
}
+static bool_t
+svc_nl_control(SVCXPRT *xprt, const u_int req, void *v)
+{
+ struct nl_softc *sc = xprt->xp_p1;
+
+ switch (req) {
+ case SVCNL_GET_XIDKEY:
+ if (!__isthreaded) {
+ /*
+ * Report to application that it had created xprt not
+ * in threaded mode, but definitly plans to use it with
+ * threads. If it tries so, it would very likely crash.
+ */
+ errno = EDOOFUS;
+ DIE(sc);
+ };
+ *(pthread_key_t *)v = sc->xidkey;
+ return (TRUE);
+ default:
+ return (FALSE);
+ }
+}
+
static enum xprt_stat
svc_nl_stat(SVCXPRT *xprt)
{

File Metadata

Mime Type
text/plain
Expires
Mon, Feb 3, 9:07 PM (21 h, 18 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16406004
Default Alt Text
D48569.diff (6 KB)

Event Timeline