]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - fs/nfs/callback.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[mv-sheeva.git] / fs / nfs / callback.c
index 93a8b3bd69e37871795b93355e0550970cf7f421..199016528fcbefa5f7a59ece47380568b0cf0f4d 100644 (file)
@@ -16,9 +16,7 @@
 #include <linux/freezer.h>
 #include <linux/kthread.h>
 #include <linux/sunrpc/svcauth_gss.h>
-#if defined(CONFIG_NFS_V4_1)
 #include <linux/sunrpc/bc_xprt.h>
-#endif
 
 #include <net/inet_sock.h>
 
@@ -136,6 +134,33 @@ out_err:
 }
 
 #if defined(CONFIG_NFS_V4_1)
+/*
+ *  * CB_SEQUENCE operations will fail until the callback sessionid is set.
+ *   */
+int nfs4_set_callback_sessionid(struct nfs_client *clp)
+{
+       struct svc_serv *serv = clp->cl_rpcclient->cl_xprt->bc_serv;
+       struct nfs4_sessionid *bc_sid;
+
+       if (!serv->sv_bc_xprt)
+               return -EINVAL;
+
+       /* on success freed in xprt_free */
+       bc_sid = kmalloc(sizeof(struct nfs4_sessionid), GFP_KERNEL);
+       if (!bc_sid)
+               return -ENOMEM;
+       memcpy(bc_sid->data, &clp->cl_session->sess_id.data,
+               NFS4_MAX_SESSIONID_LEN);
+       spin_lock_bh(&serv->sv_cb_lock);
+       serv->sv_bc_xprt->xpt_bc_sid = bc_sid;
+       spin_unlock_bh(&serv->sv_cb_lock);
+       dprintk("%s set xpt_bc_sid=%u:%u:%u:%u for sv_bc_xprt %p\n", __func__,
+               ((u32 *)bc_sid->data)[0], ((u32 *)bc_sid->data)[1],
+               ((u32 *)bc_sid->data)[2], ((u32 *)bc_sid->data)[3],
+               serv->sv_bc_xprt);
+       return 0;
+}
+
 /*
  * The callback service for NFSv4.1 callbacks
  */
@@ -177,30 +202,38 @@ nfs41_callback_svc(void *vrqstp)
 struct svc_rqst *
 nfs41_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt)
 {
-       struct svc_xprt *bc_xprt;
-       struct svc_rqst *rqstp = ERR_PTR(-ENOMEM);
+       struct svc_rqst *rqstp;
+       int ret;
 
-       dprintk("--> %s\n", __func__);
-       /* Create a svc_sock for the service */
-       bc_xprt = svc_sock_create(serv, xprt->prot);
-       if (!bc_xprt)
+       /*
+        * Create an svc_sock for the back channel service that shares the
+        * fore channel connection.
+        * Returns the input port (0) and sets the svc_serv bc_xprt on success
+        */
+       ret = svc_create_xprt(serv, "tcp-bc", &init_net, PF_INET, 0,
+                             SVC_SOCK_ANONYMOUS);
+       if (ret < 0) {
+               rqstp = ERR_PTR(ret);
                goto out;
+       }
 
        /*
         * Save the svc_serv in the transport so that it can
         * be referenced when the session backchannel is initialized
         */
-       serv->bc_xprt = bc_xprt;
        xprt->bc_serv = serv;
 
        INIT_LIST_HEAD(&serv->sv_cb_list);
        spin_lock_init(&serv->sv_cb_lock);
        init_waitqueue_head(&serv->sv_cb_waitq);
        rqstp = svc_prepare_thread(serv, &serv->sv_pools[0]);
-       if (IS_ERR(rqstp))
-               svc_sock_destroy(bc_xprt);
+       if (IS_ERR(rqstp)) {
+               svc_xprt_put(serv->sv_bc_xprt);
+               serv->sv_bc_xprt = NULL;
+       }
 out:
-       dprintk("--> %s return %p\n", __func__, rqstp);
+       dprintk("--> %s return %ld\n", __func__,
+               IS_ERR(rqstp) ? PTR_ERR(rqstp) : 0);
        return rqstp;
 }
 
@@ -233,6 +266,10 @@ static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt,
                struct nfs_callback_data *cb_info)
 {
 }
+int nfs4_set_callback_sessionid(struct nfs_client *clp)
+{
+       return 0;
+}
 #endif /* CONFIG_NFS_V4_1 */
 
 /*
@@ -328,6 +365,9 @@ static int check_gss_callback_principal(struct nfs_client *clp,
        struct rpc_clnt *r = clp->cl_rpcclient;
        char *p = svc_gss_principal(rqstp);
 
+       /* No RPC_AUTH_GSS on NFSv4.1 back channel yet */
+       if (clp->cl_minorversion != 0)
+               return SVC_DROP;
        /*
         * It might just be a normal user principal, in which case
         * userspace won't bother to tell us the name at all.
@@ -345,6 +385,23 @@ static int check_gss_callback_principal(struct nfs_client *clp,
        return SVC_OK;
 }
 
+/* pg_authenticate method helper */
+static struct nfs_client *nfs_cb_find_client(struct svc_rqst *rqstp)
+{
+       struct nfs4_sessionid *sessionid = bc_xprt_sid(rqstp);
+       int is_cb_compound = rqstp->rq_proc == CB_COMPOUND ? 1 : 0;
+
+       dprintk("--> %s rq_proc %d\n", __func__, rqstp->rq_proc);
+       if (svc_is_backchannel(rqstp))
+               /* Sessionid (usually) set after CB_NULL ping */
+               return nfs4_find_client_sessionid(svc_addr(rqstp), sessionid,
+                                                 is_cb_compound);
+       else
+               /* No callback identifier in pg_authenticate */
+               return nfs4_find_client_no_ident(svc_addr(rqstp));
+}
+
+/* pg_authenticate method for nfsv4 callback threads. */
 static int nfs_callback_authenticate(struct svc_rqst *rqstp)
 {
        struct nfs_client *clp;
@@ -352,7 +409,7 @@ static int nfs_callback_authenticate(struct svc_rqst *rqstp)
        int ret = SVC_OK;
 
        /* Don't talk to strangers */
-       clp = nfs_find_client(svc_addr(rqstp), 4);
+       clp = nfs_cb_find_client(rqstp);
        if (clp == NULL)
                return SVC_DROP;