Merge branch 'for-2.6.37' of git://linux-nfs.org/~bfields/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 26 Oct 2010 16:55:25 +0000 (09:55 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 26 Oct 2010 16:55:25 +0000 (09:55 -0700)
* 'for-2.6.37' of git://linux-nfs.org/~bfields/linux: (99 commits)
  svcrpc: svc_tcp_sendto XPT_DEAD check is redundant
  svcrpc: no need for XPT_DEAD check in svc_xprt_enqueue
  svcrpc: assume svc_delete_xprt() called only once
  svcrpc: never clear XPT_BUSY on dead xprt
  nfsd4: fix connection allocation in sequence()
  nfsd4: only require krb5 principal for NFSv4.0 callbacks
  nfsd4: move minorversion to client
  nfsd4: delay session removal till free_client
  nfsd4: separate callback change and callback probe
  nfsd4: callback program number is per-session
  nfsd4: track backchannel connections
  nfsd4: confirm only on succesful create_session
  nfsd4: make backchannel sequence number per-session
  nfsd4: use client pointer to backchannel session
  nfsd4: move callback setup into session init code
  nfsd4: don't cache seq_misordered replies
  SUNRPC: Properly initialize sock_xprt.srcaddr in all cases
  SUNRPC: Use conventional switch statement when reclassifying sockets
  sunrpc/xprtrdma: clean up workqueue usage
  sunrpc: Turn list_for_each-s into the ..._entry-s
  ...

Fix up trivial conflicts (two different deprecation notices added in
separate branches) in Documentation/feature-removal-schedule.txt

15 files changed:
1  2 
Documentation/feature-removal-schedule.txt
fs/compat.c
fs/nfs/client.c
fs/nfs/mount_clnt.c
fs/nfsd/Kconfig
fs/nfsd/nfs4state.c
fs/nfsd/nfsctl.c
include/linux/nfs4.h
include/linux/sunrpc/clnt.h
net/socket.c
net/sunrpc/auth.c
net/sunrpc/cache.c
net/sunrpc/clnt.c
net/sunrpc/rpcb_clnt.c
net/sunrpc/xprtsock.c

@@@ -386,6 -386,34 +386,6 @@@ Who:      Tejun Heo <tj@kernel.org
  
  ----------------------------
  
 -What: Support for VMware's guest paravirtuliazation technique [VMI] will be
 -      dropped.
 -When: 2.6.37 or earlier.
 -Why:  With the recent innovations in CPU hardware acceleration technologies
 -      from Intel and AMD, VMware ran a few experiments to compare these
 -      techniques to guest paravirtualization technique on VMware's platform.
 -      These hardware assisted virtualization techniques have outperformed the
 -      performance benefits provided by VMI in most of the workloads. VMware
 -      expects that these hardware features will be ubiquitous in a couple of
 -      years, as a result, VMware has started a phased retirement of this
 -      feature from the hypervisor. We will be removing this feature from the
 -      Kernel too. Right now we are targeting 2.6.37 but can retire earlier if
 -      technical reasons (read opportunity to remove major chunk of pvops)
 -      arise.
 -
 -      Please note that VMI has always been an optimization and non-VMI kernels
 -      still work fine on VMware's platform.
 -      Latest versions of VMware's product which support VMI are,
 -      Workstation 7.0 and VSphere 4.0 on ESX side, future maintainence
 -      releases for these products will continue supporting VMI.
 -
 -      For more details about VMI retirement take a look at this,
 -      http://blogs.vmware.com/guestosguide/2009/09/vmi-retirement.html
 -
 -Who:  Alok N Kataria <akataria@vmware.com>
 -
 -----------------------------
 -
  What: Support for lcd_switch and display_get in asus-laptop driver
  When: March 2010
  Why:  These two features use non-standard interfaces. There are the
@@@ -502,6 -530,16 +502,6 @@@ Who:      Thomas Gleixner <tglx@linutronix.d
  
  ----------------------------
  
 -What: old ieee1394 subsystem (CONFIG_IEEE1394)
 -When: 2.6.37
 -Files:        drivers/ieee1394/ except init_ohci1394_dma.c
 -Why:  superseded by drivers/firewire/ (CONFIG_FIREWIRE) which offers more
 -      features, better performance, and better security, all with smaller
 -      and more modern code base
 -Who:  Stefan Richter <stefanr@s5r6.in-berlin.de>
 -
 -----------------------------
 -
  What: The acpi_sleep=s4_nonvs command line option
  When: 2.6.37
  Files:        arch/x86/kernel/acpi/sleep.c
@@@ -526,12 -564,13 +526,22 @@@ Who:    FUJITA Tomonori <fujita.tomonori@l
  
  ----------------------------
  
 -      
 +What: iwlwifi disable_hw_scan module parameters
 +When: 2.6.40
 +Why:  Hareware scan is the prefer method for iwlwifi devices for
 +      scanning operation. Remove software scan support for all the
 +      iwlwifi devices.
 +
 +Who:  Wey-Yi Guy <wey-yi.w.guy@intel.com>
 +
 +----------------------------
