Module: xenomai-2.6
Branch: master
Commit: 283c5f6eae1d1d7c65073e2f30fd40abdcf2c1ca
URL:    
http://git.xenomai.org/?p=xenomai-2.6.git;a=commit;h=283c5f6eae1d1d7c65073e2f30fd40abdcf2c1ca

Author: Philippe Gerum <r...@xenomai.org>
Date:   Sun Sep  9 12:35:27 2012 +0200

rtipc/xddp: fix crash upon lingering close

XDDP is based on Xenomai's messages pipes. Cleanup operations when
closing a message pipe may be postponed by the nucleus until both rt
and nrt ends are dropped, which may happen after the RTDM socket slot
is released. Therefore, the asynchronous cleanup handler XDDP provides
must not refer to the message pipe state based on the socket's private
context, since the RTDM socket slot may have been reused in the
meantime.

Fixing this issue also requires to offload the release of the RTIPC
socket state (rtipc_private) to the protocol's .close() handler, since
the protocol implementation may want to keep this state alive until
the cleanup is eventually performed at some point in the future.

---

 ksrc/drivers/ipc/bufp.c  |    2 +
 ksrc/drivers/ipc/iddp.c  |    2 +
 ksrc/drivers/ipc/rtipc.c |   14 ++++-----
 ksrc/drivers/ipc/xddp.c  |   67 +++++++++++++++-------------------------------
 4 files changed, 32 insertions(+), 53 deletions(-)

diff --git a/ksrc/drivers/ipc/bufp.c b/ksrc/drivers/ipc/bufp.c
index bd3ca51..529b355 100644
--- a/ksrc/drivers/ipc/bufp.c
+++ b/ksrc/drivers/ipc/bufp.c
@@ -171,6 +171,8 @@ static int bufp_close(struct rtipc_private *priv,
        if (sk->bufmem)
                xnarch_free_host_mem(sk->bufmem, sk->bufsz);
 
+       kfree(sk);
+
        return 0;
 }
 
diff --git a/ksrc/drivers/ipc/iddp.c b/ksrc/drivers/ipc/iddp.c
index a0e71b4..f65cafe 100644
--- a/ksrc/drivers/ipc/iddp.c
+++ b/ksrc/drivers/ipc/iddp.c
@@ -244,6 +244,8 @@ static int iddp_close(struct rtipc_private *priv,
                xnheap_free(&kheap, mbuf);
        }
 
+       kfree(sk);
+
        return 0;
 }
 
