]> Pileus Git - ~andy/linux/commitdiff
Merge commit 'linux-pnfs/nfs41-for-2.6.31' into nfsv41-for-2.6.31
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Thu, 18 Jun 2009 00:59:58 +0000 (17:59 -0700)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Thu, 18 Jun 2009 00:59:58 +0000 (17:59 -0700)
1  2 
fs/nfs/super.c
net/sunrpc/svc.c
net/sunrpc/xprtsock.c

diff --combined fs/nfs/super.c
index 26127b69a2755c66e3713a119259051f018745bc,69804a8245f68836d829c2eb4ab32ab3a17956ac..6063054455f8587785cc3e65c31b1c68420f73e8
@@@ -90,6 -90,7 +90,7 @@@ enum 
        Opt_mountport,
        Opt_mountvers,
        Opt_nfsvers,
+       Opt_minorversion,
  
        /* Mount options that take string arguments */
        Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost,
@@@ -155,6 -156,7 +156,7 @@@ static const match_table_t nfs_mount_op
        { Opt_mountvers, "mountvers=%u" },
        { Opt_nfsvers, "nfsvers=%u" },
        { Opt_nfsvers, "vers=%u" },
+       { Opt_minorversion, "minorversion=%u" },
  
        { Opt_sec, "sec=%s" },
        { Opt_proto, "proto=%s" },
@@@ -1211,6 -1213,13 +1213,13 @@@ static int nfs_parse_mount_options(cha
                                nfs_parse_invalid_value("nfsvers");
                        }
                        break;
+               case Opt_minorversion:
+                       if (match_int(args, &option))
+                               return 0;
+                       if (option < 0 || option > NFS4_MAX_MINOR_VERSION)
+                               return 0;
+                       mnt->minorversion = option;
+                       break;
  
                /*
                 * options that take text values
@@@ -1813,7 -1822,6 +1822,7 @@@ nfs_remount(struct super_block *sb, in
        if (data == NULL)
                return -ENOMEM;
  
 +      lock_kernel();
        /* fill out struct with values from existing mount */
        data->flags = nfss->flags;
        data->rsize = nfss->rsize;
        error = nfs_compare_remount_data(nfss, data);
  out:
        kfree(data);
 +      unlock_kernel();
        return error;
  }
  