++
+ What:   access to nfsd auth cache through sys_nfsservctl or '.' files
+         in the 'nfsd' filesystem.
+ When:   2.6.40
+ Why:    This is a legacy interface which have been replaced by a more
+         dynamic cache.  Continuing to maintain this interface is an
+         unnecessary burden.
+ Who:    NeilBrown <neilb@suse.de>
+ ----------------------------
diff --combined fs/compat.c
@@@ -1153,7 -1153,7 +1153,7 @@@ static ssize_t compat_do_readv_writev(i
  {
        compat_ssize_t tot_len;
        struct iovec iovstack[UIO_FASTIOV];
 -      struct iovec *iov;
 +      struct iovec *iov = iovstack;
        ssize_t ret;
        io_fn_t fn;
        iov_fn_t fnv;
@@@ -1963,7 -1963,7 +1963,7 @@@ asmlinkage long compat_sys_ppoll(struc
  }
  #endif /* HAVE_SET_RESTORE_SIGMASK */
  
- #if defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE)
+ #if (defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE)) && !defined(CONFIG_NFSD_DEPRECATED)
  /* Stuff for NFS server syscalls... */
  struct compat_nfsctl_svc {
        u16                     svc32_port;
diff --combined fs/nfs/client.c
@@@ -48,7 -48,6 +48,7 @@@
  #include "iostat.h"
  #include "internal.h"
  #include "fscache.h"
 +#include "pnfs.h"
  
  #define NFSDBG_FACILITY               NFSDBG_CLIENT
  
@@@ -156,9 -155,7 +156,9 @@@ static struct nfs_client *nfs_alloc_cli
        cred = rpc_lookup_machine_cred();
        if (!IS_ERR(cred))
                clp->cl_machine_cred = cred;
 -
 +#if defined(CONFIG_NFS_V4_1)
 +      INIT_LIST_HEAD(&clp->cl_layouts);
 +#endif
        nfs_fscache_get_client_cookie(clp);
  
        return clp;
@@@ -255,7 -252,6 +255,7 @@@ void nfs_put_client(struct nfs_client *
                nfs_free_client(clp);
        }
  }
 +EXPORT_SYMBOL_GPL(nfs_put_client);
  
  #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
  /*
@@@ -605,6 -601,7 +605,7 @@@ static int nfs_create_rpc_client(struc
  {
        struct rpc_clnt         *clnt = NULL;
        struct rpc_create_args args = {
+               .net            = &init_net,
                .protocol       = clp->cl_proto,
                .address        = (struct sockaddr *)&clp->cl_addr,
                .addrsize       = clp->cl_addrlen,
   */
  static void nfs_destroy_server(struct nfs_server *server)
  {
 -      if (!(server->flags & NFS_MOUNT_NONLM))
 +      if (!(server->flags & NFS_MOUNT_LOCAL_FLOCK) ||
 +                      !(server->flags & NFS_MOUNT_LOCAL_FCNTL))
                nlmclnt_done(server->nlm_host);
  }
  
@@@ -662,8 -658,7 +663,8 @@@ static int nfs_start_lockd(struct nfs_s
  
        if (nlm_init.nfs_version > 3)
                return 0;
 -      if (server->flags & NFS_MOUNT_NONLM)
 +      if ((server->flags & NFS_MOUNT_LOCAL_FLOCK) &&
 +                      (server->flags & NFS_MOUNT_LOCAL_FCNTL))
                return 0;
  
        switch (clp->cl_proto) {
@@@ -904,13 -899,11 +905,13 @@@ static void nfs_server_set_fsinfo(struc
        if (server->wsize > NFS_MAX_FILE_IO_SIZE)
                server->wsize = NFS_MAX_FILE_IO_SIZE;
        server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
 +      set_pnfs_layoutdriver(server, fsinfo->layouttype);
 +
        server->wtmult = nfs_block_bits(fsinfo->wtmult, NULL);
  
        server->dtsize = nfs_block_size(fsinfo->dtpref, NULL);
 -      if (server->dtsize > PAGE_CACHE_SIZE)
 -              server->dtsize = PAGE_CACHE_SIZE;
 +      if (server->dtsize > PAGE_CACHE_SIZE * NFS_MAX_READDIR_PAGES)
 +              server->dtsize = PAGE_CACHE_SIZE * NFS_MAX_READDIR_PAGES;
        if (server->dtsize > server->rsize)
                server->dtsize = server->rsize;
  
  
        server->maxfilesize = fsinfo->maxfilesize;
  
 +      server->time_delta = fsinfo->time_delta;
 +
        /* We're airborne Set socket buffersize */
        rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100);
  }
@@@ -945,7 -936,6 +946,7 @@@ static int nfs_probe_fsinfo(struct nfs_
        }
  
        fsinfo.fattr = fattr;
 +      fsinfo.layouttype = 0;
        error = clp->rpc_ops->fsinfo(server, mntfh, &fsinfo);
        if (error < 0)
                goto out_error;
@@@ -1028,7 -1018,6 +1029,7 @@@ void nfs_free_server(struct nfs_server 
  {
        dprintk("--> nfs_free_server()\n");
  
 +      unset_pnfs_layoutdriver(server);
        spin_lock(&nfs_client_lock);
        list_del(&server->client_link);
        list_del(&server->master_link);
@@@ -1368,9 -1357,8 +1369,9 @@@ static int nfs4_init_server(struct nfs_
  
        /* Initialise the client representation from the mount data */
        server->flags = data->flags;
 -      server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR|
 -              NFS_CAP_POSIX_LOCK;
 +      server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR|NFS_CAP_POSIX_LOCK;
 +      if (!(data->flags & NFS_MOUNT_NORDIRPLUS))
 +                      server->caps |= NFS_CAP_READDIRPLUS;
        server->options = data->options;
  
        /* Get a client record */
diff --combined fs/nfs/mount_clnt.c
@@@ -153,6 -153,7 +153,7 @@@ int nfs_mount(struct nfs_mount_request 
                .rpc_resp       = &result,
        };
        struct rpc_create_args args = {
+               .net            = &init_net,
                .protocol       = info->protocol,
                .address        = info->sap,
                .addrsize       = info->salen,
@@@ -224,6 -225,7 +225,7 @@@ void nfs_umount(const struct nfs_mount_
                .to_retries = 2,
        };
        struct rpc_create_args args = {
+               .net            = &init_net,
                .protocol       = IPPROTO_UDP,
                .address        = info->sap,
                .addrsize       = info->salen,
@@@ -436,7 -438,7 +438,7 @@@ static int decode_auth_flavors(struct x
  
        for (i = 0; i < entries; i++) {
                flavors[i] = ntohl(*p++);
 -              dprintk("NFS:\tflavor %u: %d\n", i, flavors[i]);
 +              dprintk("NFS:   auth flavor[%u]: %d\n", i, flavors[i]);
        }
        *count = i;
  
diff --combined fs/nfsd/Kconfig
@@@ -2,7 -2,6 +2,7 @@@ config NFS
        tristate "NFS server support"
        depends on INET
        depends on FILE_LOCKING
 +      depends on BKL # fix as soon as lockd is done
        select LOCKD
        select SUNRPC
        select EXPORTFS
  
          If unsure, say N.
  
+ config NFSD_DEPRECATED
+       bool "Include support for deprecated syscall interface to NFSD"
+       depends on NFSD
+       default y
+       help
+         The syscall interface to nfsd was obsoleted in 2.6.0 by a new
+         filesystem based interface.  The old interface is due for removal
+         in 2.6.40.  If you wish to remove the interface before then
+         say N.
+         In unsure, say Y.
  config NFSD_V2_ACL
        bool
        depends on NFSD
diff --combined fs/nfsd/nfs4state.c
@@@ -33,7 -33,7 +33,7 @@@
  */
  
  #include <linux/file.h>
 -#include <linux/smp_lock.h>
 +#include <linux/fs.h>
  #include <linux/slab.h>
  #include <linux/namei.h>
  #include <linux/swap.h>
@@@ -207,7 -207,6 +207,6 @@@ alloc_init_deleg(struct nfs4_client *cl
  {
        struct nfs4_delegation *dp;
        struct nfs4_file *fp = stp->st_file;
-       struct nfs4_cb_conn *cb = &stp->st_stateowner->so_client->cl_cb_conn;
  
        dprintk("NFSD alloc_init_deleg\n");
        /*
        nfs4_file_get_access(fp, O_RDONLY);
        dp->dl_flock = NULL;
        dp->dl_type = type;
-       dp->dl_ident = cb->cb_ident;
        dp->dl_stateid.si_boot = boot_time;
        dp->dl_stateid.si_stateownerid = current_delegid++;
        dp->dl_stateid.si_fileid = 0;
@@@ -535,171 -533,258 +533,258 @@@ gen_sessionid(struct nfsd4_session *ses
   */
  #define NFSD_MIN_HDR_SEQ_SZ  (24 + 12 + 44)
  
+ static void
+ free_session_slots(struct nfsd4_session *ses)
+ {
+       int i;
+       for (i = 0; i < ses->se_fchannel.maxreqs; i++)
+               kfree(ses->se_slots[i]);
+ }
  /*
-  * Give the client the number of ca_maxresponsesize_cached slots it
-  * requests, of size bounded by NFSD_SLOT_CACHE_SIZE,
-  * NFSD_MAX_MEM_PER_SESSION, and nfsd_drc_max_mem. Do not allow more
-  * than NFSD_MAX_SLOTS_PER_SESSION.
-  *
-  * If we run out of reserved DRC memory we should (up to a point)
+  * We don't actually need to cache the rpc and session headers, so we
+  * can allocate a little less for each slot:
+  */
+ static inline int slot_bytes(struct nfsd4_channel_attrs *ca)
+ {
+       return ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ;
+ }
+ static int nfsd4_sanitize_slot_size(u32 size)
+ {
+       size -= NFSD_MIN_HDR_SEQ_SZ; /* We don't cache the rpc header */
+       size = min_t(u32, size, NFSD_SLOT_CACHE_SIZE);
+       return size;
+ }
+ /*
+  * XXX: If we run out of reserved DRC memory we could (up to a point)
   * re-negotiate active sessions and reduce their slot usage to make
   * rooom for new connections. For now we just fail the create session.
   */
- static int set_forechannel_drc_size(struct nfsd4_channel_attrs *fchan)
+ static int nfsd4_get_drc_mem(int slotsize, u32 num)
  {
-       int mem, size = fchan->maxresp_cached;
+       int avail;
  
-       if (fchan->maxreqs < 1)
-               return nfserr_inval;
+       num = min_t(u32, num, NFSD_MAX_SLOTS_PER_SESSION);
  
-       if (size < NFSD_MIN_HDR_SEQ_SZ)
-               size = NFSD_MIN_HDR_SEQ_SZ;
-       size -= NFSD_MIN_HDR_SEQ_SZ;
-       if (size > NFSD_SLOT_CACHE_SIZE)
-               size = NFSD_SLOT_CACHE_SIZE;
+       spin_lock(&nfsd_drc_lock);
+       avail = min_t(int, NFSD_MAX_MEM_PER_SESSION,
+                       nfsd_drc_max_mem - nfsd_drc_mem_used);
+       num = min_t(int, num, avail / slotsize);
+       nfsd_drc_mem_used += num * slotsize;
+       spin_unlock(&nfsd_drc_lock);
  
-       /* bound the maxreqs by NFSD_MAX_MEM_PER_SESSION */
-       mem = fchan->maxreqs * size;
-       if (mem > NFSD_MAX_MEM_PER_SESSION) {
-               fchan->maxreqs = NFSD_MAX_MEM_PER_SESSION / size;
-               if (fchan->maxreqs > NFSD_MAX_SLOTS_PER_SESSION)
-                       fchan->maxreqs = NFSD_MAX_SLOTS_PER_SESSION;
-               mem = fchan->maxreqs * size;
-       }
+       return num;
+ }
  
+ static void nfsd4_put_drc_mem(int slotsize, int num)
+ {
        spin_lock(&nfsd_drc_lock);
-       /* bound the total session drc memory ussage */
-       if (mem + nfsd_drc_mem_used > nfsd_drc_max_mem) {
-               fchan->maxreqs = (nfsd_drc_max_mem - nfsd_drc_mem_used) / size;
-               mem = fchan->maxreqs * size;
-       }
-       nfsd_drc_mem_used += mem;
+       nfsd_drc_mem_used -= slotsize * num;
        spin_unlock(&nfsd_drc_lock);
+ }
  
-       if (fchan->maxreqs == 0)
-               return nfserr_jukebox;
+ static struct nfsd4_session *alloc_session(int slotsize, int numslots)
+ {
+       struct nfsd4_session *new;
+       int mem, i;
  
-       fchan->maxresp_cached = size + NFSD_MIN_HDR_SEQ_SZ;
-       return 0;
+       BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot *)
+                       + sizeof(struct nfsd4_session) > PAGE_SIZE);
+       mem = numslots * sizeof(struct nfsd4_slot *);
+       new = kzalloc(sizeof(*new) + mem, GFP_KERNEL);
+       if (!new)
+               return NULL;
+       /* allocate each struct nfsd4_slot and data cache in one piece */
+       for (i = 0; i < numslots; i++) {
+               mem = sizeof(struct nfsd4_slot) + slotsize;
+               new->se_slots[i] = kzalloc(mem, GFP_KERNEL);
+               if (!new->se_slots[i])
+                       goto out_free;
+       }
+       return new;
+ out_free:
+       while (i--)
+               kfree(new->se_slots[i]);
+       kfree(new);
+       return NULL;
  }
  
- /*
-  * fchan holds the client values on input, and the server values on output
-  * sv_max_mesg is the maximum payload plus one page for overhead.
-  */
- static int init_forechannel_attrs(struct svc_rqst *rqstp,
-                                 struct nfsd4_channel_attrs *session_fchan,
-                                 struct nfsd4_channel_attrs *fchan)
+ static void init_forechannel_attrs(struct nfsd4_channel_attrs *new, struct nfsd4_channel_attrs *req, int numslots, int slotsize)
  {
-       int status = 0;
-       __u32   maxcount = nfsd_serv->sv_max_mesg;
+       u32 maxrpc = nfsd_serv->sv_max_mesg;
  
-       /* headerpadsz set to zero in encode routine */
+       new->maxreqs = numslots;
+       new->maxresp_cached = slotsize + NFSD_MIN_HDR_SEQ_SZ;
+       new->maxreq_sz = min_t(u32, req->maxreq_sz, maxrpc);
+       new->maxresp_sz = min_t(u32, req->maxresp_sz, maxrpc);
+       new->maxops = min_t(u32, req->maxops, NFSD_MAX_OPS_PER_COMPOUND);
+ }
  
-       /* Use the client's max request and max response size if possible */
-       if (fchan->maxreq_sz > maxcount)
-               fchan->maxreq_sz = maxcount;
-       session_fchan->maxreq_sz = fchan->maxreq_sz;
+ static void free_conn(struct nfsd4_conn *c)
+ {
+       svc_xprt_put(c->cn_xprt);
+       kfree(c);
+ }
  
-       if (fchan->maxresp_sz > maxcount)
-               fchan->maxresp_sz = maxcount;
-       session_fchan->maxresp_sz = fchan->maxresp_sz;
+ static void nfsd4_conn_lost(struct svc_xpt_user *u)
+ {
+       struct nfsd4_conn *c = container_of(u, struct nfsd4_conn, cn_xpt_user);
+       struct nfs4_client *clp = c->cn_session->se_client;
  
-       /* Use the client's maxops if possible */
-       if (fchan->maxops > NFSD_MAX_OPS_PER_COMPOUND)
-               fchan->maxops = NFSD_MAX_OPS_PER_COMPOUND;
-       session_fchan->maxops = fchan->maxops;
+       spin_lock(&clp->cl_lock);
+       if (!list_empty(&c->cn_persession)) {
+               list_del(&c->cn_persession);
+               free_conn(c);
+       }
+       spin_unlock(&clp->cl_lock);
+ }
  
-       /* FIXME: Error means no more DRC pages so the server should
-        * recover pages from existing sessions. For now fail session
-        * creation.
-        */
-       status = set_forechannel_drc_size(fchan);
+ static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags)
+ {
+       struct nfsd4_conn *conn;
  
-       session_fchan->maxresp_cached = fchan->maxresp_cached;
-       session_fchan->maxreqs = fchan->maxreqs;
+       conn = kmalloc(sizeof(struct nfsd4_conn), GFP_KERNEL);
+       if (!conn)
+               return NULL;
+       svc_xprt_get(rqstp->rq_xprt);
+       conn->cn_xprt = rqstp->rq_xprt;
+       conn->cn_flags = flags;
+       INIT_LIST_HEAD(&conn->cn_xpt_user.list);
+       return conn;
+ }
  
-       dprintk("%s status %d\n", __func__, status);
-       return status;
+ static void __nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses)
+ {
+       conn->cn_session = ses;
+       list_add(&conn->cn_persession, &ses->se_conns);
  }
  
- static void
- free_session_slots(struct nfsd4_session *ses)
+ static void nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses)
  {
-       int i;
+       struct nfs4_client *clp = ses->se_client;
  
-       for (i = 0; i < ses->se_fchannel.maxreqs; i++)
-               kfree(ses->se_slots[i]);
+       spin_lock(&clp->cl_lock);
+       __nfsd4_hash_conn(conn, ses);
+       spin_unlock(&clp->cl_lock);
  }
  
- /*
-  * We don't actually need to cache the rpc and session headers, so we
-  * can allocate a little less for each slot:
-  */
- static inline int slot_bytes(struct nfsd4_channel_attrs *ca)
+ static void nfsd4_register_conn(struct nfsd4_conn *conn)
  {
-       return ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ;
+       conn->cn_xpt_user.callback = nfsd4_conn_lost;
+       register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user);
  }
  
- static int
- alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp,
-                  struct nfsd4_create_session *cses)
+ static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses)
  {
-       struct nfsd4_session *new, tmp;
-       struct nfsd4_slot *sp;
-       int idx, slotsize, cachesize, i;
-       int status;
+       struct nfsd4_conn *conn;
+       u32 flags = NFS4_CDFC4_FORE;
  
-       memset(&tmp, 0, sizeof(tmp));
+       if (ses->se_flags & SESSION4_BACK_CHAN)
+               flags |= NFS4_CDFC4_BACK;
+       conn = alloc_conn(rqstp, flags);
+       if (!conn)
+               return nfserr_jukebox;
+       nfsd4_hash_conn(conn, ses);
+       nfsd4_register_conn(conn);
+       return nfs_ok;
+ }
  
-       /* FIXME: For now, we just accept the client back channel attributes. */
-       tmp.se_bchannel = cses->back_channel;
-       status = init_forechannel_attrs(rqstp, &tmp.se_fchannel,
-                                       &cses->fore_channel);
-       if (status)
-               goto out;
+ static void nfsd4_del_conns(struct nfsd4_session *s)
+ {
+       struct nfs4_client *clp = s->se_client;
+       struct nfsd4_conn *c;
  
-       BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot)
-                    + sizeof(struct nfsd4_session) > PAGE_SIZE);
+       spin_lock(&clp->cl_lock);
+       while (!list_empty(&s->se_conns)) {
+               c = list_first_entry(&s->se_conns, struct nfsd4_conn, cn_persession);
+               list_del_init(&c->cn_persession);
+               spin_unlock(&clp->cl_lock);
  
-       status = nfserr_jukebox;
-       /* allocate struct nfsd4_session and slot table pointers in one piece */
-       slotsize = tmp.se_fchannel.maxreqs * sizeof(struct nfsd4_slot *);
-       new = kzalloc(sizeof(*new) + slotsize, GFP_KERNEL);
-       if (!new)
-               goto out;
+               unregister_xpt_user(c->cn_xprt, &c->cn_xpt_user);
+               free_conn(c);
  
-       memcpy(new, &tmp, sizeof(*new));
+               spin_lock(&clp->cl_lock);
+       }
+       spin_unlock(&clp->cl_lock);
+ }
  
-       /* allocate each struct nfsd4_slot and data cache in one piece */
-       cachesize = slot_bytes(&new->se_fchannel);
-       for (i = 0; i < new->se_fchannel.maxreqs; i++) {
-               sp = kzalloc(sizeof(*sp) + cachesize, GFP_KERNEL);
-               if (!sp)
-                       goto out_free;
-               new->se_slots[i] = sp;
+ void free_session(struct kref *kref)
+ {
+       struct nfsd4_session *ses;
+       int mem;
+       ses = container_of(kref, struct nfsd4_session, se_ref);
+       nfsd4_del_conns(ses);
+       spin_lock(&nfsd_drc_lock);
+       mem = ses->se_fchannel.maxreqs * slot_bytes(&ses->se_fchannel);
+       nfsd_drc_mem_used -= mem;
+       spin_unlock(&nfsd_drc_lock);
+       free_session_slots(ses);
+       kfree(ses);
+ }
+ static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, struct nfsd4_create_session *cses)
+ {
+       struct nfsd4_session *new;
+       struct nfsd4_channel_attrs *fchan = &cses->fore_channel;
+       int numslots, slotsize;
+       int status;
+       int idx;
+       /*
+        * Note decreasing slot size below client's request may
+        * make it difficult for client to function correctly, whereas
+        * decreasing the number of slots will (just?) affect
+        * performance.  When short on memory we therefore prefer to
+        * decrease number of slots instead of their size.
+        */
+       slotsize = nfsd4_sanitize_slot_size(fchan->maxresp_cached);
+       numslots = nfsd4_get_drc_mem(slotsize, fchan->maxreqs);
+       new = alloc_session(slotsize, numslots);
+       if (!new) {
+               nfsd4_put_drc_mem(slotsize, fchan->maxreqs);
+               return NULL;
        }
+       init_forechannel_attrs(&new->se_fchannel, fchan, numslots, slotsize);
  
        new->se_client = clp;
        gen_sessionid(new);
-       idx = hash_sessionid(&new->se_sessionid);
-       memcpy(clp->cl_sessionid.data, new->se_sessionid.data,
-              NFS4_MAX_SESSIONID_LEN);
  
+       INIT_LIST_HEAD(&new->se_conns);
+       new->se_cb_seq_nr = 1;
        new->se_flags = cses->flags;
+       new->se_cb_prog = cses->callback_prog;
        kref_init(&new->se_ref);
+       idx = hash_sessionid(&new->se_sessionid);
        spin_lock(&client_lock);
        list_add(&new->se_hash, &sessionid_hashtbl[idx]);
        list_add(&new->se_perclnt, &clp->cl_sessions);
        spin_unlock(&client_lock);
  
-       status = nfs_ok;
- out:
-       return status;
- out_free:
-       free_session_slots(new);
-       kfree(new);
-       goto out;
+       status = nfsd4_new_conn(rqstp, new);
+       /* whoops: benny points out, status is ignored! (err, or bogus) */
+       if (status) {
+               free_session(&new->se_ref);
+               return NULL;
+       }
+       if (!clp->cl_cb_session && (cses->flags & SESSION4_BACK_CHAN)) {
+               struct sockaddr *sa = svc_addr(rqstp);
+               clp->cl_cb_session = new;
+               clp->cl_cb_conn.cb_xprt = rqstp->rq_xprt;
+               svc_xprt_get(rqstp->rq_xprt);
+               rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa);
+               clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa);
+               nfsd4_probe_callback(clp);
+       }
+       return new;
  }
  
  /* caller must hold client_lock */