diff --git a/ksrc/drivers/ipc/rtipc.c b/ksrc/drivers/ipc/rtipc.c
index 4546946..fae7742 100644
--- a/ksrc/drivers/ipc/rtipc.c
+++ b/ksrc/drivers/ipc/rtipc.c
@@ -166,16 +166,14 @@ static int rtipc_close(struct rtdm_dev_context *context,
                       rtdm_user_info_t *user_info)
 {
        struct rtipc_private *p;
-       int ret;
 
        p = rtdm_context_to_private(context);
-       ret = p->proto->proto_ops.close(p, user_info);
-       if (ret)
-               return ret;
-
-       kfree(p->state);
-
-       return 0;
+       /*
+        * CAUTION: p->state shall be released by the
+        * proto_ops.close() handler when appropriate (which may be
+        * done asynchronously later, see XDDP).
+        */
+       return p->proto->proto_ops.close(p, user_info);
 }
 
 static ssize_t rtipc_recvmsg(struct rtdm_dev_context *context,
diff --git a/ksrc/drivers/ipc/xddp.c b/ksrc/drivers/ipc/xddp.c
index 23f8265..1c69e9c 100644
--- a/ksrc/drivers/ipc/xddp.c
+++ b/ksrc/drivers/ipc/xddp.c
@@ -42,6 +42,7 @@ struct xddp_socket {
        size_t poolsz;
        xnhandle_t handle;
        char label[XNOBJECT_NAME_LEN];
+       int fd;                 /* i.e. RTDM socket fd */
 
        struct xddp_message *buffer;
        int buffer_port;
@@ -115,21 +116,16 @@ static void __xddp_flush_pool(xnheap_t *heap,
        xnarch_free_host_mem(poolmem, poolsz);
 }
 
-static void *__xddp_alloc_handler(size_t size, void *xstate) /* nklock free */
+static void *__xddp_alloc_handler(size_t size, void *skarg) /* nklock free */
 {
-       struct rtdm_dev_context *context = xstate;
-       struct rtipc_private *priv;
-       struct xddp_socket *sk;
+       struct xddp_socket *sk = skarg;
        void *buf;
 
-       priv = rtdm_context_to_private(context);
-       sk = priv->state;
-
        /* Try to allocate memory for the incoming message. */
        buf = xnheap_alloc(sk->bufpool, size);
        if (unlikely(buf == NULL)) {
                if (sk->monitor)
-                       sk->monitor(context->fd, XDDP_EVTNOBUF, size);
+                       sk->monitor(sk->fd, XDDP_EVTNOBUF, size);
                if (size > xnheap_max_contiguous(sk->bufpool))
                        buf = (void *)-1; /* Will never succeed. */
        }
@@ -159,15 +155,10 @@ static int __xddp_resize_streambuf(struct xddp_socket 
*sk) /* sk->lock held */
        return 0;
 }
 
-static void __xddp_free_handler(void *buf, void *xstate) /* nklock free */
+static void __xddp_free_handler(void *buf, void *skarg) /* nklock free */
 {
-       struct rtdm_dev_context *context = xstate;
-       struct rtipc_private *priv;
+       struct xddp_socket *sk = skarg;
        rtdm_lockctx_t lockctx;
-       struct xddp_socket *sk;
-
-       priv = rtdm_context_to_private(context);
-       sk = priv->state;
 
        if (buf != sk->buffer) {
                xnheap_free(sk->bufpool, buf);
@@ -193,52 +184,38 @@ static void __xddp_free_handler(void *buf, void *xstate) 
/* nklock free */
        rtdm_lock_put_irqrestore(&sk->lock, lockctx);
 }
 
-static void __xddp_output_handler(xnpipe_mh_t *mh, void *xstate) /* nklock 
held */
+static void __xddp_output_handler(xnpipe_mh_t *mh, void *skarg) /* nklock held 
*/
 {
-       struct rtdm_dev_context *context = xstate;
-       struct rtipc_private *priv;
-       struct xddp_socket *sk;
-
-       priv = rtdm_context_to_private(context);
-       sk = priv->state;
+       struct xddp_socket *sk = skarg;
 
        if (sk->monitor)
-               sk->monitor(context->fd, XDDP_EVTOUT, xnpipe_m_size(mh));
+               sk->monitor(sk->fd, XDDP_EVTOUT, xnpipe_m_size(mh));
 }
 
-static int __xddp_input_handler(xnpipe_mh_t *mh, int retval, void *xstate) /* 
nklock held */
+static int __xddp_input_handler(xnpipe_mh_t *mh, int retval, void *skarg) /* 
nklock held */
 {
-       struct rtdm_dev_context *context = xstate;
-       struct rtipc_private *priv;
-       struct xddp_socket *sk;
-
-       priv = rtdm_context_to_private(context);
-       sk = priv->state;
+       struct xddp_socket *sk = skarg;
 
        if (sk->monitor == NULL)
                return retval;
 
        if (retval == 0)
                /* Callee may alter the return value passed to userland. */
-               retval = sk->monitor(context->fd, XDDP_EVTIN,
-                                    xnpipe_m_size(mh));
+               retval = sk->monitor(sk->fd, XDDP_EVTIN, xnpipe_m_size(mh));
        else if (retval == -EPIPE && mh == NULL)
-               sk->monitor(context->fd, XDDP_EVTDOWN, 0);
+               sk->monitor(sk->fd, XDDP_EVTDOWN, 0);
 
        return retval;
 }
 
-static void __xddp_release_handler(void *xstate) /* nklock free */
+static void __xddp_release_handler(void *skarg) /* nklock free */
 {
-       struct rtdm_dev_context *context = xstate;
-       struct rtipc_private *priv;
-       struct xddp_socket *sk;
-
-       priv = rtdm_context_to_private(context);
-       sk = priv->state;
+       struct xddp_socket *sk = skarg;
 
        if (sk->bufpool == &sk->privpool)
                xnheap_destroy(&sk->privpool, __xddp_flush_pool, NULL);
+
+       kfree(sk);
 }
 
 static int xddp_socket(struct rtipc_private *priv,
@@ -743,6 +720,8 @@ static int __xddp_bind_socket(struct rtipc_private *priv,
                sk->curbufsz = sk->reqbufsz;
        }
 
+       sk->fd = rtdm_private_to_context(priv)->fd;
+
        ops.output = &__xddp_output_handler;
        ops.input = &__xddp_input_handler;
        ops.alloc_ibuf = &__xddp_alloc_handler;
@@ -750,15 +729,13 @@ static int __xddp_bind_socket(struct rtipc_private *priv,
        ops.free_obuf = &__xddp_free_handler;
        ops.release = &__xddp_release_handler;
 
-       ret = xnpipe_connect(sa->sipc_port, &ops,
-                            rtdm_private_to_context(priv));
+       ret = xnpipe_connect(sa->sipc_port, &ops, sk);
        if (ret < 0) {
                if (ret == -EBUSY)
                        ret = -EADDRINUSE;
        fail_freeheap:
                if (sk->bufpool == &sk->privpool)
-                       xnheap_destroy(&sk->privpool,
-                                      __xddp_flush_pool, NULL);
+                       xnheap_destroy(&sk->privpool, __xddp_flush_pool, NULL);
        fail:
                clear_bit(_XDDP_BINDING, &sk->status);
                return ret;
@@ -785,7 +762,7 @@ static int __xddp_bind_socket(struct rtipc_private *priv,
        }
 
        RTDM_EXECUTE_ATOMICALLY(
-               portmap[sk->minor] = rtdm_private_to_context(priv)->fd;
+               portmap[sk->minor] = sk->fd;
                __clear_bit(_XDDP_BINDING, &sk->status);
                __set_bit(_XDDP_BOUND, &sk->status);
        );


_______________________________________________
Xenomai-git mailing list
Xenomai-git@xenomai.org
http://www.xenomai.org/mailman/listinfo/xenomai-git

Reply via email to