@@@ -2263,6 -2270,7 +2272,7 @@@ static int nfs4_validate_mount_data(voi
        args->nfs_server.port   = NFS_PORT; /* 2049 unless user set port= */
        args->auth_flavors[0]   = RPC_AUTH_UNIX;
        args->auth_flavor_len   = 0;
+       args->minorversion      = 0;
  
        switch (data->version) {
        case 1:
@@@ -2477,12 -2485,13 +2487,13 @@@ static void nfs4_kill_super(struct supe
  {
        struct nfs_server *server = NFS_SB(sb);
  
+       dprintk("--> %s\n", __func__);
        nfs_super_return_all_delegations(sb);
        kill_anon_super(sb);
        nfs4_renewd_prepare_shutdown(server);
        nfs_fscache_release_super_cookie(sb);
        nfs_free_server(server);
+       dprintk("<-- %s\n", __func__);
  }
  
  /*
diff --combined net/sunrpc/svc.c
index 5ed8931dfe98f8af810a28a046f9c6729f07e6a3,6b90ce439c0081c8a191e05830f17d3669ae897a..952f206ff307a42b8a7bb20066dcf6ed5e3ab2c9
@@@ -25,6 -25,7 +25,7 @@@
  #include <linux/sunrpc/stats.h>
  #include <linux/sunrpc/svcsock.h>
  #include <linux/sunrpc/clnt.h>
+ #include <linux/sunrpc/bc_xprt.h>
  
  #define RPCDBG_FACILITY       RPCDBG_SVCDSP
  
@@@ -124,7 -125,7 +125,7 @@@ svc_pool_map_choose_mode(void
  {
        unsigned int node;
  
 -      if (num_online_nodes() > 1) {
 +      if (nr_online_nodes > 1) {
                /*
                 * Actually have multiple NUMA nodes,
                 * so split pools on NUMA node boundaries
@@@ -486,6 -487,10 +487,10 @@@ svc_destroy(struct svc_serv *serv
        if (svc_serv_is_pooled(serv))
                svc_pool_map_put();
  
+ #if defined(CONFIG_NFS_V4_1)
+       svc_sock_destroy(serv->bc_xprt);
+ #endif /* CONFIG_NFS_V4_1 */
        svc_unregister(serv);
        kfree(serv->sv_pools);
        kfree(serv);
@@@ -970,20 -975,18 +975,18 @@@ svc_printk(struct svc_rqst *rqstp, cons
  }
  
  /*
-  * Process the RPC request.
+  * Common routine for processing the RPC request.
   */
- int
- svc_process(struct svc_rqst *rqstp)
static int
+ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
  {
        struct svc_program      *progp;
        struct svc_version      *versp = NULL;  /* compiler food */
        struct svc_procedure    *procp = NULL;
-       struct kvec *           argv = &rqstp->rq_arg.head[0];
-       struct kvec *           resv = &rqstp->rq_res.head[0];
        struct svc_serv         *serv = rqstp->rq_server;
        kxdrproc_t              xdr;
        __be32                  *statp;
-       u32                     dir, prog, vers, proc;
+       u32                     prog, vers, proc;
        __be32                  auth_stat, rpc_stat;
        int                     auth_res;
        __be32                  *reply_statp;
        if (argv->iov_len < 6*4)
                goto err_short_len;
  
-       /* setup response xdr_buf.
-        * Initially it has just one page
-        */
-       rqstp->rq_resused = 1;
-       resv->iov_base = page_address(rqstp->rq_respages[0]);
-       resv->iov_len = 0;
-       rqstp->rq_res.pages = rqstp->rq_respages + 1;
-       rqstp->rq_res.len = 0;
-       rqstp->rq_res.page_base = 0;
-       rqstp->rq_res.page_len = 0;
-       rqstp->rq_res.buflen = PAGE_SIZE;
-       rqstp->rq_res.tail[0].iov_base = NULL;
-       rqstp->rq_res.tail[0].iov_len = 0;
        /* Will be turned off only in gss privacy case: */
        rqstp->rq_splice_ok = 1;
        /* Will be turned off only when NFSv4 Sessions are used */
        /* Setup reply header */
        rqstp->rq_xprt->xpt_ops->xpo_prep_reply_hdr(rqstp);
  
-       rqstp->rq_xid = svc_getu32(argv);
        svc_putu32(resv, rqstp->rq_xid);
  
-       dir  = svc_getnl(argv);
        vers = svc_getnl(argv);
  
        /* First words of reply: */
        svc_putnl(resv, 1);             /* REPLY */
  
-       if (dir != 0)           /* direction != CALL */
-               goto err_bad_dir;
        if (vers != 2)          /* RPC version number */
                goto err_bad_rpc;
  
   sendit:
        if (svc_authorise(rqstp))
                goto dropit;
-       return svc_send(rqstp);
+       return 1;               /* Caller can now send it */
  
   dropit:
        svc_authorise(rqstp);   /* doesn't hurt to call this twice */
@@@ -1161,12 -1147,6 +1147,6 @@@ err_short_len
  
        goto dropit;                    /* drop request */
  
- err_bad_dir:
-       svc_printk(rqstp, "bad direction %d, dropping request\n", dir);
-       serv->sv_stats->rpcbadfmt++;
-       goto dropit;                    /* drop request */
  err_bad_rpc:
        serv->sv_stats->rpcbadfmt++;
        svc_putnl(resv, 1);     /* REJECT */
@@@ -1219,6 -1199,100 +1199,100 @@@ err_bad
  }
  EXPORT_SYMBOL_GPL(svc_process);
  
+ /*
+  * Process the RPC request.
+  */
+ int
+ svc_process(struct svc_rqst *rqstp)
+ {
+       struct kvec             *argv = &rqstp->rq_arg.head[0];
+       struct kvec             *resv = &rqstp->rq_res.head[0];
+       struct svc_serv         *serv = rqstp->rq_server;
+       u32                     dir;
+       int                     error;
+       /*
+        * Setup response xdr_buf.
+        * Initially it has just one page
+        */
+       rqstp->rq_resused = 1;
+       resv->iov_base = page_address(rqstp->rq_respages[0]);
+       resv->iov_len = 0;
+       rqstp->rq_res.pages = rqstp->rq_respages + 1;
+       rqstp->rq_res.len = 0;
+       rqstp->rq_res.page_base = 0;
+       rqstp->rq_res.page_len = 0;
+       rqstp->rq_res.buflen = PAGE_SIZE;
+       rqstp->rq_res.tail[0].iov_base = NULL;
+       rqstp->rq_res.tail[0].iov_len = 0;
+       rqstp->rq_xid = svc_getu32(argv);
+       dir  = svc_getnl(argv);
+       if (dir != 0) {
+               /* direction != CALL */
+               svc_printk(rqstp, "bad direction %d, dropping request\n", dir);
+               serv->sv_stats->rpcbadfmt++;
+               svc_drop(rqstp);
+               return 0;
+       }
+       error = svc_process_common(rqstp, argv, resv);
+       if (error <= 0)
+               return error;
+       return svc_send(rqstp);
+ }
+ #if defined(CONFIG_NFS_V4_1)
+ /*
+  * Process a backchannel RPC request that arrived over an existing
+  * outbound connection
+  */
+ int
+ bc_svc_process(struct svc_serv *serv, struct rpc_rqst *req,
+              struct svc_rqst *rqstp)
+ {
+       struct kvec     *argv = &rqstp->rq_arg.head[0];
+       struct kvec     *resv = &rqstp->rq_res.head[0];
+       int             error;
+       /* Build the svc_rqst used by the common processing routine */
+       rqstp->rq_xprt = serv->bc_xprt;
+       rqstp->rq_xid = req->rq_xid;
+       rqstp->rq_prot = req->rq_xprt->prot;
+       rqstp->rq_server = serv;
+       rqstp->rq_addrlen = sizeof(req->rq_xprt->addr);
+       memcpy(&rqstp->rq_addr, &req->rq_xprt->addr, rqstp->rq_addrlen);
+       memcpy(&rqstp->rq_arg, &req->rq_rcv_buf, sizeof(rqstp->rq_arg));
+       memcpy(&rqstp->rq_res, &req->rq_snd_buf, sizeof(rqstp->rq_res));
+       /* reset result send buffer "put" position */
+       resv->iov_len = 0;
+       if (rqstp->rq_prot != IPPROTO_TCP) {
+               printk(KERN_ERR "No support for Non-TCP transports!\n");
+               BUG();
+       }
+       /*
+        * Skip the next two words because they've already been
+        * processed in the trasport
+        */
+       svc_getu32(argv);       /* XID */
+       svc_getnl(argv);        /* CALLDIR */
+       error = svc_process_common(rqstp, argv, resv);
+       if (error <= 0)
+               return error;
+       memcpy(&req->rq_snd_buf, &rqstp->rq_res, sizeof(req->rq_snd_buf));
+       return bc_send(req);
+ }
+ EXPORT_SYMBOL(bc_svc_process);
+ #endif /* CONFIG_NFS_V4_1 */
  /*
   * Return (transport-specific) limit on the rpc payload.
   */
diff --combined net/sunrpc/xprtsock.c
index 6c2d61586551511ff303760923bf6a887e0ae7b1,8a721867b60135e3c4f76a9631884db98ea109a7..9111d11c09fd5955c44b7ee2a9831a61597defb5
@@@ -34,6 -34,9 +34,9 @@@
  #include <linux/sunrpc/sched.h>
  #include <linux/sunrpc/xprtsock.h>
  #include <linux/file.h>
+ #ifdef CONFIG_NFS_V4_1
+ #include <linux/sunrpc/bc_xprt.h>
+ #endif
  
  #include <net/sock.h>
  #include <net/checksum.h>
@@@ -270,6 -273,13 +273,13 @@@ struct sock_xprt 
  #define TCP_RCV_COPY_FRAGHDR  (1UL << 1)
  #define TCP_RCV_COPY_XID      (1UL << 2)
  #define TCP_RCV_COPY_DATA     (1UL << 3)
+ #define TCP_RCV_READ_CALLDIR  (1UL << 4)
+ #define TCP_RCV_COPY_CALLDIR  (1UL << 5)
+ /*
+  * TCP RPC flags
+  */
+ #define TCP_RPC_REPLY         (1UL << 6)
  
  static inline struct sockaddr *xs_addr(struct rpc_xprt *xprt)
  {
@@@ -918,7 -928,7 +928,7 @@@ static void xs_udp_data_ready(struct so
        UDPX_INC_STATS_BH(sk, UDP_MIB_INDATAGRAMS);
  
        /* Something worked... */
 -      dst_confirm(skb->dst);
 +      dst_confirm(skb_dst(skb));
  
        xprt_adjust_cwnd(task, copied);
        xprt_update_rtt(task);
@@@ -956,7 -966,7 +966,7 @@@ static inline void xs_tcp_read_fraghdr(
        transport->tcp_offset = 0;
  
        /* Sanity check of the record length */
-       if (unlikely(transport->tcp_reclen < 4)) {
+       if (unlikely(transport->tcp_reclen < 8)) {
                dprintk("RPC:       invalid TCP record fragment length\n");
                xprt_force_disconnect(xprt);
                return;
@@@ -991,33 -1001,77 +1001,77 @@@ static inline void xs_tcp_read_xid(stru
        if (used != len)
                return;
        transport->tcp_flags &= ~TCP_RCV_COPY_XID;
-       transport->tcp_flags |= TCP_RCV_COPY_DATA;
+       transport->tcp_flags |= TCP_RCV_READ_CALLDIR;
        transport->tcp_copied = 4;
-       dprintk("RPC:       reading reply for XID %08x\n",
+       dprintk("RPC:       reading %s XID %08x\n",
+                       (transport->tcp_flags & TCP_RPC_REPLY) ? "reply for"
+                                                             : "request with",
                        ntohl(transport->tcp_xid));
        xs_tcp_check_fraghdr(transport);
  }
  
- static inline void xs_tcp_read_request(struct rpc_xprt *xprt, struct xdr_skb_reader *desc)
+ static inline void xs_tcp_read_calldir(struct sock_xprt *transport,
+                                      struct xdr_skb_reader *desc)
  {
-       struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
-       struct rpc_rqst *req;
+       size_t len, used;
+       u32 offset;
+       __be32  calldir;
+       /*
+        * We want transport->tcp_offset to be 8 at the end of this routine
+        * (4 bytes for the xid and 4 bytes for the call/reply flag).
+        * When this function is called for the first time,
+        * transport->tcp_offset is 4 (after having already read the xid).
+        */
+       offset = transport->tcp_offset - sizeof(transport->tcp_xid);
+       len = sizeof(calldir) - offset;
+       dprintk("RPC:       reading CALL/REPLY flag (%Zu bytes)\n", len);
+       used = xdr_skb_read_bits(desc, &calldir, len);
+       transport->tcp_offset += used;
+       if (used != len)
+               return;
+       transport->tcp_flags &= ~TCP_RCV_READ_CALLDIR;
+       transport->tcp_flags |= TCP_RCV_COPY_CALLDIR;
+       transport->tcp_flags |= TCP_RCV_COPY_DATA;
+       /*
+        * We don't yet have the XDR buffer, so we will write the calldir
+        * out after we get the buffer from the 'struct rpc_rqst'
+        */
+       if (ntohl(calldir) == RPC_REPLY)
+               transport->tcp_flags |= TCP_RPC_REPLY;
+       else
+               transport->tcp_flags &= ~TCP_RPC_REPLY;
+       dprintk("RPC:       reading %s CALL/REPLY flag %08x\n",
+                       (transport->tcp_flags & TCP_RPC_REPLY) ?
+                               "reply for" : "request with", calldir);
+       xs_tcp_check_fraghdr(transport);
+ }
+ static inline void xs_tcp_read_common(struct rpc_xprt *xprt,
+                                    struct xdr_skb_reader *desc,
+                                    struct rpc_rqst *req)
+ {
+       struct sock_xprt *transport =
+                               container_of(xprt, struct sock_xprt, xprt);
        struct xdr_buf *rcvbuf;
        size_t len;
        ssize_t r;
  
-       /* Find and lock the request corresponding to this xid */
-       spin_lock(&xprt->transport_lock);
-       req = xprt_lookup_rqst(xprt, transport->tcp_xid);
-       if (!req) {
-               transport->tcp_flags &= ~TCP_RCV_COPY_DATA;
-               dprintk("RPC:       XID %08x request not found!\n",
-                               ntohl(transport->tcp_xid));
-               spin_unlock(&xprt->transport_lock);
-               return;
+       rcvbuf = &req->rq_private_buf;
+       if (transport->tcp_flags & TCP_RCV_COPY_CALLDIR) {
+               /*
+                * Save the RPC direction in the XDR buffer
+                */
+               __be32  calldir = transport->tcp_flags & TCP_RPC_REPLY ?
+                                       htonl(RPC_REPLY) : 0;
+               memcpy(rcvbuf->head[0].iov_base + transport->tcp_copied,
+                       &calldir, sizeof(calldir));
+               transport->tcp_copied += sizeof(calldir);
+               transport->tcp_flags &= ~TCP_RCV_COPY_CALLDIR;
        }
  
-       rcvbuf = &req->rq_private_buf;
        len = desc->count;
        if (len > transport->tcp_reclen - transport->tcp_offset) {
                struct xdr_skb_reader my_desc;
                                "tcp_offset = %u, tcp_reclen = %u\n",
                                xprt, transport->tcp_copied,
                                transport->tcp_offset, transport->tcp_reclen);
-               goto out;
+               return;
        }
  
        dprintk("RPC:       XID %08x read %Zd bytes\n",
                        transport->tcp_flags &= ~TCP_RCV_COPY_DATA;
        }
  
- out:
+       return;
+ }
+ /*
+  * Finds the request corresponding to the RPC xid and invokes the common
+  * tcp read code to read the data.
+  */
+ static inline int xs_tcp_read_reply(struct rpc_xprt *xprt,
+                                   struct xdr_skb_reader *desc)
+ {
+       struct sock_xprt *transport =
+                               container_of(xprt, struct sock_xprt, xprt);
+       struct rpc_rqst *req;
+       dprintk("RPC:       read reply XID %08x\n", ntohl(transport->tcp_xid));
+       /* Find and lock the request corresponding to this xid */
+       spin_lock(&xprt->transport_lock);
+       req = xprt_lookup_rqst(xprt, transport->tcp_xid);
+       if (!req) {
+               dprintk("RPC:       XID %08x request not found!\n",
+                               ntohl(transport->tcp_xid));
+               spin_unlock(&xprt->transport_lock);
+               return -1;
+       }
+       xs_tcp_read_common(xprt, desc, req);
        if (!(transport->tcp_flags & TCP_RCV_COPY_DATA))
                xprt_complete_rqst(req->rq_task, transport->tcp_copied);
        spin_unlock(&xprt->transport_lock);
-       xs_tcp_check_fraghdr(transport);
+       return 0;
+ }
+ #if defined(CONFIG_NFS_V4_1)
+ /*
+  * Obtains an rpc_rqst previously allocated and invokes the common
+  * tcp read code to read the data.  The result is placed in the callback
+  * queue.
+  * If we're unable to obtain the rpc_rqst we schedule the closing of the
+  * connection and return -1.
+  */
+ static inline int xs_tcp_read_callback(struct rpc_xprt *xprt,
+                                      struct xdr_skb_reader *desc)
+ {
+       struct sock_xprt *transport =
+                               container_of(xprt, struct sock_xprt, xprt);
+       struct rpc_rqst *req;
+       req = xprt_alloc_bc_request(xprt);
+       if (req == NULL) {
+               printk(KERN_WARNING "Callback slot table overflowed\n");
+               xprt_force_disconnect(xprt);
+               return -1;
+       }
+       req->rq_xid = transport->tcp_xid;
+       dprintk("RPC:       read callback  XID %08x\n", ntohl(req->rq_xid));
+       xs_tcp_read_common(xprt, desc, req);
+       if (!(transport->tcp_flags & TCP_RCV_COPY_DATA)) {
+               struct svc_serv *bc_serv = xprt->bc_serv;
+               /*
+                * Add callback request to callback list.  The callback
+                * service sleeps on the sv_cb_waitq waiting for new
+                * requests.  Wake it up after adding enqueing the
+                * request.
+                */
+               dprintk("RPC:       add callback request to list\n");
+               spin_lock(&bc_serv->sv_cb_lock);
+               list_add(&req->rq_bc_list, &bc_serv->sv_cb_list);
+               spin_unlock(&bc_serv->sv_cb_lock);
+               wake_up(&bc_serv->sv_cb_waitq);
+       }
+       req->rq_private_buf.len = transport->tcp_copied;
+       return 0;
+ }
+ static inline int _xs_tcp_read_data(struct rpc_xprt *xprt,
+                                       struct xdr_skb_reader *desc)
+ {
+       struct sock_xprt *transport =
+                               container_of(xprt, struct sock_xprt, xprt);
+       return (transport->tcp_flags & TCP_RPC_REPLY) ?
+               xs_tcp_read_reply(xprt, desc) :
+               xs_tcp_read_callback(xprt, desc);
+ }
+ #else
+ static inline int _xs_tcp_read_data(struct rpc_xprt *xprt,
+                                       struct xdr_skb_reader *desc)
+ {
+       return xs_tcp_read_reply(xprt, desc);
+ }
+ #endif /* CONFIG_NFS_V4_1 */
+ /*
+  * Read data off the transport.  This can be either an RPC_CALL or an
+  * RPC_REPLY.  Relay the processing to helper functions.
+  */
+ static void xs_tcp_read_data(struct rpc_xprt *xprt,
+                                   struct xdr_skb_reader *desc)
+ {
+       struct sock_xprt *transport =
+                               container_of(xprt, struct sock_xprt, xprt);
+       if (_xs_tcp_read_data(xprt, desc) == 0)
+               xs_tcp_check_fraghdr(transport);
+       else {
+               /*
+                * The transport_lock protects the request handling.
+                * There's no need to hold it to update the tcp_flags.
+                */
+               transport->tcp_flags &= ~TCP_RCV_COPY_DATA;
+       }
  }
  
  static inline void xs_tcp_read_discard(struct sock_xprt *transport, struct xdr_skb_reader *desc)
@@@ -1114,9 -1282,14 +1282,14 @@@ static int xs_tcp_data_recv(read_descri
                        xs_tcp_read_xid(transport, &desc);
                        continue;
                }
+               /* Read in the call/reply flag */
+               if (transport->tcp_flags & TCP_RCV_READ_CALLDIR) {
+                       xs_tcp_read_calldir(transport, &desc);
+                       continue;
+               }
                /* Read in the request data */
                if (transport->tcp_flags & TCP_RCV_COPY_DATA) {
-                       xs_tcp_read_request(xprt, &desc);
+                       xs_tcp_read_data(xprt, &desc);
                        continue;
                }
                /* Skip over any trailing bytes on short reads */
@@@ -2010,6 -2183,9 +2183,9 @@@ static struct rpc_xprt_ops xs_tcp_ops 
        .buf_free               = rpc_free,
        .send_request           = xs_tcp_send_request,
        .set_retrans_timeout    = xprt_set_retrans_timeout_def,
+ #if defined(CONFIG_NFS_V4_1)
+       .release_request        = bc_release_request,
+ #endif /* CONFIG_NFS_V4_1 */
        .close                  = xs_tcp_close,
        .destroy                = xs_destroy,
        .print_stats            = xs_tcp_print_stats,