@@@ -731,21 -816,6 +816,6 @@@ unhash_session(struct nfsd4_session *se
        list_del(&ses->se_perclnt);
  }
  
- void
- free_session(struct kref *kref)
- {
-       struct nfsd4_session *ses;
-       int mem;
-       ses = container_of(kref, struct nfsd4_session, se_ref);
-       spin_lock(&nfsd_drc_lock);
-       mem = ses->se_fchannel.maxreqs * slot_bytes(&ses->se_fchannel);
-       nfsd_drc_mem_used -= mem;
-       spin_unlock(&nfsd_drc_lock);
-       free_session_slots(ses);
-       kfree(ses);
- }
  /* must be called under the client_lock */
  static inline void
  renew_client_locked(struct nfs4_client *clp)
@@@ -812,6 -882,13 +882,13 @@@ static struct nfs4_client *alloc_client
  static inline void
  free_client(struct nfs4_client *clp)
  {
+       while (!list_empty(&clp->cl_sessions)) {
+               struct nfsd4_session *ses;
+               ses = list_entry(clp->cl_sessions.next, struct nfsd4_session,
+                               se_perclnt);
+               list_del(&ses->se_perclnt);
+               nfsd4_put_session(ses);
+       }
        if (clp->cl_cred.cr_group_info)
                put_group_info(clp->cl_cred.cr_group_info);
        kfree(clp->cl_principal);
@@@ -838,15 -915,12 +915,12 @@@ release_session_client(struct nfsd4_ses
  static inline void
  unhash_client_locked(struct nfs4_client *clp)
  {
+       struct nfsd4_session *ses;
        mark_client_expired(clp);
        list_del(&clp->cl_lru);
-       while (!list_empty(&clp->cl_sessions)) {
-               struct nfsd4_session  *ses;
-               ses = list_entry(clp->cl_sessions.next, struct nfsd4_session,
-                                se_perclnt);
-               unhash_session(ses);
-               nfsd4_put_session(ses);
-       }
+       list_for_each_entry(ses, &clp->cl_sessions, se_perclnt)
+               list_del_init(&ses->se_hash);
  }
  
  static void
@@@ -875,7 -949,7 +949,7 @@@ expire_client(struct nfs4_client *clp
                sop = list_entry(clp->cl_openowners.next, struct nfs4_stateowner, so_perclient);
                release_openowner(sop);
        }
-       nfsd4_set_callback_client(clp, NULL);
+       nfsd4_shutdown_callback(clp);
        if (clp->cl_cb_conn.cb_xprt)
                svc_xprt_put(clp->cl_cb_conn.cb_xprt);
        list_del(&clp->cl_idhash);
@@@ -960,6 -1034,8 +1034,8 @@@ static struct nfs4_client *create_clien
        if (clp == NULL)
                return NULL;
  
+       INIT_LIST_HEAD(&clp->cl_sessions);
        princ = svc_gss_principal(rqstp);
        if (princ) {
                clp->cl_principal = kstrdup(princ, GFP_KERNEL);
        INIT_LIST_HEAD(&clp->cl_strhash);
        INIT_LIST_HEAD(&clp->cl_openowners);
        INIT_LIST_HEAD(&clp->cl_delegations);
-       INIT_LIST_HEAD(&clp->cl_sessions);
        INIT_LIST_HEAD(&clp->cl_lru);
+       spin_lock_init(&clp->cl_lock);
+       INIT_WORK(&clp->cl_cb_null.cb_work, nfsd4_do_callback_rpc);
        clp->cl_time = get_seconds();
        clear_bit(0, &clp->cl_cb_slot_busy);
        rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table");
        clp->cl_flavor = rqstp->rq_flavor;
        copy_cred(&clp->cl_cred, &rqstp->rq_cred);
        gen_confirm(clp);
+       clp->cl_cb_session = NULL;
        return clp;
  }
  
@@@ -1098,7 -1175,7 +1175,7 @@@ find_unconfirmed_client_by_str(const ch
  static void
  gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, u32 scopeid)
  {
-       struct nfs4_cb_conn *cb = &clp->cl_cb_conn;
+       struct nfs4_cb_conn *conn = &clp->cl_cb_conn;
        unsigned short expected_family;
  
        /* Currently, we only support tcp and tcp6 for the callback channel */
        else
                goto out_err;
  
-       cb->cb_addrlen = rpc_uaddr2sockaddr(se->se_callback_addr_val,
+       conn->cb_addrlen = rpc_uaddr2sockaddr(se->se_callback_addr_val,
                                            se->se_callback_addr_len,
-                                           (struct sockaddr *) &cb->cb_addr,
-                                           sizeof(cb->cb_addr));
+                                           (struct sockaddr *)&conn->cb_addr,
+                                           sizeof(conn->cb_addr));
  
-       if (!cb->cb_addrlen || cb->cb_addr.ss_family != expected_family)
+       if (!conn->cb_addrlen || conn->cb_addr.ss_family != expected_family)
                goto out_err;
  
-       if (cb->cb_addr.ss_family == AF_INET6)
-               ((struct sockaddr_in6 *) &cb->cb_addr)->sin6_scope_id = scopeid;
+       if (conn->cb_addr.ss_family == AF_INET6)
+               ((struct sockaddr_in6 *)&conn->cb_addr)->sin6_scope_id = scopeid;
  
-       cb->cb_minorversion = 0;
-       cb->cb_prog = se->se_callback_prog;
-       cb->cb_ident = se->se_callback_ident;
+       conn->cb_prog = se->se_callback_prog;
+       conn->cb_ident = se->se_callback_ident;
        return;
  out_err:
-       cb->cb_addr.ss_family = AF_UNSPEC;
-       cb->cb_addrlen = 0;
+       conn->cb_addr.ss_family = AF_UNSPEC;
+       conn->cb_addrlen = 0;
        dprintk(KERN_INFO "NFSD: this client (clientid %08x/%08x) "
                "will not receive delegations\n",
                clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
@@@ -1415,7 -1491,9 +1491,9 @@@ nfsd4_create_session(struct svc_rqst *r
  {
        struct sockaddr *sa = svc_addr(rqstp);
        struct nfs4_client *conf, *unconf;
+       struct nfsd4_session *new;
        struct nfsd4_clid_slot *cs_slot = NULL;
+       bool confirm_me = false;
        int status = 0;
  
        nfs4_lock_state();
                                cs_slot->sl_seqid, cr_ses->seqid);
                        goto out;
                }
-               cs_slot->sl_seqid++;
        } else if (unconf) {
                if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) ||
                    !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) {
                if (status) {
                        /* an unconfirmed replay returns misordered */
                        status = nfserr_seq_misordered;
-                       goto out_cache;
+                       goto out;
                }
  
-               cs_slot->sl_seqid++; /* from 0 to 1 */
-               move_to_confirmed(unconf);
-               if (cr_ses->flags & SESSION4_BACK_CHAN) {
-                       unconf->cl_cb_conn.cb_xprt = rqstp->rq_xprt;
-                       svc_xprt_get(rqstp->rq_xprt);
-                       rpc_copy_addr(
-                               (struct sockaddr *)&unconf->cl_cb_conn.cb_addr,
-                               sa);
-                       unconf->cl_cb_conn.cb_addrlen = svc_addr_len(sa);
-                       unconf->cl_cb_conn.cb_minorversion =
-                               cstate->minorversion;
-                       unconf->cl_cb_conn.cb_prog = cr_ses->callback_prog;
-                       unconf->cl_cb_seq_nr = 1;
-                       nfsd4_probe_callback(unconf, &unconf->cl_cb_conn);
-               }
+               confirm_me = true;
                conf = unconf;
        } else {
                status = nfserr_stale_clientid;
                goto out;
        }
  
+       /*
+        * XXX: we should probably set this at creation time, and check
+        * for consistent minorversion use throughout:
+        */
+       conf->cl_minorversion = 1;
        /*
         * We do not support RDMA or persistent sessions
         */
        cr_ses->flags &= ~SESSION4_PERSIST;
        cr_ses->flags &= ~SESSION4_RDMA;
  
-       status = alloc_init_session(rqstp, conf, cr_ses);
-       if (status)
+       status = nfserr_jukebox;
+       new = alloc_init_session(rqstp, conf, cr_ses);
+       if (!new)
                goto out;
-       memcpy(cr_ses->sessionid.data, conf->cl_sessionid.data,
+       status = nfs_ok;
+       memcpy(cr_ses->sessionid.data, new->se_sessionid.data,
               NFS4_MAX_SESSIONID_LEN);
+       cs_slot->sl_seqid++;
        cr_ses->seqid = cs_slot->sl_seqid;
  
- out_cache:
        /* cache solo and embedded create sessions under the state lock */
        nfsd4_cache_create_session(cr_ses, cs_slot, status);
+       if (confirm_me)
+               move_to_confirmed(conf);
  out:
        nfs4_unlock_state();
        dprintk("%s returns %d\n", __func__, ntohl(status));
@@@ -1546,8 -1616,11 +1616,11 @@@ nfsd4_destroy_session(struct svc_rqst *
  
        nfs4_lock_state();
        /* wait for callbacks */
-       nfsd4_set_callback_client(ses->se_client, NULL);
+       nfsd4_shutdown_callback(ses->se_client);
        nfs4_unlock_state();
+       nfsd4_del_conns(ses);
        nfsd4_put_session(ses);
        status = nfs_ok;
  out:
        return status;
  }
  
+ static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_session *s)
+ {
+       struct nfsd4_conn *c;
+       list_for_each_entry(c, &s->se_conns, cn_persession) {
+               if (c->cn_xprt == xpt) {
+                       return c;
+               }
+       }
+       return NULL;
+ }
+ static void nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses)
+ {
+       struct nfs4_client *clp = ses->se_client;
+       struct nfsd4_conn *c;
+       spin_lock(&clp->cl_lock);
+       c = __nfsd4_find_conn(new->cn_xprt, ses);
+       if (c) {
+               spin_unlock(&clp->cl_lock);
+               free_conn(new);
+               return;
+       }
+       __nfsd4_hash_conn(new, ses);
+       spin_unlock(&clp->cl_lock);
+       nfsd4_register_conn(new);
+       return;
+ }
  __be32
  nfsd4_sequence(struct svc_rqst *rqstp,
               struct nfsd4_compound_state *cstate,
        struct nfsd4_compoundres *resp = rqstp->rq_resp;
        struct nfsd4_session *session;
        struct nfsd4_slot *slot;
+       struct nfsd4_conn *conn;
        int status;
  
        if (resp->opcnt != 1)
                return nfserr_sequence_pos;
  
+       /*
+        * Will be either used or freed by nfsd4_sequence_check_conn
+        * below.
+        */
+       conn = alloc_conn(rqstp, NFS4_CDFC4_FORE);
+       if (!conn)
+               return nfserr_jukebox;
        spin_lock(&client_lock);
        status = nfserr_badsession;
        session = find_in_sessionid_hashtbl(&seq->sessionid);
        if (status)
                goto out;
  
+       nfsd4_sequence_check_conn(conn, session);
+       conn = NULL;
        /* Success! bump slot seqid */
        slot->sl_inuse = true;
        slot->sl_seqid = seq->seqid;
@@@ -1613,6 -1728,7 +1728,7 @@@ out
                nfsd4_get_session(cstate->session);
                atomic_inc(&session->se_client->cl_refcount);
        }
+       kfree(conn);
        spin_unlock(&client_lock);
        dprintk("%s: return %d\n", __func__, ntohl(status));
        return status;
@@@ -1747,6 -1863,11 +1863,11 @@@ nfsd4_setclientid(struct svc_rqst *rqst
                        goto out;
                gen_clid(new);
        }
+       /*
+        * XXX: we should probably set this at creation time, and check
+        * for consistent minorversion use throughout:
+        */
+       new->cl_minorversion = 0;
        gen_callback(new, setclid, rpc_get_scope_id(sa));
        add_to_unconfirmed(new, strhashval);
        setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot;
@@@ -1807,7 -1928,8 +1928,8 @@@ nfsd4_setclientid_confirm(struct svc_rq
                        status = nfserr_clid_inuse;
                else {
                        atomic_set(&conf->cl_cb_set, 0);
-                       nfsd4_probe_callback(conf, &unconf->cl_cb_conn);
+                       nfsd4_change_callback(conf, &unconf->cl_cb_conn);
+                       nfsd4_probe_callback(conf);
                        expire_client(unconf);
                        status = nfs_ok;
  
                        }
                        move_to_confirmed(unconf);
                        conf = unconf;
-                       nfsd4_probe_callback(conf, &conf->cl_cb_conn);
+                       nfsd4_probe_callback(conf);
                        status = nfs_ok;
                }
        } else if ((!conf || (conf && !same_verf(&conf->cl_confirm, &confirm)))
@@@ -2944,7 -3066,11 +3066,11 @@@ nfs4_preprocess_stateid_op(struct nfsd4
        if (STALE_STATEID(stateid)) 
                goto out;
  
-       status = nfserr_bad_stateid;
+       /*
+        * We assume that any stateid that has the current boot time,
+        * but that we can't find, is expired:
+        */
+       status = nfserr_expired;
        if (is_delegation_stateid(stateid)) {
                dp = find_delegation_stateid(ino, stateid);
                if (!dp)
                stp = find_stateid(stateid, flags);
                if (!stp)
                        goto out;
+               status = nfserr_bad_stateid;
                if (nfs4_check_fh(current_fh, stp))
                        goto out;
                if (!stp->st_stateowner->so_confirmed)
@@@ -3038,8 -3165,9 +3165,9 @@@ nfs4_preprocess_seqid_op(struct nfsd4_c
                 * a replayed close:
                 */
                sop = search_close_lru(stateid->si_stateownerid, flags);
+               /* It's not stale; let's assume it's expired: */
                if (sop == NULL)
-                       return nfserr_bad_stateid;
+                       return nfserr_expired;
                *sopp = sop;
                goto check_replay;
        }
@@@ -3304,6 -3432,7 +3432,7 @@@ nfsd4_delegreturn(struct svc_rqst *rqst
        status = nfserr_bad_stateid;
        if (!is_delegation_stateid(stateid))
                goto out;
+       status = nfserr_expired;
        dp = find_delegation_stateid(inode, stateid);
        if (!dp)
                goto out;
@@@ -3895,7 -4024,7 +4024,7 @@@ check_for_locks(struct nfs4_file *filp
        struct inode *inode = filp->fi_inode;
        int status = 0;
  
 -      lock_kernel();
 +      lock_flocks();
        for (flpp = &inode->i_flock; *flpp != NULL; flpp = &(*flpp)->fl_next) {
                if ((*flpp)->fl_owner == (fl_owner_t)lowner) {
                        status = 1;
                }
        }
  out:
 -      unlock_kernel();
 +      unlock_flocks();
        return status;
  }
  
diff --combined fs/nfsd/nfsctl.c
@@@ -22,6 -22,7 +22,7 @@@
   */
  enum {
        NFSD_Root = 1,
+ #ifdef CONFIG_NFSD_DEPRECATED
        NFSD_Svc,
        NFSD_Add,
        NFSD_Del,
@@@ -29,6 -30,7 +30,7 @@@
        NFSD_Unexport,
        NFSD_Getfd,
        NFSD_Getfs,
+ #endif
        NFSD_List,
        NFSD_Export_features,
        NFSD_Fh,
@@@ -54,6 -56,7 +56,7 @@@
  /*
   * write() for these nodes.
   */
+ #ifdef CONFIG_NFSD_DEPRECATED
  static ssize_t write_svc(struct file *file, char *buf, size_t size);
  static ssize_t write_add(struct file *file, char *buf, size_t size);
  static ssize_t write_del(struct file *file, char *buf, size_t size);
@@@ -61,6 -64,7 +64,7 @@@ static ssize_t write_export(struct fil
  static ssize_t write_unexport(struct file *file, char *buf, size_t size);
  static ssize_t write_getfd(struct file *file, char *buf, size_t size);
  static ssize_t write_getfs(struct file *file, char *buf, size_t size);
+ #endif
  static ssize_t write_filehandle(struct file *file, char *buf, size_t size);
  static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size);
  static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size);
@@@ -76,6 -80,7 +80,7 @@@ static ssize_t write_recoverydir(struc
  #endif
  
  static ssize_t (*write_op[])(struct file *, char *, size_t) = {
+ #ifdef CONFIG_NFSD_DEPRECATED
        [NFSD_Svc] = write_svc,
        [NFSD_Add] = write_add,
        [NFSD_Del] = write_del,
@@@ -83,6 -88,7 +88,7 @@@
        [NFSD_Unexport] = write_unexport,
        [NFSD_Getfd] = write_getfd,
        [NFSD_Getfs] = write_getfs,
+ #endif
        [NFSD_Fh] = write_filehandle,
        [NFSD_FO_UnlockIP] = write_unlock_ip,
        [NFSD_FO_UnlockFS] = write_unlock_fs,
@@@ -121,6 -127,14 +127,14 @@@ static ssize_t nfsctl_transaction_write
  
  static ssize_t nfsctl_transaction_read(struct file *file, char __user *buf, size_t size, loff_t *pos)
  {
+       static int warned;
+       if (file->f_dentry->d_name.name[0] == '.' && !warned) {
+               printk(KERN_INFO
+                      "Warning: \"%s\" uses deprecated NFSD interface: %s."
+                      "  This will be removed in 2.6.40\n",
+                      current->comm, file->f_dentry->d_name.name);
+               warned = 1;
+       }
        if (! file->private_data) {
                /* An attempt to read a transaction file without writing
                 * causes a 0-byte write so that the file can return
@@@ -137,7 -151,6 +151,7 @@@ static const struct file_operations tra
        .write          = nfsctl_transaction_write,
        .read           = nfsctl_transaction_read,
        .release        = simple_transaction_release,
 +      .llseek         = default_llseek,
  };
  
  static int exports_open(struct inode *inode, struct file *file)
@@@ -187,6 -200,7 +201,7 @@@ static const struct file_operations poo
   * payload - write methods
   */
  
+ #ifdef CONFIG_NFSD_DEPRECATED
  /**
   * write_svc - Start kernel's NFSD server
   *
@@@ -402,7 -416,7 +417,7 @@@ static ssize_t write_getfs(struct file 
  
        ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6);
  
-       clp = auth_unix_lookup(&in6);
+       clp = auth_unix_lookup(&init_net, &in6);
        if (!clp)
                err = -EPERM;
        else {
@@@ -465,7 -479,7 +480,7 @@@ static ssize_t write_getfd(struct file 
  
        ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6);
  
-       clp = auth_unix_lookup(&in6);
+       clp = auth_unix_lookup(&init_net, &in6);
        if (!clp)
                err = -EPERM;
        else {
   out:
        return err;
  }
+ #endif /* CONFIG_NFSD_DEPRECATED */
  
  /**
   * write_unlock_ip - Release all locks used by a client
@@@ -1000,12 -1015,12 +1016,12 @@@ static ssize_t __write_ports_addxprt(ch
        if (err != 0)
                return err;
  
-       err = svc_create_xprt(nfsd_serv, transport,
+       err = svc_create_xprt(nfsd_serv, transport, &init_net,
                                PF_INET, port, SVC_SOCK_ANONYMOUS);
        if (err < 0)
                goto out_err;
  
-       err = svc_create_xprt(nfsd_serv, transport,
+       err = svc_create_xprt(nfsd_serv, transport, &init_net,
                                PF_INET6, port, SVC_SOCK_ANONYMOUS);
        if (err < 0 && err != -EAFNOSUPPORT)
                goto out_close;
@@@ -1356,6 -1371,7 +1372,7 @@@ static ssize_t write_recoverydir(struc
  static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
  {
        static struct tree_descr nfsd_files[] = {
+ #ifdef CONFIG_NFSD_DEPRECATED
                [NFSD_Svc] = {".svc", &transaction_ops, S_IWUSR},
                [NFSD_Add] = {".add", &transaction_ops, S_IWUSR},
                [NFSD_Del] = {".del", &transaction_ops, S_IWUSR},
                [NFSD_Unexport] = {".unexport", &transaction_ops, S_IWUSR},
                [NFSD_Getfd] = {".getfd", &transaction_ops, S_IWUSR|S_IRUSR},
                [NFSD_Getfs] = {".getfs", &transaction_ops, S_IWUSR|S_IRUSR},
+ #endif
                [NFSD_List] = {"exports", &exports_operations, S_IRUGO},
                [NFSD_Export_features] = {"export_features",
                                        &export_features_operations, S_IRUGO},
diff --combined include/linux/nfs4.h
@@@ -17,9 -17,7 +17,9 @@@
  
  #define NFS4_BITMAP_SIZE      2
  #define NFS4_VERIFIER_SIZE    8
 -#define NFS4_STATEID_SIZE     16
 +#define NFS4_STATEID_SEQID_SIZE 4
 +#define NFS4_STATEID_OTHER_SIZE 12
 +#define NFS4_STATEID_SIZE     (NFS4_STATEID_SEQID_SIZE + NFS4_STATEID_OTHER_SIZE)
  #define NFS4_FHSIZE           128
  #define NFS4_MAXPATHLEN               PATH_MAX
  #define NFS4_MAXNAMLEN                NAME_MAX
@@@ -63,6 -61,9 +63,9 @@@
  #define NFS4_SHARE_SIGNAL_DELEG_WHEN_RESRC_AVAIL      0x10000
  #define NFS4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED                0x20000
  
+ #define NFS4_CDFC4_FORE       0x1
+ #define NFS4_CDFC4_BACK 0x2
  #define NFS4_SET_TO_SERVER_TIME       0
  #define NFS4_SET_TO_CLIENT_TIME       1
  
@@@ -169,16 -170,7 +172,16 @@@ struct nfs4_acl 
  };
  
  typedef struct { char data[NFS4_VERIFIER_SIZE]; } nfs4_verifier;
 -typedef struct { char data[NFS4_STATEID_SIZE]; } nfs4_stateid;
 +
 +struct nfs41_stateid {
 +      __be32 seqid;
 +      char other[NFS4_STATEID_OTHER_SIZE];
 +} __attribute__ ((packed));
 +
 +typedef union {
 +      char data[NFS4_STATEID_SIZE];
 +      struct nfs41_stateid stateid;
 +} nfs4_stateid;
  
  enum nfs_opnum4 {
        OP_ACCESS = 3,
@@@ -482,8 -474,6 +485,8 @@@ enum lock_type4 
  #define FATTR4_WORD1_TIME_MODIFY        (1UL << 21)
  #define FATTR4_WORD1_TIME_MODIFY_SET    (1UL << 22)
  #define FATTR4_WORD1_MOUNTED_ON_FILEID  (1UL << 23)
 +#define FATTR4_WORD1_FS_LAYOUT_TYPES    (1UL << 30)
 +#define FATTR4_WORD2_LAYOUT_BLKSIZE     (1UL << 1)
  
  #define NFSPROC4_NULL 0
  #define NFSPROC4_COMPOUND 1
@@@ -545,8 -535,6 +548,8 @@@ enum 
        NFSPROC4_CLNT_SEQUENCE,
        NFSPROC4_CLNT_GET_LEASE_TIME,
        NFSPROC4_CLNT_RECLAIM_COMPLETE,
 +      NFSPROC4_CLNT_LAYOUTGET,
 +      NFSPROC4_CLNT_GETDEVICEINFO,
  };
  
  /* nfs41 types */
@@@ -565,49 -553,6 +568,49 @@@ enum state_protect_how4 
        SP4_SSV         = 2
  };
  
 +enum pnfs_layouttype {
 +      LAYOUT_NFSV4_1_FILES  = 1,
 +      LAYOUT_OSD2_OBJECTS = 2,
 +      LAYOUT_BLOCK_VOLUME = 3,
 +};
 +
 +/* used for both layout return and recall */
 +enum pnfs_layoutreturn_type {
 +      RETURN_FILE = 1,
 +      RETURN_FSID = 2,
 +      RETURN_ALL  = 3
 +};
 +
 +enum pnfs_iomode {
 +      IOMODE_READ = 1,
 +      IOMODE_RW = 2,
 +      IOMODE_ANY = 3,
 +};
 +
 +enum pnfs_notify_deviceid_type4 {
 +      NOTIFY_DEVICEID4_CHANGE = 1 << 1,
 +      NOTIFY_DEVICEID4_DELETE = 1 << 2,
 +};
 +
 +#define NFL4_UFLG_MASK                        0x0000003F
 +#define NFL4_UFLG_DENSE                       0x00000001
 +#define NFL4_UFLG_COMMIT_THRU_MDS     0x00000002
 +#define NFL4_UFLG_STRIPE_UNIT_SIZE_MASK       0xFFFFFFC0
 +
 +/* Encoded in the loh_body field of type layouthint4 */
 +enum filelayout_hint_care4 {
 +      NFLH4_CARE_DENSE                = NFL4_UFLG_DENSE,
 +      NFLH4_CARE_COMMIT_THRU_MDS      = NFL4_UFLG_COMMIT_THRU_MDS,
 +      NFLH4_CARE_STRIPE_UNIT_SIZE     = 0x00000040,
 +      NFLH4_CARE_STRIPE_COUNT         = 0x00000080
 +};
 +
 +#define NFS4_DEVICEID4_SIZE 16
 +
 +struct nfs4_deviceid {
 +      char data[NFS4_DEVICEID4_SIZE];
 +};
 +
  #endif
  #endif
  
@@@ -102,6 -102,7 +102,7 @@@ struct rpc_procinfo 
  #ifdef __KERNEL__
  
  struct rpc_create_args {
+       struct net              *net;
        int                     protocol;
        struct sockaddr         *address;
        size_t                  addrsize;
@@@ -137,6 -138,7 +138,6 @@@ int                rpcb_register(u32, u32, int, unsig
  int           rpcb_v4_register(const u32 program, const u32 version,
                                 const struct sockaddr *address,
                                 const char *netid);
 -int           rpcb_getport_sync(struct sockaddr_in *, u32, u32, int);
  void          rpcb_getport_async(struct rpc_task *);
  
  void          rpc_call_start(struct rpc_task *);
diff --combined net/socket.c
@@@ -209,8 -209,8 +209,8 @@@ int move_addr_to_kernel(void __user *ua
   *    specified. Zero is returned for a success.
   */
  
 -int move_addr_to_user(struct sockaddr *kaddr, int klen, void __user *uaddr,
 -                    int __user *ulen)
 +static int move_addr_to_user(struct sockaddr *kaddr, int klen,
 +                           void __user *uaddr, int __user *ulen)
  {
        int err;
        int len;
@@@ -502,7 -502,6 +502,7 @@@ static int sock_no_open(struct inode *i
  const struct file_operations bad_sock_fops = {
        .owner = THIS_MODULE,
        .open = sock_no_open,
 +      .llseek = noop_llseek,
  };
  
  /**
@@@ -536,13 -535,14 +536,13 @@@ void sock_release(struct socket *sock
  }
  EXPORT_SYMBOL(sock_release);
  
 -int sock_tx_timestamp(struct msghdr *msg, struct sock *sk,
 -                    union skb_shared_tx *shtx)
 +int sock_tx_timestamp(struct sock *sk, __u8 *tx_flags)
  {
 -      shtx->flags = 0;
 +      *tx_flags = 0;
        if (sock_flag(sk, SOCK_TIMESTAMPING_TX_HARDWARE))
 -              shtx->hardware = 1;
 +              *tx_flags |= SKBTX_HW_TSTAMP;
        if (sock_flag(sk, SOCK_TIMESTAMPING_TX_SOFTWARE))
 -              shtx->software = 1;
 +              *tx_flags |= SKBTX_SW_TSTAMP;
        return 0;
  }
  EXPORT_SYMBOL(sock_tx_timestamp);
@@@ -662,8 -662,7 +662,8 @@@ void __sock_recv_timestamp(struct msghd
  }
  EXPORT_SYMBOL_GPL(__sock_recv_timestamp);
  
 -inline void sock_recv_drops(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
 +static inline void sock_recv_drops(struct msghdr *msg, struct sock *sk,
 +                                 struct sk_buff *skb)
  {
        if (sock_flag(sk, SOCK_RXQ_OVFL) && skb && skb->dropcount)
                put_cmsg(msg, SOL_SOCKET, SO_RXQ_OVFL,
@@@ -1145,7 -1144,7 +1145,7 @@@ call_kill
  }
  EXPORT_SYMBOL(sock_wake_async);
  
static int __sock_create(struct net *net, int family, int type, int protocol,
+ int __sock_create(struct net *net, int family, int type, int protocol,
                         struct socket **res, int kern)
  {
        int err;
@@@ -1257,6 -1256,7 +1257,7 @@@ out_release
        rcu_read_unlock();
        goto out_sock_release;
  }
+ EXPORT_SYMBOL(__sock_create);
  
  int sock_create(int family, int type, int protocol, struct socket **res)
  {
@@@ -1920,8 -1920,7 +1921,8 @@@ SYSCALL_DEFINE3(sendmsg, int, fd, struc
                 * Afterwards, it will be a kernel pointer. Thus the compiler-assisted
                 * checking falls down on this.
                 */
 -              if (copy_from_user(ctl_buf, (void __user *)msg_sys.msg_control,
 +              if (copy_from_user(ctl_buf,
 +                                 (void __user __force *)msg_sys.msg_control,
                                   ctl_len))
                        goto out_freectl;
                msg_sys.msg_control = ctl_buf;
@@@ -3056,19 -3055,14 +3057,19 @@@ int kernel_getsockopt(struct socket *so
                        char *optval, int *optlen)
  {
        mm_segment_t oldfs = get_fs();
 +      char __user *uoptval;
 +      int __user *uoptlen;
        int err;
  
 +      uoptval = (char __user __force *) optval;
 +      uoptlen = (int __user __force *) optlen;
 +
        set_fs(KERNEL_DS);
        if (level == SOL_SOCKET)
 -              err = sock_getsockopt(sock, level, optname, optval, optlen);
 +              err = sock_getsockopt(sock, level, optname, uoptval, uoptlen);
        else
 -              err = sock->ops->getsockopt(sock, level, optname, optval,
 -                                          optlen);
 +              err = sock->ops->getsockopt(sock, level, optname, uoptval,
 +                                          uoptlen);
        set_fs(oldfs);
        return err;
  }
@@@ -3078,16 -3072,13 +3079,16 @@@ int kernel_setsockopt(struct socket *so
                        char *optval, unsigned int optlen)
  {
        mm_segment_t oldfs = get_fs();
 +      char __user *uoptval;
        int err;
  
 +      uoptval = (char __user __force *) optval;
 +
        set_fs(KERNEL_DS);
        if (level == SOL_SOCKET)
 -              err = sock_setsockopt(sock, level, optname, optval, optlen);
 +              err = sock_setsockopt(sock, level, optname, uoptval, optlen);
        else
 -              err = sock->ops->setsockopt(sock, level, optname, optval,
 +              err = sock->ops->setsockopt(sock, level, optname, uoptval,
                                            optlen);
        set_fs(oldfs);
        return err;
diff --combined net/sunrpc/auth.c
@@@ -595,7 -595,7 +595,7 @@@ rpcauth_unwrap_resp(struct rpc_task *ta
  int
  rpcauth_refreshcred(struct rpc_task *task)
  {
 -      struct rpc_cred *cred = task->tk_rqstp->rq_cred;
 +      struct rpc_cred *cred;
        int err;
  
        cred = task->tk_rqstp->rq_cred;
@@@ -658,7 -658,7 +658,7 @@@ out1
        return err;
  }
  
- void __exit rpcauth_remove_module(void)
+ void rpcauth_remove_module(void)
  {
        rpc_destroy_authunix();
        rpc_destroy_generic_auth();
diff --combined net/sunrpc/cache.c
  #include <linux/workqueue.h>
  #include <linux/mutex.h>
  #include <linux/pagemap.h>
 -#include <linux/smp_lock.h>
  #include <asm/ioctls.h>
  #include <linux/sunrpc/types.h>
  #include <linux/sunrpc/cache.h>
  #include <linux/sunrpc/stats.h>
  #include <linux/sunrpc/rpc_pipe_fs.h>
+ #include "netns.h"
  
  #define        RPCDBG_FACILITY RPCDBG_CACHE
  
- static int cache_defer_req(struct cache_req *req, struct cache_head *item);
+ static void cache_defer_req(struct cache_req *req, struct cache_head *item);
  static void cache_revisit_request(struct cache_head *item);
  
  static void cache_init(struct cache_head *h)
  {
-       time_t now = get_seconds();
+       time_t now = seconds_since_boot();
        h->next = NULL;
        h->flags = 0;
        kref_init(&h->ref);
@@@ -51,7 -53,7 +52,7 @@@
  
  static inline int cache_is_expired(struct cache_detail *detail, struct cache_head *h)
  {
-       return  (h->expiry_time < get_seconds()) ||
+       return  (h->expiry_time < seconds_since_boot()) ||
                (detail->flush_time > h->last_refresh);
  }
  
@@@ -126,7 -128,7 +127,7 @@@ static void cache_dequeue(struct cache_
  static void cache_fresh_locked(struct cache_head *head, time_t expiry)
  {
        head->expiry_time = expiry;
-       head->last_refresh = get_seconds();
+       head->last_refresh = seconds_since_boot();
        set_bit(CACHE_VALID, &head->flags);
  }
  
@@@ -237,7 -239,7 +238,7 @@@ int cache_check(struct cache_detail *de
  
        /* now see if we want to start an upcall */
        refresh_age = (h->expiry_time - h->last_refresh);
-       age = get_seconds() - h->last_refresh;
+       age = seconds_since_boot() - h->last_refresh;
  
        if (rqstp == NULL) {
                if (rv == -EAGAIN)
                                cache_revisit_request(h);
                                if (rv == -EAGAIN) {
                                        set_bit(CACHE_NEGATIVE, &h->flags);
-                                       cache_fresh_locked(h, get_seconds()+CACHE_NEW_EXPIRY);
+                                       cache_fresh_locked(h, seconds_since_boot()+CACHE_NEW_EXPIRY);
                                        cache_fresh_unlocked(h, detail);
                                        rv = -ENOENT;
                                }
        }
  
        if (rv == -EAGAIN) {
-               if (cache_defer_req(rqstp, h) < 0) {
+               cache_defer_req(rqstp, h);
+               if (!test_bit(CACHE_PENDING, &h->flags)) {
                        /* Request is not deferred */
                        rv = cache_is_valid(detail, h);
                        if (rv == -EAGAIN)
@@@ -387,11 -390,11 +389,11 @@@ static int cache_clean(void
                        return -1;
                }
                current_detail = list_entry(next, struct cache_detail, others);
-               if (current_detail->nextcheck > get_seconds())
+               if (current_detail->nextcheck > seconds_since_boot())
                        current_index = current_detail->hash_size;
                else {
                        current_index = 0;
-                       current_detail->nextcheck = get_seconds()+30*60;
+                       current_detail->nextcheck = seconds_since_boot()+30*60;
                }
        }
  
@@@ -476,7 -479,7 +478,7 @@@ EXPORT_SYMBOL_GPL(cache_flush)
  void cache_purge(struct cache_detail *detail)
  {
        detail->flush_time = LONG_MAX;
-       detail->nextcheck = get_seconds();
+       detail->nextcheck = seconds_since_boot();
        cache_flush();
        detail->flush_time = 1;
  }
@@@ -505,81 -508,155 +507,155 @@@ EXPORT_SYMBOL_GPL(cache_purge)
  
  static DEFINE_SPINLOCK(cache_defer_lock);
  static LIST_HEAD(cache_defer_list);
- static struct list_head cache_defer_hash[DFR_HASHSIZE];
+ static struct hlist_head cache_defer_hash[DFR_HASHSIZE];
  static int cache_defer_cnt;
  
- static int cache_defer_req(struct cache_req *req, struct cache_head *item)
+ static void __unhash_deferred_req(struct cache_deferred_req *dreq)
+ {
+       hlist_del_init(&dreq->hash);
+       if (!list_empty(&dreq->recent)) {
+               list_del_init(&dreq->recent);
+               cache_defer_cnt--;
+       }
+ }
+ static void __hash_deferred_req(struct cache_deferred_req *dreq, struct cache_head *item)
  {
-       struct cache_deferred_req *dreq, *discard;
        int hash = DFR_HASH(item);
  
-       if (cache_defer_cnt >= DFR_MAX) {
-               /* too much in the cache, randomly drop this one,
-                * or continue and drop the oldest below
-                */
-               if (net_random()&1)
-                       return -ENOMEM;
-       }
-       dreq = req->defer(req);
-       if (dreq == NULL)
-               return -ENOMEM;
+       INIT_LIST_HEAD(&dreq->recent);
+       hlist_add_head(&dreq->hash, &cache_defer_hash[hash]);
+ }
+ static void setup_deferral(struct cache_deferred_req *dreq,
+                          struct cache_head *item,
+                          int count_me)
+ {
  
        dreq->item = item;
  
        spin_lock(&cache_defer_lock);
  
-       list_add(&dreq->recent, &cache_defer_list);
-       if (cache_defer_hash[hash].next == NULL)
-               INIT_LIST_HEAD(&cache_defer_hash[hash]);
-       list_add(&dreq->hash, &cache_defer_hash[hash]);
+       __hash_deferred_req(dreq, item);
  
-       /* it is in, now maybe clean up */
-       discard = NULL;
-       if (++cache_defer_cnt > DFR_MAX) {
-               discard = list_entry(cache_defer_list.prev,
-                                    struct cache_deferred_req, recent);
-               list_del_init(&discard->recent);
-               list_del_init(&discard->hash);
-               cache_defer_cnt--;
+       if (count_me) {
+               cache_defer_cnt++;
+               list_add(&dreq->recent, &cache_defer_list);
        }
        spin_unlock(&cache_defer_lock);
  
+ }
+ struct thread_deferred_req {
+       struct cache_deferred_req handle;
+       struct completion completion;
+ };
+ static void cache_restart_thread(struct cache_deferred_req *dreq, int too_many)
+ {
+       struct thread_deferred_req *dr =
+               container_of(dreq, struct thread_deferred_req, handle);
+       complete(&dr->completion);
+ }
+ static void cache_wait_req(struct cache_req *req, struct cache_head *item)
+ {
+       struct thread_deferred_req sleeper;
+       struct cache_deferred_req *dreq = &sleeper.handle;
+       sleeper.completion = COMPLETION_INITIALIZER_ONSTACK(sleeper.completion);
+       dreq->revisit = cache_restart_thread;
+       setup_deferral(dreq, item, 0);
+       if (!test_bit(CACHE_PENDING, &item->flags) ||
+           wait_for_completion_interruptible_timeout(
+                   &sleeper.completion, req->thread_wait) <= 0) {
+               /* The completion wasn't completed, so we need
+                * to clean up
+                */
+               spin_lock(&cache_defer_lock);
+               if (!hlist_unhashed(&sleeper.handle.hash)) {
+                       __unhash_deferred_req(&sleeper.handle);
+                       spin_unlock(&cache_defer_lock);
+               } else {
+                       /* cache_revisit_request already removed
+                        * this from the hash table, but hasn't
+                        * called ->revisit yet.  It will very soon
+                        * and we need to wait for it.
+                        */
+                       spin_unlock(&cache_defer_lock);
+                       wait_for_completion(&sleeper.completion);
+               }
+       }
+ }
+ static void cache_limit_defers(void)
+ {
+       /* Make sure we haven't exceed the limit of allowed deferred
+        * requests.
+        */
+       struct cache_deferred_req *discard = NULL;
+       if (cache_defer_cnt <= DFR_MAX)
+               return;
+       spin_lock(&cache_defer_lock);
+       /* Consider removing either the first or the last */
+       if (cache_defer_cnt > DFR_MAX) {
+               if (net_random() & 1)
+                       discard = list_entry(cache_defer_list.next,
+                                            struct cache_deferred_req, recent);
+               else
+                       discard = list_entry(cache_defer_list.prev,
+                                            struct cache_deferred_req, recent);
+               __unhash_deferred_req(discard);
+       }
+       spin_unlock(&cache_defer_lock);
        if (discard)
-               /* there was one too many */
                discard->revisit(discard, 1);
+ }
  
-       if (!test_bit(CACHE_PENDING, &item->flags)) {
-               /* must have just been validated... */
-               cache_revisit_request(item);
-               return -EAGAIN;
+ static void cache_defer_req(struct cache_req *req, struct cache_head *item)
+ {
+       struct cache_deferred_req *dreq;
+       if (req->thread_wait) {
+               cache_wait_req(req, item);
+               if (!test_bit(CACHE_PENDING, &item->flags))
+                       return;
        }
-       return 0;
+       dreq = req->defer(req);
+       if (dreq == NULL)
+               return;
+       setup_deferral(dreq, item, 1);
+       if (!test_bit(CACHE_PENDING, &item->flags))
+               /* Bit could have been cleared before we managed to
+                * set up the deferral, so need to revisit just in case
+                */
+               cache_revisit_request(item);
+       cache_limit_defers();
  }
  
  static void cache_revisit_request(struct cache_head *item)
  {
        struct cache_deferred_req *dreq;
        struct list_head pending;
-       struct list_head *lp;
+       struct hlist_node *lp, *tmp;
        int hash = DFR_HASH(item);
  
        INIT_LIST_HEAD(&pending);
        spin_lock(&cache_defer_lock);
  
-       lp = cache_defer_hash[hash].next;
-       if (lp) {
-               while (lp != &cache_defer_hash[hash]) {
-                       dreq = list_entry(lp, struct cache_deferred_req, hash);
-                       lp = lp->next;
-                       if (dreq->item == item) {
-                               list_del_init(&dreq->hash);
-                               list_move(&dreq->recent, &pending);
-                               cache_defer_cnt--;
-                       }
+       hlist_for_each_entry_safe(dreq, lp, tmp, &cache_defer_hash[hash], hash)
+               if (dreq->item == item) {
+                       __unhash_deferred_req(dreq);
+                       list_add(&dreq->recent, &pending);
                }
-       }
        spin_unlock(&cache_defer_lock);
  
        while (!list_empty(&pending)) {
@@@ -600,9 -677,8 +676,8 @@@ void cache_clean_deferred(void *owner
  
        list_for_each_entry_safe(dreq, tmp, &cache_defer_list, recent) {
                if (dreq->owner == owner) {
-                       list_del_init(&dreq->hash);
-                       list_move(&dreq->recent, &pending);
-                       cache_defer_cnt--;
+                       __unhash_deferred_req(dreq);
+                       list_add(&dreq->recent, &pending);
                }
        }
        spin_unlock(&cache_defer_lock);
@@@ -901,7 -977,7 +976,7 @@@ static int cache_release(struct inode *
                filp->private_data = NULL;
                kfree(rp);
  
-               cd->last_close = get_seconds();
+               cd->last_close = seconds_since_boot();
                atomic_dec(&cd->readers);
        }
        module_put(cd->owner);
@@@ -1014,6 -1090,23 +1089,23 @@@ static void warn_no_listener(struct cac
        }
  }
  
+ static bool cache_listeners_exist(struct cache_detail *detail)
+ {
+       if (atomic_read(&detail->readers))
+               return true;
+       if (detail->last_close == 0)
+               /* This cache was never opened */
+               return false;
+       if (detail->last_close < seconds_since_boot() - 30)
+               /*
+                * We allow for the possibility that someone might
+                * restart a userspace daemon without restarting the
+                * server; but after 30 seconds, we give up.
+                */
+                return false;
+       return true;
+ }
  /*
   * register an upcall request to user-space and queue it up for read() by the
   * upcall daemon.
@@@ -1032,10 -1125,9 +1124,9 @@@ int sunrpc_cache_pipe_upcall(struct cac
        char *bp;
        int len;
  
-       if (atomic_read(&detail->readers) == 0 &&
-           detail->last_close < get_seconds() - 30) {
-                       warn_no_listener(detail);
-                       return -EINVAL;
+       if (!cache_listeners_exist(detail)) {
+               warn_no_listener(detail);
+               return -EINVAL;
        }
  
        buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
@@@ -1094,13 -1186,19 +1185,19 @@@ int qword_get(char **bpp, char *dest, i
        if (bp[0] == '\\' && bp[1] == 'x') {
                /* HEX STRING */
                bp += 2;
-               while (isxdigit(bp[0]) && isxdigit(bp[1]) && len < bufsize) {
-                       int byte = isdigit(*bp) ? *bp-'0' : toupper(*bp)-'A'+10;
-                       bp++;
-                       byte <<= 4;
-                       byte |= isdigit(*bp) ? *bp-'0' : toupper(*bp)-'A'+10;
-                       *dest++ = byte;
-                       bp++;
+               while (len < bufsize) {
+                       int h, l;
+                       h = hex_to_bin(bp[0]);
+                       if (h < 0)
+                               break;
+                       l = hex_to_bin(bp[1]);
+                       if (l < 0)
+                               break;
+                       *dest++ = (h << 4) | l;
+                       bp += 2;
                        len++;
                }
        } else {
@@@ -1218,7 -1316,8 +1315,8 @@@ static int c_show(struct seq_file *m, v
  
        ifdebug(CACHE)
                seq_printf(m, "# expiry=%ld refcnt=%d flags=%lx\n",
-                          cp->expiry_time, atomic_read(&cp->ref.refcount), cp->flags);
+                          convert_to_wallclock(cp->expiry_time),
+                          atomic_read(&cp->ref.refcount), cp->flags);
        cache_get(cp);
        if (cache_check(cd, cp, NULL))
                /* cache_check does a cache_put on failure */
@@@ -1284,7 -1383,7 +1382,7 @@@ static ssize_t read_flush(struct file *
        unsigned long p = *ppos;
        size_t len;
  
-       sprintf(tbuf, "%lu\n", cd->flush_time);
+       sprintf(tbuf, "%lu\n", convert_to_wallclock(cd->flush_time));
        len = strlen(tbuf);
        if (p >= len)
                return 0;
@@@ -1302,19 -1401,20 +1400,20 @@@ static ssize_t write_flush(struct file 
                           struct cache_detail *cd)
  {
        char tbuf[20];
-       char *ep;
-       long flushtime;
+       char *bp, *ep;
        if (*ppos || count > sizeof(tbuf)-1)
                return -EINVAL;
        if (copy_from_user(tbuf, buf, count))
                return -EFAULT;
        tbuf[count] = 0;
-       flushtime = simple_strtoul(tbuf, &ep, 0);
+       simple_strtoul(tbuf, &ep, 0);
        if (*ep && *ep != '\n')
                return -EINVAL;
  
-       cd->flush_time = flushtime;
-       cd->nextcheck = get_seconds();
+       bp = tbuf;
+       cd->flush_time = get_expiry(&bp);
+       cd->nextcheck = seconds_since_boot();
        cache_flush();
  
        *ppos += count;
@@@ -1347,10 -1447,15 +1446,10 @@@ static unsigned int cache_poll_procfs(s
  static long cache_ioctl_procfs(struct file *filp,
                               unsigned int cmd, unsigned long arg)
  {
 -      long ret;
        struct inode *inode = filp->f_path.dentry->d_inode;
        struct cache_detail *cd = PDE(inode)->data;
  
 -      lock_kernel();
 -      ret = cache_ioctl(inode, filp, cmd, arg, cd);
 -      unlock_kernel();
 -
 -      return ret;
 +      return cache_ioctl(inode, filp, cmd, arg, cd);
  }
  
  static int cache_open_procfs(struct inode *inode, struct file *filp)
@@@ -1435,11 -1540,12 +1534,13 @@@ static const struct file_operations cac
        .read           = read_flush_procfs,
        .write          = write_flush_procfs,
        .release        = release_flush_procfs,
 +      .llseek         = no_llseek,
  };
  
- static void remove_cache_proc_entries(struct cache_detail *cd)
+ static void remove_cache_proc_entries(struct cache_detail *cd, struct net *net)
  {
+       struct sunrpc_net *sn;
        if (cd->u.procfs.proc_ent == NULL)
                return;
        if (cd->u.procfs.flush_ent)
        if (cd->u.procfs.content_ent)
                remove_proc_entry("content", cd->u.procfs.proc_ent);
        cd->u.procfs.proc_ent = NULL;
-       remove_proc_entry(cd->name, proc_net_rpc);
+       sn = net_generic(net, sunrpc_net_id);
+       remove_proc_entry(cd->name, sn->proc_net_rpc);
  }
  
  #ifdef CONFIG_PROC_FS
- static int create_cache_proc_entries(struct cache_detail *cd)
+ static int create_cache_proc_entries(struct cache_detail *cd, struct net *net)
  {
        struct proc_dir_entry *p;
+       struct sunrpc_net *sn;
  
-       cd->u.procfs.proc_ent = proc_mkdir(cd->name, proc_net_rpc);
+       sn = net_generic(net, sunrpc_net_id);
+       cd->u.procfs.proc_ent = proc_mkdir(cd->name, sn->proc_net_rpc);
        if (cd->u.procfs.proc_ent == NULL)
                goto out_nomem;
        cd->u.procfs.channel_ent = NULL;
        }
        return 0;
  out_nomem:
-       remove_cache_proc_entries(cd);
+       remove_cache_proc_entries(cd, net);
        return -ENOMEM;
  }
  #else /* CONFIG_PROC_FS */
- static int create_cache_proc_entries(struct cache_detail *cd)
+ static int create_cache_proc_entries(struct cache_detail *cd, struct net *net)
  {
        return 0;
  }
@@@ -1503,23 -1612,33 +1607,33 @@@ void __init cache_initialize(void
        INIT_DELAYED_WORK_DEFERRABLE(&cache_cleaner, do_cache_clean);
  }
  
- int cache_register(struct cache_detail *cd)
+ int cache_register_net(struct cache_detail *cd, struct net *net)
  {
        int ret;
  
        sunrpc_init_cache_detail(cd);
-       ret = create_cache_proc_entries(cd);
+       ret = create_cache_proc_entries(cd, net);
        if (ret)
                sunrpc_destroy_cache_detail(cd);
        return ret;
  }
+ int cache_register(struct cache_detail *cd)
+ {
+       return cache_register_net(cd, &init_net);
+ }
  EXPORT_SYMBOL_GPL(cache_register);
  
- void cache_unregister(struct cache_detail *cd)
+ void cache_unregister_net(struct cache_detail *cd, struct net *net)
  {
-       remove_cache_proc_entries(cd);
+       remove_cache_proc_entries(cd, net);
        sunrpc_destroy_cache_detail(cd);
  }
+ void cache_unregister(struct cache_detail *cd)
+ {
+       cache_unregister_net(cd, &init_net);
+ }
  EXPORT_SYMBOL_GPL(cache_unregister);
  
  static ssize_t cache_read_pipefs(struct file *filp, char __user *buf,
@@@ -1550,8 -1669,13 +1664,8 @@@ static long cache_ioctl_pipefs(struct f
  {
        struct inode *inode = filp->f_dentry->d_inode;
        struct cache_detail *cd = RPC_I(inode)->private;
 -      long ret;
  
 -      lock_kernel();
 -      ret = cache_ioctl(inode, filp, cmd, arg, cd);
 -      unlock_kernel();
 -
 -      return ret;
 +      return cache_ioctl(inode, filp, cmd, arg, cd);
  }
  
  static int cache_open_pipefs(struct inode *inode, struct file *filp)
@@@ -1636,7 -1760,6 +1750,7 @@@ const struct file_operations cache_flus
        .read           = read_flush_pipefs,
        .write          = write_flush_pipefs,
        .release        = release_flush_pipefs,
 +      .llseek         = no_llseek,
  };
  
  int sunrpc_cache_register_pipefs(struct dentry *parent,
diff --combined net/sunrpc/clnt.c
@@@ -284,6 -284,7 +284,7 @@@ struct rpc_clnt *rpc_create(struct rpc_
        struct rpc_xprt *xprt;
        struct rpc_clnt *clnt;
        struct xprt_create xprtargs = {
+               .net = args->net,
                .ident = args->protocol,
                .srcaddr = args->saddress,
                .dstaddr = args->address,
@@@ -1675,7 -1676,7 +1676,7 @@@ rpc_verify_header(struct rpc_task *task
                        rpcauth_invalcred(task);
                        /* Ensure we obtain a new XID! */
                        xprt_release(task);
 -                      task->tk_action = call_refresh;
 +                      task->tk_action = call_reserve;
                        goto out_retry;
                case RPC_AUTH_BADCRED:
                case RPC_AUTH_BADVERF:
diff --combined net/sunrpc/rpcb_clnt.c
@@@ -177,6 -177,7 +177,7 @@@ static DEFINE_MUTEX(rpcb_create_local_m
  static int rpcb_create_local(void)
  {
        struct rpc_create_args args = {
+               .net            = &init_net,
                .protocol       = XPRT_TRANSPORT_TCP,
                .address        = (struct sockaddr *)&rpcb_inaddr_loopback,
                .addrsize       = sizeof(rpcb_inaddr_loopback),
         */
        clnt4 = rpc_bind_new_program(clnt, &rpcb_program, RPCBVERS_4);
        if (IS_ERR(clnt4)) {
 -              dprintk("RPC:       failed to create local rpcbind v4 "
 -                              "cleint (errno %ld).\n", PTR_ERR(clnt4));
 +              dprintk("RPC:       failed to bind second program to "
 +                              "rpcbind v4 client (errno %ld).\n",
 +                              PTR_ERR(clnt4));
                clnt4 = NULL;
        }
  
@@@ -229,6 -229,7 +230,7 @@@ static struct rpc_clnt *rpcb_create(cha
                                    size_t salen, int proto, u32 version)
  {
        struct rpc_create_args args = {
+               .net            = &init_net,
                .protocol       = proto,
                .address        = srvaddr,
                .addrsize       = salen,
                ((struct sockaddr_in6 *)srvaddr)->sin6_port = htons(RPCBIND_PORT);
                break;
        default:
-               return NULL;
+               return ERR_PTR(-EAFNOSUPPORT);
        }
  
        return rpc_create(&args);
@@@ -476,6 -477,57 +478,6 @@@ int rpcb_v4_register(const u32 program
        return -EAFNOSUPPORT;
  }
  
 -/**
 - * rpcb_getport_sync - obtain the port for an RPC service on a given host
 - * @sin: address of remote peer
 - * @prog: RPC program number to bind
 - * @vers: RPC version number to bind
 - * @prot: transport protocol to use to make this request
 - *
 - * Return value is the requested advertised port number,
 - * or a negative errno value.
 - *
 - * Called from outside the RPC client in a synchronous task context.
 - * Uses default timeout parameters specified by underlying transport.
 - *
 - * XXX: Needs to support IPv6
 - */
 -int rpcb_getport_sync(struct sockaddr_in *sin, u32 prog, u32 vers, int prot)
 -{
 -      struct rpcbind_args map = {
 -              .r_prog         = prog,
 -              .r_vers         = vers,
 -              .r_prot         = prot,
 -              .r_port         = 0,
 -      };
 -      struct rpc_message msg = {
 -              .rpc_proc       = &rpcb_procedures2[RPCBPROC_GETPORT],
 -              .rpc_argp       = &map,
 -              .rpc_resp       = &map,
 -      };
 -      struct rpc_clnt *rpcb_clnt;
 -      int status;
 -
 -      dprintk("RPC:       %s(%pI4, %u, %u, %d)\n",
 -              __func__, &sin->sin_addr.s_addr, prog, vers, prot);
 -
 -      rpcb_clnt = rpcb_create(NULL, (struct sockaddr *)sin,
 -                              sizeof(*sin), prot, RPCBVERS_2);
 -      if (IS_ERR(rpcb_clnt))
 -              return PTR_ERR(rpcb_clnt);
 -
 -      status = rpc_call_sync(rpcb_clnt, &msg, 0);
 -      rpc_shutdown_client(rpcb_clnt);
 -
 -      if (status >= 0) {
 -              if (map.r_port != 0)
 -                      return map.r_port;
 -              status = -EACCES;
 -      }
 -      return status;
 -}
 -EXPORT_SYMBOL_GPL(rpcb_getport_sync);
 -
  static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt, struct rpcbind_args *map, struct rpc_procinfo *proc)
  {
        struct rpc_message msg = {
diff --combined net/sunrpc/xprtsock.c
@@@ -774,8 -774,7 +774,7 @@@ static void xs_destroy(struct rpc_xprt 
  
        xs_close(xprt);
        xs_free_peer_addresses(xprt);
-       kfree(xprt->slot);
-       kfree(xprt);
+       xprt_free(xprt);
        module_put(THIS_MODULE);
  }
  
@@@ -800,7 -799,7 +799,7 @@@ static void xs_udp_data_ready(struct so
        u32 _xid;
        __be32 *xp;
  
 -      read_lock(&sk->sk_callback_lock);
 +      read_lock_bh(&sk->sk_callback_lock);
        dprintk("RPC:       xs_udp_data_ready...\n");
        if (!(xprt = xprt_from_sock(sk)))
                goto out;
   dropit:
        skb_free_datagram(sk, skb);
   out:
 -      read_unlock(&sk->sk_callback_lock);
 +      read_unlock_bh(&sk->sk_callback_lock);
  }
  
  static inline void xs_tcp_read_fraghdr(struct rpc_xprt *xprt, struct xdr_skb_reader *desc)
@@@ -1229,7 -1228,7 +1228,7 @@@ static void xs_tcp_data_ready(struct so
  
        dprintk("RPC:       xs_tcp_data_ready...\n");
  
 -      read_lock(&sk->sk_callback_lock);
 +      read_lock_bh(&sk->sk_callback_lock);
        if (!(xprt = xprt_from_sock(sk)))
                goto out;
        if (xprt->shutdown)
                read = tcp_read_sock(sk, &rd_desc, xs_tcp_data_recv);
        } while (read > 0);
  out:
 -      read_unlock(&sk->sk_callback_lock);
 +      read_unlock_bh(&sk->sk_callback_lock);
  }
  
  /*
@@@ -1301,7 -1300,7 +1300,7 @@@ static void xs_tcp_state_change(struct 
  {
        struct rpc_xprt *xprt;
  
 -      read_lock(&sk->sk_callback_lock);
 +      read_lock_bh(&sk->sk_callback_lock);
        if (!(xprt = xprt_from_sock(sk)))
                goto out;
        dprintk("RPC:       xs_tcp_state_change client %p...\n", xprt);
  
        switch (sk->sk_state) {
        case TCP_ESTABLISHED:
 -              spin_lock_bh(&xprt->transport_lock);
 +              spin_lock(&xprt->transport_lock);
                if (!xprt_test_and_set_connected(xprt)) {
                        struct sock_xprt *transport = container_of(xprt,
                                        struct sock_xprt, xprt);
  
                        xprt_wake_pending_tasks(xprt, -EAGAIN);
                }
 -              spin_unlock_bh(&xprt->transport_lock);
 +              spin_unlock(&xprt->transport_lock);
                break;
        case TCP_FIN_WAIT1:
                /* The client initiated a shutdown of the socket */
                xs_sock_mark_closed(xprt);
        }
   out:
 -      read_unlock(&sk->sk_callback_lock);
 +      read_unlock_bh(&sk->sk_callback_lock);
  }
  
  /**
@@@ -1376,7 -1375,7 +1375,7 @@@ static void xs_error_report(struct soc
  {
        struct rpc_xprt *xprt;
  
 -      read_lock(&sk->sk_callback_lock);
 +      read_lock_bh(&sk->sk_callback_lock);
        if (!(xprt = xprt_from_sock(sk)))
                goto out;
        dprintk("RPC:       %s client %p...\n"
                        __func__, xprt, sk->sk_err);
        xprt_wake_pending_tasks(xprt, -EAGAIN);
  out:
 -      read_unlock(&sk->sk_callback_lock);
 +      read_unlock_bh(&sk->sk_callback_lock);
  }
  
  static void xs_write_space(struct sock *sk)
   */
  static void xs_udp_write_space(struct sock *sk)
  {
 -      read_lock(&sk->sk_callback_lock);
 +      read_lock_bh(&sk->sk_callback_lock);
  
        /* from net/core/sock.c:sock_def_write_space */
        if (sock_writeable(sk))
                xs_write_space(sk);
  
 -      read_unlock(&sk->sk_callback_lock);
 +      read_unlock_bh(&sk->sk_callback_lock);
  }
  
  /**
   */
  static void xs_tcp_write_space(struct sock *sk)
  {
 -      read_lock(&sk->sk_callback_lock);
 +      read_lock_bh(&sk->sk_callback_lock);
  
        /* from net/core/stream.c:sk_stream_write_space */
        if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk))
                xs_write_space(sk);
  
 -      read_unlock(&sk->sk_callback_lock);
 +      read_unlock_bh(&sk->sk_callback_lock);
  }
  
  static void xs_udp_do_set_buffer_size(struct rpc_xprt *xprt)
@@@ -1516,7 -1515,7 +1515,7 @@@ static void xs_set_port(struct rpc_xpr
        xs_update_peer_port(xprt);
  }
  
- static unsigned short xs_get_srcport(struct sock_xprt *transport, struct socket *sock)
+ static unsigned short xs_get_srcport(struct sock_xprt *transport)
  {
        unsigned short port = transport->srcport;
  
        return port;
  }
  
- static unsigned short xs_next_srcport(struct sock_xprt *transport, struct socket *sock, unsigned short port)
+ static unsigned short xs_next_srcport(struct sock_xprt *transport, unsigned short port)
  {
        if (transport->srcport != 0)
                transport->srcport = 0;
                return xprt_max_resvport;
        return --port;
  }
- static int xs_bind4(struct sock_xprt *transport, struct socket *sock)
+ static int xs_bind(struct sock_xprt *transport, struct socket *sock)
  {
-       struct sockaddr_in myaddr = {
-               .sin_family = AF_INET,
-       };
-       struct sockaddr_in *sa;
+       struct sockaddr_storage myaddr;
        int err, nloop = 0;
-       unsigned short port = xs_get_srcport(transport, sock);
+       unsigned short port = xs_get_srcport(transport);
        unsigned short last;
  
-       sa = (struct sockaddr_in *)&transport->srcaddr;
-       myaddr.sin_addr = sa->sin_addr;
+       memcpy(&myaddr, &transport->srcaddr, transport->xprt.addrlen);
        do {
-               myaddr.sin_port = htons(port);
-               err = kernel_bind(sock, (struct sockaddr *) &myaddr,
-                                               sizeof(myaddr));
+               rpc_set_port((struct sockaddr *)&myaddr, port);
+               err = kernel_bind(sock, (struct sockaddr *)&myaddr,
+                               transport->xprt.addrlen);
                if (port == 0)
                        break;
                if (err == 0) {
                        break;
                }
                last = port;
-               port = xs_next_srcport(transport, sock, port);
+               port = xs_next_srcport(transport, port);
                if (port > last)
                        nloop++;
        } while (err == -EADDRINUSE && nloop != 2);
-       dprintk("RPC:       %s %pI4:%u: %s (%d)\n",
-                       __func__, &myaddr.sin_addr,
-                       port, err ? "failed" : "ok", err);
-       return err;
- }
- static int xs_bind6(struct sock_xprt *transport, struct socket *sock)
- {
-       struct sockaddr_in6 myaddr = {
-               .sin6_family = AF_INET6,
-       };
-       struct sockaddr_in6 *sa;
-       int err, nloop = 0;
-       unsigned short port = xs_get_srcport(transport, sock);
-       unsigned short last;
  
-       sa = (struct sockaddr_in6 *)&transport->srcaddr;
-       myaddr.sin6_addr = sa->sin6_addr;
-       do {
-               myaddr.sin6_port = htons(port);
-               err = kernel_bind(sock, (struct sockaddr *) &myaddr,
-                                               sizeof(myaddr));
-               if (port == 0)
-                       break;
-               if (err == 0) {
-                       transport->srcport = port;
-                       break;
-               }
-               last = port;
-               port = xs_next_srcport(transport, sock, port);
-               if (port > last)
-                       nloop++;
-       } while (err == -EADDRINUSE && nloop != 2);
-       dprintk("RPC:       xs_bind6 %pI6:%u: %s (%d)\n",
-               &myaddr.sin6_addr, port, err ? "failed" : "ok", err);
+       if (myaddr.ss_family == AF_INET)
+               dprintk("RPC:       %s %pI4:%u: %s (%d)\n", __func__,
+                               &((struct sockaddr_in *)&myaddr)->sin_addr,
+                               port, err ? "failed" : "ok", err);
+       else
+               dprintk("RPC:       %s %pI6:%u: %s (%d)\n", __func__,
+                               &((struct sockaddr_in6 *)&myaddr)->sin6_addr,
+                               port, err ? "failed" : "ok", err);
        return err;
  }
  
  #ifdef CONFIG_DEBUG_LOCK_ALLOC
  static struct lock_class_key xs_key[2];
  static struct lock_class_key xs_slock_key[2];
@@@ -1622,6 -1591,18 +1591,18 @@@ static inline void xs_reclassify_socket
        sock_lock_init_class_and_name(sk, "slock-AF_INET6-RPC",
                &xs_slock_key[1], "sk_lock-AF_INET6-RPC", &xs_key[1]);
  }
+ static inline void xs_reclassify_socket(int family, struct socket *sock)
+ {
+       switch (family) {
+       case AF_INET:
+               xs_reclassify_socket4(sock);
+               break;
+       case AF_INET6:
+               xs_reclassify_socket6(sock);
+               break;
+       }
+ }
  #else
  static inline void xs_reclassify_socket4(struct socket *sock)
  {
  static inline void xs_reclassify_socket6(struct socket *sock)
  {
  }
+ static inline void xs_reclassify_socket(int family, struct socket *sock)
+ {
+ }
  #endif
  
+ static struct socket *xs_create_sock(struct rpc_xprt *xprt,
+               struct sock_xprt *transport, int family, int type, int protocol)
+ {
+       struct socket *sock;
+       int err;
+       err = __sock_create(xprt->xprt_net, family, type, protocol, &sock, 1);
+       if (err < 0) {
+               dprintk("RPC:       can't create %d transport socket (%d).\n",
+                               protocol, -err);
+               goto out;
+       }
+       xs_reclassify_socket(family, sock);
+       if (xs_bind(transport, sock)) {
+               sock_release(sock);
+               goto out;
+       }
+       return sock;
+ out:
+       return ERR_PTR(err);
+ }
  static void xs_udp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
  {
        struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
        xs_udp_do_set_buffer_size(xprt);
  }
  
- /**
-  * xs_udp_connect_worker4 - set up a UDP socket
-  * @work: RPC transport to connect
-  *
-  * Invoked by a work queue tasklet.
-  */
- static void xs_udp_connect_worker4(struct work_struct *work)
+ static void xs_udp_setup_socket(struct work_struct *work)
  {
        struct sock_xprt *transport =
                container_of(work, struct sock_xprt, connect_worker.work);
        struct rpc_xprt *xprt = &transport->xprt;
        struct socket *sock = transport->sock;
-       int err, status = -EIO;
+       int status = -EIO;
  
        if (xprt->shutdown)
                goto out;
  
        /* Start by resetting any existing state */
        xs_reset_transport(transport);
-       err = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock);
-       if (err < 0) {
-               dprintk("RPC:       can't create UDP transport socket (%d).\n", -err);
+       sock = xs_create_sock(xprt, transport,
+                       xs_addr(xprt)->sa_family, SOCK_DGRAM, IPPROTO_UDP);
+       if (IS_ERR(sock))
                goto out;
-       }
-       xs_reclassify_socket4(sock);
-       if (xs_bind4(transport, sock)) {
-               sock_release(sock);
-               goto out;
-       }
-       dprintk("RPC:       worker connecting xprt %p via %s to "
-                               "%s (port %s)\n", xprt,
-                       xprt->address_strings[RPC_DISPLAY_PROTO],
-                       xprt->address_strings[RPC_DISPLAY_ADDR],
-                       xprt->address_strings[RPC_DISPLAY_PORT]);
-       xs_udp_finish_connecting(xprt, sock);
-       status = 0;
- out:
-       xprt_clear_connecting(xprt);
-       xprt_wake_pending_tasks(xprt, status);
- }
- /**
-  * xs_udp_connect_worker6 - set up a UDP socket
-  * @work: RPC transport to connect
-  *
-  * Invoked by a work queue tasklet.
-  */
- static void xs_udp_connect_worker6(struct work_struct *work)
- {
-       struct sock_xprt *transport =
-               container_of(work, struct sock_xprt, connect_worker.work);
-       struct rpc_xprt *xprt = &transport->xprt;
-       struct socket *sock = transport->sock;
-       int err, status = -EIO;
-       if (xprt->shutdown)
-               goto out;
-       /* Start by resetting any existing state */
-       xs_reset_transport(transport);
-       err = sock_create_kern(PF_INET6, SOCK_DGRAM, IPPROTO_UDP, &sock);
-       if (err < 0) {
-               dprintk("RPC:       can't create UDP transport socket (%d).\n", -err);
-               goto out;
-       }
-       xs_reclassify_socket6(sock);
-       if (xs_bind6(transport, sock) < 0) {
-               sock_release(sock);
-               goto out;
-       }
  
        dprintk("RPC:       worker connecting xprt %p via %s to "
                                "%s (port %s)\n", xprt,
   * We need to preserve the port number so the reply cache on the server can
   * find our cached RPC replies when we get around to reconnecting.
   */
- static void xs_abort_connection(struct rpc_xprt *xprt, struct sock_xprt *transport)
+ static void xs_abort_connection(struct sock_xprt *transport)
  {
        int result;
        struct sockaddr any;
  
-       dprintk("RPC:       disconnecting xprt %p to reuse port\n", xprt);
+       dprintk("RPC:       disconnecting xprt %p to reuse port\n", transport);
  
        /*
         * Disconnect the transport socket by doing a connect operation
        any.sa_family = AF_UNSPEC;
        result = kernel_connect(transport->sock, &any, sizeof(any), 0);
        if (!result)
-               xs_sock_mark_closed(xprt);
+               xs_sock_mark_closed(&transport->xprt);
        else
                dprintk("RPC:       AF_UNSPEC connect return code %d\n",
                                result);
  }
  
- static void xs_tcp_reuse_connection(struct rpc_xprt *xprt, struct sock_xprt *transport)
+ static void xs_tcp_reuse_connection(struct sock_xprt *transport)
  {
        unsigned int state = transport->inet->sk_state;
  
                                "sk_shutdown set to %d\n",
                                __func__, transport->inet->sk_shutdown);
        }
-       xs_abort_connection(xprt, transport);
+       xs_abort_connection(transport);
  }
  
  static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
   *
   * Invoked by a work queue tasklet.
   */
- static void xs_tcp_setup_socket(struct rpc_xprt *xprt,
-               struct sock_xprt *transport,
-               struct socket *(*create_sock)(struct rpc_xprt *,
-                       struct sock_xprt *))
+ static void xs_tcp_setup_socket(struct work_struct *work)
  {
+       struct sock_xprt *transport =
+               container_of(work, struct sock_xprt, connect_worker.work);
        struct socket *sock = transport->sock;
+       struct rpc_xprt *xprt = &transport->xprt;
        int status = -EIO;
  
        if (xprt->shutdown)
  
        if (!sock) {
                clear_bit(XPRT_CONNECTION_ABORT, &xprt->state);
-               sock = create_sock(xprt, transport);
+               sock = xs_create_sock(xprt, transport,
+                               xs_addr(xprt)->sa_family, SOCK_STREAM, IPPROTO_TCP);
                if (IS_ERR(sock)) {
                        status = PTR_ERR(sock);
                        goto out;
                abort_and_exit = test_and_clear_bit(XPRT_CONNECTION_ABORT,
                                &xprt->state);
                /* "close" the socket, preserving the local port */
-               xs_tcp_reuse_connection(xprt, transport);
+               xs_tcp_reuse_connection(transport);
  
                if (abort_and_exit)
                        goto out_eagain;
@@@ -1925,84 -1876,6 +1876,6 @@@ out
        xprt_wake_pending_tasks(xprt, status);
  }
  
- static struct socket *xs_create_tcp_sock4(struct rpc_xprt *xprt,
-               struct sock_xprt *transport)
- {
-       struct socket *sock;
-       int err;
-       /* start from scratch */
-       err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock);
-       if (err < 0) {
-               dprintk("RPC:       can't create TCP transport socket (%d).\n",
-                               -err);
-               goto out_err;
-       }
-       xs_reclassify_socket4(sock);
-       if (xs_bind4(transport, sock) < 0) {
-               sock_release(sock);
-               goto out_err;
-       }
-       return sock;
- out_err:
-       return ERR_PTR(-EIO);
- }
- /**
-  * xs_tcp_connect_worker4 - connect a TCP socket to a remote endpoint
-  * @work: RPC transport to connect
-  *
-  * Invoked by a work queue tasklet.
-  */
- static void xs_tcp_connect_worker4(struct work_struct *work)
- {
-       struct sock_xprt *transport =
-               container_of(work, struct sock_xprt, connect_worker.work);
-       struct rpc_xprt *xprt = &transport->xprt;
-       xs_tcp_setup_socket(xprt, transport, xs_create_tcp_sock4);
- }
- static struct socket *xs_create_tcp_sock6(struct rpc_xprt *xprt,
-               struct sock_xprt *transport)
- {
-       struct socket *sock;
-       int err;
-       /* start from scratch */
-       err = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, &sock);
-       if (err < 0) {
-               dprintk("RPC:       can't create TCP transport socket (%d).\n",
-                               -err);
-               goto out_err;
-       }
-       xs_reclassify_socket6(sock);
-       if (xs_bind6(transport, sock) < 0) {
-               sock_release(sock);
-               goto out_err;
-       }
-       return sock;
- out_err:
-       return ERR_PTR(-EIO);
- }
- /**
-  * xs_tcp_connect_worker6 - connect a TCP socket to a remote endpoint
-  * @work: RPC transport to connect
-  *
-  * Invoked by a work queue tasklet.
-  */
- static void xs_tcp_connect_worker6(struct work_struct *work)
- {
-       struct sock_xprt *transport =
-               container_of(work, struct sock_xprt, connect_worker.work);
-       struct rpc_xprt *xprt = &transport->xprt;
-       xs_tcp_setup_socket(xprt, transport, xs_create_tcp_sock6);
- }
  /**
   * xs_connect - connect a socket to a remote endpoint
   * @task: address of RPC task that manages state of connect request
@@@ -2262,6 -2135,31 +2135,31 @@@ static struct rpc_xprt_ops bc_tcp_ops 
        .print_stats            = xs_tcp_print_stats,
  };
  
+ static int xs_init_anyaddr(const int family, struct sockaddr *sap)
+ {
+       static const struct sockaddr_in sin = {
+               .sin_family             = AF_INET,
+               .sin_addr.s_addr        = htonl(INADDR_ANY),
+       };
+       static const struct sockaddr_in6 sin6 = {
+               .sin6_family            = AF_INET6,
+               .sin6_addr              = IN6ADDR_ANY_INIT,
+       };
+       switch (family) {
+       case AF_INET:
+               memcpy(sap, &sin, sizeof(sin));
+               break;
+       case AF_INET6:
+               memcpy(sap, &sin6, sizeof(sin6));
+               break;
+       default:
+               dprintk("RPC:       %s: Bad address family\n", __func__);
+               return -EAFNOSUPPORT;
+       }
+       return 0;
+ }
  static struct rpc_xprt *xs_setup_xprt(struct xprt_create *args,
                                      unsigned int slot_table_size)
  {
                return ERR_PTR(-EBADF);
        }
  
-       new = kzalloc(sizeof(*new), GFP_KERNEL);
-       if (new == NULL) {
+       xprt = xprt_alloc(args->net, sizeof(*new), slot_table_size);
+       if (xprt == NULL) {
                dprintk("RPC:       xs_setup_xprt: couldn't allocate "
                                "rpc_xprt\n");
                return ERR_PTR(-ENOMEM);
        }
-       xprt = &new->xprt;
-       xprt->max_reqs = slot_table_size;
-       xprt->slot = kcalloc(xprt->max_reqs, sizeof(struct rpc_rqst), GFP_KERNEL);
-       if (xprt->slot == NULL) {
-               kfree(xprt);
-               dprintk("RPC:       xs_setup_xprt: couldn't allocate slot "
-                               "table\n");
-               return ERR_PTR(-ENOMEM);
-       }
  
+       new = container_of(xprt, struct sock_xprt, xprt);
        memcpy(&xprt->addr, args->dstaddr, args->addrlen);
        xprt->addrlen = args->addrlen;
        if (args->srcaddr)
                memcpy(&new->srcaddr, args->srcaddr, args->addrlen);
+       else {
+               int err;
+               err = xs_init_anyaddr(args->dstaddr->sa_family,
+                                       (struct sockaddr *)&new->srcaddr);
+               if (err != 0)
+                       return ERR_PTR(err);
+       }
  
        return xprt;
  }
@@@ -2341,7 -2237,7 +2237,7 @@@ static struct rpc_xprt *xs_setup_udp(st
                        xprt_set_bound(xprt);
  
                INIT_DELAYED_WORK(&transport->connect_worker,
-                                       xs_udp_connect_worker4);
+                                       xs_udp_setup_socket);
                xs_format_peer_addresses(xprt, "udp", RPCBIND_NETID_UDP);
                break;
        case AF_INET6:
                        xprt_set_bound(xprt);
  
                INIT_DELAYED_WORK(&transport->connect_worker,
-                                       xs_udp_connect_worker6);
+                                       xs_udp_setup_socket);
                xs_format_peer_addresses(xprt, "udp", RPCBIND_NETID_UDP6);
                break;
        default:
                return xprt;
        ret = ERR_PTR(-EINVAL);
  out_err:
-       kfree(xprt->slot);
-       kfree(xprt);
+       xprt_free(xprt);
        return ret;
  }
  
@@@ -2416,7 -2311,7 +2311,7 @@@ static struct rpc_xprt *xs_setup_tcp(st
                        xprt_set_bound(xprt);
  
                INIT_DELAYED_WORK(&transport->connect_worker,
-                                       xs_tcp_connect_worker4);
+                                       xs_tcp_setup_socket);
                xs_format_peer_addresses(xprt, "tcp", RPCBIND_NETID_TCP);
                break;
        case AF_INET6:
                        xprt_set_bound(xprt);
  
                INIT_DELAYED_WORK(&transport->connect_worker,
-                                       xs_tcp_connect_worker6);
+                                       xs_tcp_setup_socket);
                xs_format_peer_addresses(xprt, "tcp", RPCBIND_NETID_TCP6);
                break;
        default:
                return xprt;
        ret = ERR_PTR(-EINVAL);
  out_err:
-       kfree(xprt->slot);
-       kfree(xprt);
+       xprt_free(xprt);
        return ret;
  }
  
@@@ -2507,15 -2401,10 +2401,10 @@@ static struct rpc_xprt *xs_setup_bc_tcp
                goto out_err;
        }
  
-       if (xprt_bound(xprt))
-               dprintk("RPC:       set up xprt to %s (port %s) via %s\n",
-                               xprt->address_strings[RPC_DISPLAY_ADDR],
-                               xprt->address_strings[RPC_DISPLAY_PORT],
-                               xprt->address_strings[RPC_DISPLAY_PROTO]);
-       else
-               dprintk("RPC:       set up xprt to %s (autobind) via %s\n",
-                               xprt->address_strings[RPC_DISPLAY_ADDR],
-                               xprt->address_strings[RPC_DISPLAY_PROTO]);
+       dprintk("RPC:       set up xprt to %s (port %s) via %s\n",
+                       xprt->address_strings[RPC_DISPLAY_ADDR],
+                       xprt->address_strings[RPC_DISPLAY_PORT],
+                       xprt->address_strings[RPC_DISPLAY_PROTO]);
  
        /*
         * Since we don't want connections for the backchannel, we set
                return xprt;
        ret = ERR_PTR(-EINVAL);
  out_err:
-       kfree(xprt->slot);
-       kfree(xprt);
+       xprt_free(xprt);
        return ret;
  }