Merge branch 'for-3.9' of git://linux-nfs.org/~bfields/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 1 Mar 2013 02:02:55 +0000 (18:02 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 1 Mar 2013 02:02:55 +0000 (18:02 -0800)
Pull nfsd changes from J Bruce Fields:
 "Miscellaneous bugfixes, plus:

   - An overhaul of the DRC cache by Jeff Layton.  The main effect is
     just to make it larger.  This decreases the chances of intermittent
     errors especially in the UDP case.  But we'll need to watch for any
     reports of performance regressions.

   - Containerized nfsd: with some limitations, we now support
     per-container nfs-service, thanks to extensive work from Stanislav
     Kinsbursky over the last year."

Some notes about conflicts, since there were *two* non-data semantic
conflicts here:

 - idr_remove_all() had been added by a memory leak fix, but has since
   become deprecated since idr_destroy() does it for us now.

 - xs_local_connect() had been added by this branch to make AF_LOCAL
   connections be synchronous, but in the meantime Trond had changed the
   calling convention in order to avoid a RCU dereference.

There were a couple of more obvious actual source-level conflicts due to
the hlist traversal changes and one just due to code changes next to
each other, but those were trivial.

* 'for-3.9' of git://linux-nfs.org/~bfields/linux: (49 commits)
  SUNRPC: make AF_LOCAL connect synchronous
  nfsd: fix compiler warning about ambiguous types in nfsd_cache_csum
  svcrpc: fix rpc server shutdown races
  svcrpc: make svc_age_temp_xprts enqueue under sv_lock
  lockd: nlmclnt_reclaim(): avoid stack overflow
  nfsd: enable NFSv4 state in containers
  nfsd: disable usermode helper client tracker in container
  nfsd: use proper net while reading "exports" file
  nfsd: containerize NFSd filesystem
  nfsd: fix comments on nfsd_cache_lookup
  SUNRPC: move cache_detail->cache_request callback call to cache_read()
  SUNRPC: remove "cache_request" argument in sunrpc_cache_pipe_upcall() function
  SUNRPC: rework cache upcall logic
  SUNRPC: introduce cache_detail->cache_request callback
  NFS: simplify and clean cache library
  NFS: use SUNRPC cache creation and destruction helper for DNS cache
  nfsd4: free_stid can be static
  nfsd: keep a checksum of the first 256 bytes of request
  sunrpc: trim off trailing checksum before returning decrypted or integrity authenticated buffer
  sunrpc: fix comment in struct xdr_buf definition
  ...

22 files changed:
1  2 
fs/lockd/clntlock.c
fs/lockd/clntproc.c
fs/lockd/host.c
fs/lockd/svcsubs.c
fs/nfs/nfs4client.c
fs/nfs/super.c
fs/nfsd/export.c
fs/nfsd/fault_inject.c
fs/nfsd/nfs4idmap.c
fs/nfsd/nfs4recover.c
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfscache.c
fs/nfsd/nfsctl.c
fs/nfsd/nfssvc.c
include/linux/lockd/lockd.h
net/sunrpc/auth_gss/svcauth_gss.c
net/sunrpc/cache.c
net/sunrpc/clnt.c
net/sunrpc/svcauth_unix.c
net/sunrpc/xprtrdma/transport.c
net/sunrpc/xprtsock.c

diff --combined fs/lockd/clntlock.c
@@@ -11,7 -11,7 +11,7 @@@
  #include <linux/slab.h>
  #include <linux/time.h>
  #include <linux/nfs_fs.h>
- #include <linux/sunrpc/clnt.h>
+ #include <linux/sunrpc/addr.h>
  #include <linux/sunrpc/svc.h>
  #include <linux/lockd/lockd.h>
  #include <linux/kthread.h>
@@@ -178,7 -178,7 +178,7 @@@ __be32 nlmclnt_grant(const struct socka
                        continue;
                if (!rpc_cmp_addr(nlm_addr(block->b_host), addr))
                        continue;
 -              if (nfs_compare_fh(NFS_FH(fl_blocked->fl_file->f_path.dentry->d_inode) ,fh) != 0)
 +              if (nfs_compare_fh(NFS_FH(file_inode(fl_blocked->fl_file)) ,fh) != 0)
                        continue;
                /* Alright, we found a lock. Set the return status
                 * and wake up the caller
@@@ -220,10 -220,19 +220,19 @@@ reclaimer(void *ptr
  {
        struct nlm_host   *host = (struct nlm_host *) ptr;
        struct nlm_wait   *block;
+       struct nlm_rqst   *req;
        struct file_lock *fl, *next;
        u32 nsmstate;
        struct net *net = host->net;
  
+       req = kmalloc(sizeof(*req), GFP_KERNEL);
+       if (!req) {
+               printk(KERN_ERR "lockd: reclaimer unable to alloc memory."
+                               " Locks for %s won't be reclaimed!\n",
+                               host->h_name);
+               return 0;
+       }
        allow_signal(SIGKILL);
  
        down_write(&host->h_rwsem);
@@@ -253,7 -262,7 +262,7 @@@ restart
                 */
                if (signalled())
                        continue;
-               if (nlmclnt_reclaim(host, fl) != 0)
+               if (nlmclnt_reclaim(host, fl, req) != 0)
                        continue;
                list_add_tail(&fl->fl_u.nfs_fl.list, &host->h_granted);
                if (host->h_nsmstate != nsmstate) {
        /* Release host handle after use */
        nlmclnt_release_host(host);
        lockd_down(net);
+       kfree(req);
        return 0;
  }
diff --combined fs/lockd/clntproc.c
@@@ -127,7 -127,7 +127,7 @@@ static void nlmclnt_setlockargs(struct 
        struct nlm_lock *lock = &argp->lock;
  
        nlmclnt_next_cookie(&argp->cookie);
 -      memcpy(&lock->fh, NFS_FH(fl->fl_file->f_path.dentry->d_inode), sizeof(struct nfs_fh));
 +      memcpy(&lock->fh, NFS_FH(file_inode(fl->fl_file)), sizeof(struct nfs_fh));
        lock->caller  = utsname()->nodename;
        lock->oh.data = req->a_owner;
        lock->oh.len  = snprintf(req->a_owner, sizeof(req->a_owner), "%u@%s",
@@@ -550,9 -550,6 +550,9 @@@ again
                status = nlmclnt_block(block, req, NLMCLNT_POLL_TIMEOUT);
                if (status < 0)
                        break;
 +              /* Resend the blocking lock request after a server reboot */
 +              if (resp->status ==  nlm_lck_denied_grace_period)
 +                      continue;
                if (resp->status != nlm_lck_blocked)
                        break;
        }
@@@ -618,17 -615,15 +618,15 @@@ out_unlock
   * RECLAIM: Try to reclaim a lock
   */
  int
- nlmclnt_reclaim(struct nlm_host *host, struct file_lock *fl)
+ nlmclnt_reclaim(struct nlm_host *host, struct file_lock *fl,
+               struct nlm_rqst *req)
  {
-       struct nlm_rqst reqst, *req;
        int             status;
  
-       req = &reqst;
        memset(req, 0, sizeof(*req));
        locks_init_lock(&req->a_args.lock.fl);
        locks_init_lock(&req->a_res.lock.fl);
        req->a_host  = host;
-       req->a_flags = 0;
  
        /* Set up the argument struct */
        nlmclnt_setlockargs(req, fl);
diff --combined fs/lockd/host.c
@@@ -13,6 -13,7 +13,7 @@@
  #include <linux/in.h>
  #include <linux/in6.h>
  #include <linux/sunrpc/clnt.h>
+ #include <linux/sunrpc/addr.h>
  #include <linux/sunrpc/svc.h>
  #include <linux/lockd/lockd.h>
  #include <linux/mutex.h>
  static struct hlist_head      nlm_server_hosts[NLM_HOST_NRHASH];
  static struct hlist_head      nlm_client_hosts[NLM_HOST_NRHASH];
  
 -#define for_each_host(host, pos, chain, table) \
 +#define for_each_host(host, chain, table) \
        for ((chain) = (table); \
             (chain) < (table) + NLM_HOST_NRHASH; ++(chain)) \
 -              hlist_for_each_entry((host), (pos), (chain), h_hash)
 +              hlist_for_each_entry((host), (chain), h_hash)
  
 -#define for_each_host_safe(host, pos, next, chain, table) \
 +#define for_each_host_safe(host, next, chain, table) \
        for ((chain) = (table); \
             (chain) < (table) + NLM_HOST_NRHASH; ++(chain)) \
 -              hlist_for_each_entry_safe((host), (pos), (next), \
 +              hlist_for_each_entry_safe((host), (next), \
                                                (chain), h_hash)
  
  static unsigned long          nrhosts;
@@@ -225,6 -226,7 +226,6 @@@ struct nlm_host *nlmclnt_lookup_host(co
                .net            = net,
        };
        struct hlist_head *chain;
 -      struct hlist_node *pos;
        struct nlm_host *host;
        struct nsm_handle *nsm = NULL;
        struct lockd_net *ln = net_generic(net, lockd_net_id);
        mutex_lock(&nlm_host_mutex);
  
        chain = &nlm_client_hosts[nlm_hash_address(sap)];
 -      hlist_for_each_entry(host, pos, chain, h_hash) {
 +      hlist_for_each_entry(host, chain, h_hash) {
                if (host->net != net)
                        continue;
                if (!rpc_cmp_addr(nlm_addr(host), sap))
@@@ -321,6 -323,7 +322,6 @@@ struct nlm_host *nlmsvc_lookup_host(con
                                    const size_t hostname_len)
  {
        struct hlist_head *chain;
 -      struct hlist_node *pos;
        struct nlm_host *host = NULL;
        struct nsm_handle *nsm = NULL;
        struct sockaddr *src_sap = svc_daddr(rqstp);
                nlm_gc_hosts(net);
  
        chain = &nlm_server_hosts[nlm_hash_address(ni.sap)];
 -      hlist_for_each_entry(host, pos, chain, h_hash) {
 +      hlist_for_each_entry(host, chain, h_hash) {
                if (host->net != net)
                        continue;
                if (!rpc_cmp_addr(nlm_addr(host), ni.sap))
@@@ -513,9 -516,10 +514,9 @@@ static struct nlm_host *next_host_state
  {
        struct nlm_host *host;
        struct hlist_head *chain;
 -      struct hlist_node *pos;
  
        mutex_lock(&nlm_host_mutex);
 -      for_each_host(host, pos, chain, cache) {
 +      for_each_host(host, chain, cache) {
                if (host->h_nsmhandle == nsm
                    && host->h_nsmstate != info->state) {
                        host->h_nsmstate = info->state;
@@@ -567,6 -571,7 +568,6 @@@ void nlm_host_rebooted(const struct nlm
  static void nlm_complain_hosts(struct net *net)
  {
        struct hlist_head *chain;
 -      struct hlist_node *pos;
        struct nlm_host *host;
  
        if (net) {
                dprintk("lockd: %lu hosts left:\n", nrhosts);
        }
  
 -      for_each_host(host, pos, chain, nlm_server_hosts) {
 +      for_each_host(host, chain, nlm_server_hosts) {
                if (net && host->net != net)
                        continue;
                dprintk("       %s (cnt %d use %d exp %ld net %p)\n",
@@@ -596,13 -601,14 +597,13 @@@ voi
  nlm_shutdown_hosts_net(struct net *net)
  {
        struct hlist_head *chain;
 -      struct hlist_node *pos;
        struct nlm_host *host;
  
        mutex_lock(&nlm_host_mutex);
  
        /* First, make all hosts eligible for gc */
        dprintk("lockd: nuking all hosts in net %p...\n", net);
 -      for_each_host(host, pos, chain, nlm_server_hosts) {
 +      for_each_host(host, chain, nlm_server_hosts) {
                if (net && host->net != net)
                        continue;
                host->h_expires = jiffies - 1;
@@@ -639,11 -645,11 +640,11 @@@ static voi
  nlm_gc_hosts(struct net *net)
  {
        struct hlist_head *chain;
 -      struct hlist_node *pos, *next;
 +      struct hlist_node *next;
        struct nlm_host *host;
  
        dprintk("lockd: host garbage collection for net %p\n", net);
 -      for_each_host(host, pos, chain, nlm_server_hosts) {
 +      for_each_host(host, chain, nlm_server_hosts) {
                if (net && host->net != net)
                        continue;
                host->h_inuse = 0;
        /* Mark all hosts that hold locks, blocks or shares */
        nlmsvc_mark_resources(net);
  
 -      for_each_host_safe(host, pos, next, chain, nlm_server_hosts) {
 +      for_each_host_safe(host, next, chain, nlm_server_hosts) {
                if (net && host->net != net)
                        continue;
                if (atomic_read(&host->h_count) || host->h_inuse
diff --combined fs/lockd/svcsubs.c
@@@ -13,7 -13,7 +13,7 @@@
  #include <linux/slab.h>
  #include <linux/mutex.h>
  #include <linux/sunrpc/svc.h>
- #include <linux/sunrpc/clnt.h>
+ #include <linux/sunrpc/addr.h>
  #include <linux/nfsd/nfsfh.h>
  #include <linux/nfsd/export.h>
  #include <linux/lockd/lockd.h>
@@@ -45,7 -45,7 +45,7 @@@ static inline void nlm_debug_print_fh(c
  
  static inline void nlm_debug_print_file(char *msg, struct nlm_file *file)
  {
 -      struct inode *inode = file->f_file->f_path.dentry->d_inode;
 +      struct inode *inode = file_inode(file->f_file);
  
        dprintk("lockd: %s %s/%ld\n",
                msg, inode->i_sb->s_id, inode->i_ino);
@@@ -84,6 -84,7 +84,6 @@@ __be3
  nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
                                        struct nfs_fh *f)
  {
 -      struct hlist_node *pos;
        struct nlm_file *file;
        unsigned int    hash;
        __be32          nfserr;
@@@ -95,7 -96,7 +95,7 @@@
        /* Lock file table */
        mutex_lock(&nlm_file_mutex);
  
 -      hlist_for_each_entry(file, pos, &nlm_files[hash], f_list)
 +      hlist_for_each_entry(file, &nlm_files[hash], f_list)
                if (!nfs_compare_fh(&file->f_handle, f))
                        goto found;
  
@@@ -247,13 -248,13 +247,13 @@@ static in
  nlm_traverse_files(void *data, nlm_host_match_fn_t match,
                int (*is_failover_file)(void *data, struct nlm_file *file))
  {
 -      struct hlist_node *pos, *next;
 +      struct hlist_node *next;
        struct nlm_file *file;
        int i, ret = 0;
  
        mutex_lock(&nlm_file_mutex);
        for (i = 0; i < FILE_NRHASH; i++) {
 -              hlist_for_each_entry_safe(file, pos, next, &nlm_files[i], f_list) {
 +              hlist_for_each_entry_safe(file, next, &nlm_files[i], f_list) {
                        if (is_failover_file && !is_failover_file(data, file))
                                continue;
                        file->f_count++;
diff --combined fs/nfs/nfs4client.c
@@@ -6,6 -6,7 +6,7 @@@
  #include <linux/nfs_fs.h>
  #include <linux/nfs_idmap.h>
  #include <linux/nfs_mount.h>
+ #include <linux/sunrpc/addr.h>
  #include <linux/sunrpc/auth.h>
  #include <linux/sunrpc/xprt.h>
  #include <linux/sunrpc/bc_xprt.h>
@@@ -29,14 -30,15 +30,14 @@@ static int nfs_get_cb_ident_idr(struct 
  
        if (clp->rpc_ops->version != 4 || minorversion != 0)
                return ret;
 -retry:
 -      if (!idr_pre_get(&nn->cb_ident_idr, GFP_KERNEL))
 -              return -ENOMEM;
 +      idr_preload(GFP_KERNEL);
        spin_lock(&nn->nfs_client_lock);
 -      ret = idr_get_new(&nn->cb_ident_idr, clp, &clp->cl_cb_ident);
 +      ret = idr_alloc(&nn->cb_ident_idr, clp, 0, 0, GFP_NOWAIT);
 +      if (ret >= 0)
 +              clp->cl_cb_ident = ret;
        spin_unlock(&nn->nfs_client_lock);
 -      if (ret == -EAGAIN)
 -              goto retry;
 -      return ret;
 +      idr_preload_end();
 +      return ret < 0 ? ret : 0;
  }
  
  #ifdef CONFIG_NFS_V4_1
@@@ -235,10 -237,11 +236,10 @@@ struct nfs_client *nfs4_init_client(str
        error = nfs4_discover_server_trunking(clp, &old);
        if (error < 0)
                goto error;
 +      nfs_put_client(clp);
        if (clp != old) {
                clp->cl_preserve_clid = true;
 -              nfs_put_client(clp);
                clp = old;
 -              atomic_inc(&clp->cl_count);
        }
  
        return clp;
@@@ -304,7 -307,7 +305,7 @@@ int nfs40_walk_client_list(struct nfs_c
                .clientid       = new->cl_clientid,
                .confirm        = new->cl_confirm,
        };
 -      int status;
 +      int status = -NFS4ERR_STALE_CLIENTID;
  
        spin_lock(&nn->nfs_client_lock);
        list_for_each_entry_safe(pos, n, &nn->nfs_client_list, cl_share_link) {
  
                if (prev)
                        nfs_put_client(prev);
 +              prev = pos;
  
                status = nfs4_proc_setclientid_confirm(pos, &clid, cred);
 -              if (status == 0) {
 +              switch (status) {
 +              case -NFS4ERR_STALE_CLIENTID:
 +                      break;
 +              case 0:
                        nfs4_swap_callback_idents(pos, new);
  
 -                      nfs_put_client(pos);
 +                      prev = NULL;
                        *result = pos;
                        dprintk("NFS: <-- %s using nfs_client = %p ({%d})\n",
                                __func__, pos, atomic_read(&pos->cl_count));
 -                      return 0;
 -              }
 -              if (status != -NFS4ERR_STALE_CLIENTID) {
 -                      nfs_put_client(pos);
 -                      dprintk("NFS: <-- %s status = %d, no result\n",
 -                              __func__, status);
 -                      return status;
 +              default:
 +                      goto out;
                }
  
                spin_lock(&nn->nfs_client_lock);
 -              prev = pos;
        }
 +      spin_unlock(&nn->nfs_client_lock);
  
 -      /*
 -       * No matching nfs_client found.  This should be impossible,
 -       * because the new nfs_client has already been added to
 -       * nfs_client_list by nfs_get_client().
 -       *
 -       * Don't BUG(), since the caller is holding a mutex.
 -       */
 +      /* No match found. The server lost our clientid */
 +out:
        if (prev)
                nfs_put_client(prev);
 -      spin_unlock(&nn->nfs_client_lock);
 -      pr_err("NFS: %s Error: no matching nfs_client found\n", __func__);
 -      return -NFS4ERR_STALE_CLIENTID;
 +      dprintk("NFS: <-- %s status = %d\n", __func__, status);
 +      return status;
  }
  
  #ifdef CONFIG_NFS_V4_1
@@@ -423,7 -433,7 +424,7 @@@ int nfs41_walk_client_list(struct nfs_c
  {
        struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id);
        struct nfs_client *pos, *n, *prev = NULL;
 -      int error;
 +      int status = -NFS4ERR_STALE_CLIENTID;
  
        spin_lock(&nn->nfs_client_lock);
        list_for_each_entry_safe(pos, n, &nn->nfs_client_list, cl_share_link) {
                                nfs_put_client(prev);
                        prev = pos;
  
 -                      error = nfs_wait_client_init_complete(pos);
 -                      if (error < 0) {
 +                      nfs4_schedule_lease_recovery(pos);
 +                      status = nfs_wait_client_init_complete(pos);
 +                      if (status < 0) {
                                nfs_put_client(pos);
                                spin_lock(&nn->nfs_client_lock);
                                continue;
                        }
 -
 +                      status = pos->cl_cons_state;
                        spin_lock(&nn->nfs_client_lock);
 +                      if (status < 0)
 +                              continue;
                }
  
                if (pos->rpc_ops != new->rpc_ops)
                if (!nfs4_match_serverowners(pos, new))
                        continue;
  
 +              atomic_inc(&pos->cl_count);
                spin_unlock(&nn->nfs_client_lock);
                dprintk("NFS: <-- %s using nfs_client = %p ({%d})\n",
                        __func__, pos, atomic_read(&pos->cl_count));
                return 0;
        }
  
 -      /*
 -       * No matching nfs_client found.  This should be impossible,
 -       * because the new nfs_client has already been added to
 -       * nfs_client_list by nfs_get_client().
 -       *
 -       * Don't BUG(), since the caller is holding a mutex.
 -       */
 +      /* No matching nfs_client found. */
        spin_unlock(&nn->nfs_client_lock);
 -      pr_err("NFS: %s Error: no matching nfs_client found\n", __func__);
 -      return -NFS4ERR_STALE_CLIENTID;
 +      dprintk("NFS: <-- %s status = %d\n", __func__, status);
 +      return status;
  }
  #endif        /* CONFIG_NFS_V4_1 */
  
diff --combined fs/nfs/super.c
@@@ -31,6 -31,7 +31,7 @@@
  #include <linux/errno.h>
  #include <linux/unistd.h>
  #include <linux/sunrpc/clnt.h>
+ #include <linux/sunrpc/addr.h>
  #include <linux/sunrpc/stats.h>
  #include <linux/sunrpc/metrics.h>
  #include <linux/sunrpc/xprtsock.h>
@@@ -54,6 -55,7 +55,6 @@@
  #include <linux/parser.h>
  #include <linux/nsproxy.h>
  #include <linux/rcupdate.h>
 -#include <linux/kthread.h>
  
  #include <asm/uaccess.h>
  
@@@ -291,7 -293,7 +292,7 @@@ struct file_system_type nfs_fs_type = 
        .name           = "nfs",
        .mount          = nfs_fs_mount,
        .kill_sb        = nfs_kill_super,
 -      .fs_flags       = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
 +      .fs_flags       = FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA,
  };
  EXPORT_SYMBOL_GPL(nfs_fs_type);
  
@@@ -300,7 -302,7 +301,7 @@@ struct file_system_type nfs_xdev_fs_typ
        .name           = "nfs",
        .mount          = nfs_xdev_mount,
        .kill_sb        = nfs_kill_super,
 -      .fs_flags       = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
 +      .fs_flags       = FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA,
  };
  
  const struct super_operations nfs_sops = {
@@@ -330,7 -332,7 +331,7 @@@ struct file_system_type nfs4_fs_type = 
        .name           = "nfs4",
        .mount          = nfs_fs_mount,
        .kill_sb        = nfs_kill_super,
 -      .fs_flags       = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
 +      .fs_flags       = FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA,
  };
  EXPORT_SYMBOL_GPL(nfs4_fs_type);
  
@@@ -417,6 -419,54 +418,6 @@@ void nfs_sb_deactive(struct super_bloc
  }
  EXPORT_SYMBOL_GPL(nfs_sb_deactive);
  
 -static int nfs_deactivate_super_async_work(void *ptr)
 -{
 -      struct super_block *sb = ptr;
 -
 -      deactivate_super(sb);
 -      module_put_and_exit(0);
 -      return 0;
 -}
 -
 -/*
 - * same effect as deactivate_super, but will do final unmount in kthread
 - * context
 - */
 -static void nfs_deactivate_super_async(struct super_block *sb)
 -{
 -      struct task_struct *task;
 -      char buf[INET6_ADDRSTRLEN + 1];
 -      struct nfs_server *server = NFS_SB(sb);
 -      struct nfs_client *clp = server->nfs_client;
 -
 -      if (!atomic_add_unless(&sb->s_active, -1, 1)) {
 -              rcu_read_lock();
 -              snprintf(buf, sizeof(buf),
 -                      rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR));
 -              rcu_read_unlock();
 -
 -              __module_get(THIS_MODULE);
 -              task = kthread_run(nfs_deactivate_super_async_work, sb,
 -                              "%s-deactivate-super", buf);
 -              if (IS_ERR(task)) {
 -                      pr_err("%s: kthread_run: %ld\n",
 -                              __func__, PTR_ERR(task));
 -                      /* make synchronous call and hope for the best */
 -                      deactivate_super(sb);
 -                      module_put(THIS_MODULE);
 -              }
 -      }
 -}
 -
 -void nfs_sb_deactive_async(struct super_block *sb)
 -{
 -      struct nfs_server *server = NFS_SB(sb);
 -
 -      if (atomic_dec_and_test(&server->active))
 -              nfs_deactivate_super_async(sb);
 -}
 -EXPORT_SYMBOL_GPL(nfs_sb_deactive_async);
 -
  /*
   * Deliver file system statistics to userspace
   */
@@@ -1103,7 -1153,7 +1104,7 @@@ static int nfs_get_option_str(substring
  {
        kfree(*option);
        *option = match_strdup(args);
 -      return !option;
 +      return !*option;
  }
  
  static int nfs_get_option_ul(substring_t args[], unsigned long *option)
@@@ -2540,23 -2590,27 +2541,23 @@@ nfs_xdev_mount(struct file_system_type 
        struct nfs_server *server;
        struct dentry *mntroot = ERR_PTR(-ENOMEM);
        struct nfs_subversion *nfs_mod = NFS_SB(data->sb)->nfs_client->cl_nfs_mod;
 -      int error;
  
 -      dprintk("--> nfs_xdev_mount_common()\n");
 +      dprintk("--> nfs_xdev_mount()\n");
  
        mount_info.mntfh = mount_info.cloned->fh;
  
        /* create a new volume representation */
        server = nfs_mod->rpc_ops->clone_server(NFS_SB(data->sb), data->fh, data->fattr, data->authflavor);
 -      if (IS_ERR(server)) {
 -              error = PTR_ERR(server);
 -              goto out_err;
 -      }
  
 -      mntroot = nfs_fs_mount_common(server, flags, dev_name, &mount_info, nfs_mod);
 -      dprintk("<-- nfs_xdev_mount_common() = 0\n");
 -out:
 -      return mntroot;
 +      if (IS_ERR(server))
 +              mntroot = ERR_CAST(server);
 +      else
 +              mntroot = nfs_fs_mount_common(server, flags,
 +                              dev_name, &mount_info, nfs_mod);
  
 -out_err:
 -      dprintk("<-- nfs_xdev_mount_common() = %d [error]\n", error);
 -      goto out;
 +      dprintk("<-- nfs_xdev_mount() = %ld\n",
 +                      IS_ERR(mntroot) ? PTR_ERR(mntroot) : 0L);
 +      return mntroot;
  }
  
  #if IS_ENABLED(CONFIG_NFS_V4)
diff --combined fs/nfsd/export.c
@@@ -67,11 -67,6 +67,6 @@@ static void expkey_request(struct cache
        (*bpp)[-1] = '\n';
  }
  
- static int expkey_upcall(struct cache_detail *cd, struct cache_head *h)
- {
-       return sunrpc_cache_pipe_upcall(cd, h, expkey_request);
- }
  static struct svc_expkey *svc_expkey_update(struct cache_detail *cd, struct svc_expkey *new,
                                            struct svc_expkey *old);
  static struct svc_expkey *svc_expkey_lookup(struct cache_detail *cd, struct svc_expkey *);
@@@ -245,7 -240,7 +240,7 @@@ static struct cache_detail svc_expkey_c
        .hash_size      = EXPKEY_HASHMAX,
        .name           = "nfsd.fh",
        .cache_put      = expkey_put,
-       .cache_upcall   = expkey_upcall,
+       .cache_request  = expkey_request,
        .cache_parse    = expkey_parse,
        .cache_show     = expkey_show,
        .match          = expkey_match,
@@@ -315,6 -310,7 +310,7 @@@ static void svc_export_put(struct kref 
        path_put(&exp->ex_path);
        auth_domain_put(exp->ex_client);
        nfsd4_fslocs_free(&exp->ex_fslocs);
+       kfree(exp->ex_uuid);
        kfree(exp);
  }
  
@@@ -337,11 -333,6 +333,6 @@@ static void svc_export_request(struct c
        (*bpp)[-1] = '\n';
  }
  
- static int svc_export_upcall(struct cache_detail *cd, struct cache_head *h)
- {
-       return sunrpc_cache_pipe_upcall(cd, h, svc_export_request);
- }
  static struct svc_export *svc_export_update(struct svc_export *new,
                                            struct svc_export *old);
  static struct svc_export *svc_export_lookup(struct svc_export *);
@@@ -544,17 -535,13 +535,17 @@@ static int svc_export_parse(struct cach
                err = get_int(&mesg, &an_int);
                if (err)
                        goto out3;
 -              exp.ex_anon_uid= an_int;
 +              exp.ex_anon_uid= make_kuid(&init_user_ns, an_int);
 +              if (!uid_valid(exp.ex_anon_uid))
 +                      goto out3;
  
                /* anon gid */
                err = get_int(&mesg, &an_int);
                if (err)
                        goto out3;
 -              exp.ex_anon_gid= an_int;
 +              exp.ex_anon_gid= make_kgid(&init_user_ns, an_int);
 +              if (!gid_valid(exp.ex_anon_gid))
 +                      goto out3;
  
                /* fsid */
                err = get_int(&mesg, &an_int);
@@@ -617,7 -604,7 +608,7 @@@ out
  }
  
  static void exp_flags(struct seq_file *m, int flag, int fsid,
 -              uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fslocs);
 +              kuid_t anonu, kgid_t anong, struct nfsd4_fs_locations *fslocs);
  static void show_secinfo(struct seq_file *m, struct svc_export *exp);
  
  static int svc_export_show(struct seq_file *m,
@@@ -674,6 -661,7 +665,7 @@@ static void svc_export_init(struct cach
        new->ex_fslocs.locations = NULL;
        new->ex_fslocs.locations_count = 0;
        new->ex_fslocs.migrated = 0;
+       new->ex_uuid = NULL;
        new->cd = item->cd;
  }
  
@@@ -715,7 -703,7 +707,7 @@@ static struct cache_detail svc_export_c
        .hash_size      = EXPORT_HASHMAX,
        .name           = "nfsd.export",
        .cache_put      = svc_export_put,
-       .cache_upcall   = svc_export_upcall,
+       .cache_request  = svc_export_request,
        .cache_parse    = svc_export_parse,
        .cache_show     = svc_export_show,
        .match          = svc_export_match,
@@@ -1183,17 -1171,15 +1175,17 @@@ static void show_secinfo(struct seq_fil
  }
  
  static void exp_flags(struct seq_file *m, int flag, int fsid,
 -              uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fsloc)
 +              kuid_t anonu, kgid_t anong, struct nfsd4_fs_locations *fsloc)
  {
        show_expflags(m, flag, NFSEXP_ALLFLAGS);
        if (flag & NFSEXP_FSID)
                seq_printf(m, ",fsid=%d", fsid);
 -      if (anonu != (uid_t)-2 && anonu != (0x10000-2))
 -              seq_printf(m, ",anonuid=%u", anonu);
 -      if (anong != (gid_t)-2 && anong != (0x10000-2))
 -              seq_printf(m, ",anongid=%u", anong);
 +      if (!uid_eq(anonu, make_kuid(&init_user_ns, (uid_t)-2)) &&
 +          !uid_eq(anonu, make_kuid(&init_user_ns, 0x10000-2)))
 +              seq_printf(m, ",anonuid=%u", from_kuid(&init_user_ns, anonu));
 +      if (!gid_eq(anong, make_kgid(&init_user_ns, (gid_t)-2)) &&
 +          !gid_eq(anong, make_kgid(&init_user_ns, 0x10000-2)))
 +              seq_printf(m, ",anongid=%u", from_kgid(&init_user_ns, anong));
        if (fsloc && fsloc->locations_count > 0) {
                char *loctype = (fsloc->migrated) ? "refer" : "replicas";
                int i;
diff --combined fs/nfsd/fault_inject.c
@@@ -9,7 -9,7 +9,7 @@@
  #include <linux/debugfs.h>
  #include <linux/module.h>
  #include <linux/nsproxy.h>
- #include <linux/sunrpc/clnt.h>
+ #include <linux/sunrpc/addr.h>
  #include <asm/uaccess.h>
  
  #include "state.h"
@@@ -101,7 -101,7 +101,7 @@@ static ssize_t fault_inject_read(struc
        loff_t pos = *ppos;
  
        if (!pos)
 -              nfsd_inject_get(file->f_dentry->d_inode->i_private, &val);
 +              nfsd_inject_get(file_inode(file)->i_private, &val);
        size = scnprintf(read_buf, sizeof(read_buf), "%llu\n", val);
  
        if (pos < 0)
@@@ -133,10 -133,10 +133,10 @@@ static ssize_t fault_inject_write(struc
  
        size = rpc_pton(net, write_buf, size, (struct sockaddr *)&sa, sizeof(sa));
        if (size > 0)
 -              nfsd_inject_set_client(file->f_dentry->d_inode->i_private, &sa, size);
 +              nfsd_inject_set_client(file_inode(file)->i_private, &sa, size);
        else {
                val = simple_strtoll(write_buf, NULL, 0);
 -              nfsd_inject_set(file->f_dentry->d_inode->i_private, val);
 +              nfsd_inject_set(file_inode(file)->i_private, val);
        }
        return len; /* on success, claim we got the whole input */
  }
diff --combined fs/nfsd/nfs4idmap.c
@@@ -65,7 -65,7 +65,7 @@@ MODULE_PARM_DESC(nfs4_disable_idmapping
  struct ent {
        struct cache_head h;
        int               type;                /* User / Group */
 -      uid_t             id;
 +      u32               id;
        char              name[IDMAP_NAMESZ];
        char              authname[IDMAP_NAMESZ];
  };
@@@ -140,12 -140,6 +140,6 @@@ idtoname_request(struct cache_detail *c
  }
  
  static int
- idtoname_upcall(struct cache_detail *cd, struct cache_head *ch)
- {
-       return sunrpc_cache_pipe_upcall(cd, ch, idtoname_request);
- }
- static int
  idtoname_match(struct cache_head *ca, struct cache_head *cb)
  {
        struct ent *a = container_of(ca, struct ent, h);
@@@ -192,7 -186,7 +186,7 @@@ static struct cache_detail idtoname_cac
        .hash_size      = ENT_HASHMAX,
        .name           = "nfs4.idtoname",
        .cache_put      = ent_put,
-       .cache_upcall   = idtoname_upcall,
+       .cache_request  = idtoname_request,
        .cache_parse    = idtoname_parse,
        .cache_show     = idtoname_show,
        .warn_no_listener = warn_no_idmapd,
@@@ -321,12 -315,6 +315,6 @@@ nametoid_request(struct cache_detail *c
  }
  
  static int
- nametoid_upcall(struct cache_detail *cd, struct cache_head *ch)
- {
-       return sunrpc_cache_pipe_upcall(cd, ch, nametoid_request);
- }
- static int
  nametoid_match(struct cache_head *ca, struct cache_head *cb)
  {
        struct ent *a = container_of(ca, struct ent, h);
@@@ -365,7 -353,7 +353,7 @@@ static struct cache_detail nametoid_cac
        .hash_size      = ENT_HASHMAX,
        .name           = "nfs4.nametoid",
        .cache_put      = ent_put,
-       .cache_upcall   = nametoid_upcall,
+       .cache_request  = nametoid_request,
        .cache_parse    = nametoid_parse,
        .cache_show     = nametoid_show,
        .warn_no_listener = warn_no_idmapd,
@@@ -540,7 -528,7 +528,7 @@@ rqst_authname(struct svc_rqst *rqstp
  
  static __be32
  idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen,
 -              uid_t *id)
 +              u32 *id)
  {
        struct ent *item, key = {
                .type = type,
  }
  
  static int
 -idmap_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name)
 +idmap_id_to_name(struct svc_rqst *rqstp, int type, u32 id, char *name)
  {
        struct ent *item, key = {
                .id = id,
  }
  
  static bool
 -numeric_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, uid_t *id)
 +numeric_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, u32 *id)
  {
        int ret;
        char buf[11];
  }
  
  static __be32
 -do_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, uid_t *id)
 +do_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, u32 *id)
  {
        if (nfs4_disable_idmapping && rqstp->rq_cred.cr_flavor < RPC_AUTH_GSS)
                if (numeric_name_to_id(rqstp, type, name, namelen, id))
  }
  
  static int
 -do_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name)
 +do_id_to_name(struct svc_rqst *rqstp, int type, u32 id, char *name)
  {
        if (nfs4_disable_idmapping && rqstp->rq_cred.cr_flavor < RPC_AUTH_GSS)
                return sprintf(name, "%u", id);
  
  __be32
  nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen,
 -              __u32 *id)
 +              kuid_t *uid)
  {
 -      return do_name_to_id(rqstp, IDMAP_TYPE_USER, name, namelen, id);
 +      __be32 status;
 +      u32 id = -1;
 +      status = do_name_to_id(rqstp, IDMAP_TYPE_USER, name, namelen, &id);
 +      *uid = make_kuid(&init_user_ns, id);
 +      if (!uid_valid(*uid))
 +              status = nfserr_badowner;
 +      return status;
  }
  
  __be32
  nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen,
 -              __u32 *id)
 +              kgid_t *gid)
  {
 -      return do_name_to_id(rqstp, IDMAP_TYPE_GROUP, name, namelen, id);
 +      __be32 status;
 +      u32 id = -1;
 +      status = do_name_to_id(rqstp, IDMAP_TYPE_GROUP, name, namelen, &id);
 +      *gid = make_kgid(&init_user_ns, id);
 +      if (!gid_valid(*gid))
 +              status = nfserr_badowner;
 +      return status;
  }
  
  int
 -nfsd_map_uid_to_name(struct svc_rqst *rqstp, __u32 id, char *name)
 +nfsd_map_uid_to_name(struct svc_rqst *rqstp, kuid_t uid, char *name)
  {
 +      u32 id = from_kuid(&init_user_ns, uid);
        return do_id_to_name(rqstp, IDMAP_TYPE_USER, id, name);
  }
  
  int
 -nfsd_map_gid_to_name(struct svc_rqst *rqstp, __u32 id, char *name)
 +nfsd_map_gid_to_name(struct svc_rqst *rqstp, kgid_t gid, char *name)
  {
 +      u32 id = from_kgid(&init_user_ns, gid);
        return do_id_to_name(rqstp, IDMAP_TYPE_GROUP, id, name);
  }
diff --combined fs/nfsd/nfs4recover.c
@@@ -73,8 -73,8 +73,8 @@@ nfs4_save_creds(const struct cred **ori
        if (!new)
                return -ENOMEM;
  
 -      new->fsuid = 0;
 -      new->fsgid = 0;
 +      new->fsuid = GLOBAL_ROOT_UID;
 +      new->fsgid = GLOBAL_ROOT_GID;
        *original_creds = override_creds(new);
        put_cred(new);
        return 0;
@@@ -1185,6 -1185,12 +1185,12 @@@ bin_to_hex_dup(const unsigned char *src
  static int
  nfsd4_umh_cltrack_init(struct net __attribute__((unused)) *net)
  {
+       /* XXX: The usermode helper s not working in container yet. */
+       if (net != &init_net) {
+               WARN(1, KERN_ERR "NFSD: attempt to initialize umh client "
+                       "tracking in a container!\n");
+               return -EINVAL;
+       }
        return nfsd4_umh_cltrack_upcall("init", NULL, NULL);
  }
  
diff --combined fs/nfsd/nfs4state.c
@@@ -40,7 -40,7 +40,7 @@@
  #include <linux/pagemap.h>
  #include <linux/ratelimit.h>
  #include <linux/sunrpc/svcauth_gss.h>
- #include <linux/sunrpc/clnt.h>
+ #include <linux/sunrpc/addr.h>
  #include "xdr4.h"
  #include "vfs.h"
  #include "current_stateid.h"
@@@ -151,7 -151,7 +151,7 @@@ get_nfs4_file(struct nfs4_file *fi
  }
  
  static int num_delegations;
 -unsigned int max_delegations;
 +unsigned long max_delegations;
  
  /*
   * Open owner state (share locks)
@@@ -261,33 -261,46 +261,46 @@@ static inline int get_new_stid(struct n
        return new_stid;
  }
  
- static void init_stid(struct nfs4_stid *stid, struct nfs4_client *cl, unsigned char type)
+ static struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct
+ kmem_cache *slab)
  {
-       stateid_t *s = &stid->sc_stateid;
+       struct idr *stateids = &cl->cl_stateids;
+       static int min_stateid = 0;
+       struct nfs4_stid *stid;
        int new_id;
  
-       stid->sc_type = type;
+       stid = kmem_cache_alloc(slab, GFP_KERNEL);
+       if (!stid)
+               return NULL;
+       if (!idr_pre_get(stateids, GFP_KERNEL))
+               goto out_free;
+       if (idr_get_new_above(stateids, stid, min_stateid, &new_id))
+               goto out_free;
        stid->sc_client = cl;
-       s->si_opaque.so_clid = cl->cl_clientid;
-       new_id = get_new_stid(stid);
-       s->si_opaque.so_id = (u32)new_id;
+       stid->sc_type = 0;
+       stid->sc_stateid.si_opaque.so_id = new_id;
+       stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid;
        /* Will be incremented before return to client: */
-       s->si_generation = 0;
- }
- static struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab)
- {
-       struct idr *stateids = &cl->cl_stateids;
+       stid->sc_stateid.si_generation = 0;
  
-       if (!idr_pre_get(stateids, GFP_KERNEL))
-               return NULL;
        /*
-        * Note: if we fail here (or any time between now and the time
-        * we actually get the new idr), we won't need to undo the idr
-        * preallocation, since the idr code caps the number of
-        * preallocated entries.
+        * It shouldn't be a problem to reuse an opaque stateid value.
+        * I don't think it is for 4.1.  But with 4.0 I worry that, for
+        * example, a stray write retransmission could be accepted by
+        * the server when it should have been rejected.  Therefore,
+        * adopt a trick from the sctp code to attempt to maximize the
+        * amount of time until an id is reused, by ensuring they always
+        * "increase" (mod INT_MAX):
         */
-       return kmem_cache_alloc(slab, GFP_KERNEL);
+       min_stateid = new_id+1;
+       if (min_stateid == INT_MAX)
+               min_stateid = 0;
+       return stid;
+ out_free:
+       kfree(stid);
+       return NULL;
  }
  
  static struct nfs4_ol_stateid * nfs4_alloc_stateid(struct nfs4_client *clp)
@@@ -316,7 -329,7 +329,7 @@@ alloc_init_deleg(struct nfs4_client *cl
        dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab));
        if (dp == NULL)
                return dp;
-       init_stid(&dp->dl_stid, clp, NFS4_DELEG_STID);
+       dp->dl_stid.sc_type = NFS4_DELEG_STID;
        /*
         * delegation seqid's are never incremented.  The 4.1 special
         * meaning of seqid 0 isn't meaningful, really, but let's avoid
        return dp;
  }
  
+ static void free_stid(struct nfs4_stid *s, struct kmem_cache *slab)
+ {
+       struct idr *stateids = &s->sc_client->cl_stateids;
+       idr_remove(stateids, s->sc_stateid.si_opaque.so_id);
+       kmem_cache_free(slab, s);
+ }
  void
  nfs4_put_delegation(struct nfs4_delegation *dp)
  {
        if (atomic_dec_and_test(&dp->dl_count)) {
                dprintk("NFSD: freeing dp %p\n",dp);
                put_nfs4_file(dp->dl_file);
-               kmem_cache_free(deleg_slab, dp);
+               free_stid(&dp->dl_stid, deleg_slab);
                num_delegations--;
        }
  }
@@@ -360,9 -381,7 +381,7 @@@ static void nfs4_put_deleg_lease(struc
  
  static void unhash_stid(struct nfs4_stid *s)
  {
-       struct idr *stateids = &s->sc_client->cl_stateids;
-       idr_remove(stateids, s->sc_stateid.si_opaque.so_id);
+       s->sc_type = 0;
  }
  
  /* Called under the state lock. */
@@@ -519,7 -538,7 +538,7 @@@ static void close_generic_stateid(struc
  
  static void free_generic_stateid(struct nfs4_ol_stateid *stp)
  {
-       kmem_cache_free(stateid_slab, stp);
+       free_stid(&stp->st_stid, stateid_slab);
  }
  
  static void release_lock_stateid(struct nfs4_ol_stateid *stp)
@@@ -700,8 -719,8 +719,8 @@@ static int nfsd4_get_drc_mem(int slotsi
        num = min_t(u32, num, NFSD_MAX_SLOTS_PER_SESSION);
  
        spin_lock(&nfsd_drc_lock);
 -      avail = min_t(int, NFSD_MAX_MEM_PER_SESSION,
 -                      nfsd_drc_max_mem - nfsd_drc_mem_used);
 +      avail = min((unsigned long)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);
@@@ -905,7 -924,7 +924,7 @@@ static struct nfsd4_session *alloc_sess
  
        new = __alloc_session(slotsize, numslots);
        if (!new) {
-               nfsd4_put_drc_mem(slotsize, fchan->maxreqs);
+               nfsd4_put_drc_mem(slotsize, numslots);
                return NULL;
        }
        init_forechannel_attrs(&new->se_fchannel, fchan, numslots, slotsize, nn);
@@@ -1048,7 -1067,7 +1067,7 @@@ static struct nfs4_client *alloc_client
  static inline void
  free_client(struct nfs4_client *clp)
  {
-       struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
+       struct nfsd_net __maybe_unused *nn = net_generic(clp->net, nfsd_net_id);
  
        lockdep_assert_held(&nn->client_lock);
        while (!list_empty(&clp->cl_sessions)) {
        }
        free_svc_cred(&clp->cl_cred);
        kfree(clp->cl_name.data);
 -      idr_remove_all(&clp->cl_stateids);
+       idr_destroy(&clp->cl_stateids);
        kfree(clp);
  }
  
@@@ -1202,7 -1223,7 +1222,7 @@@ static bool groups_equal(struct group_i
        if (g1->ngroups != g2->ngroups)
                return false;
        for (i=0; i<g1->ngroups; i++)
 -              if (GROUP_AT(g1, i) != GROUP_AT(g2, i))
 +              if (!gid_eq(GROUP_AT(g1, i), GROUP_AT(g2, i)))
                        return false;
        return true;
  }
@@@ -1227,8 -1248,8 +1247,8 @@@ static boo
  same_creds(struct svc_cred *cr1, struct svc_cred *cr2)
  {
        if ((is_gss_cred(cr1) != is_gss_cred(cr2))
 -              || (cr1->cr_uid != cr2->cr_uid)
 -              || (cr1->cr_gid != cr2->cr_gid)
 +              || (!uid_eq(cr1->cr_uid, cr2->cr_uid))
 +              || (!gid_eq(cr1->cr_gid, cr2->cr_gid))
                || !groups_equal(cr1->cr_group_info, cr2->cr_group_info))
                return false;
        if (cr1->cr_principal == cr2->cr_principal)
@@@ -1258,7 -1279,12 +1278,12 @@@ static void gen_confirm(struct nfs4_cli
  
  static struct nfs4_stid *find_stateid(struct nfs4_client *cl, stateid_t *t)
  {
-       return idr_find(&cl->cl_stateids, t->si_opaque.so_id);
+       struct nfs4_stid *ret;
+       ret = idr_find(&cl->cl_stateids, t->si_opaque.so_id);
+       if (!ret || !ret->sc_type)
+               return NULL;
+       return ret;
  }
  
  static struct nfs4_stid *find_stateid_by_type(struct nfs4_client *cl, stateid_t *t, char typemask)
@@@ -1844,11 -1870,12 +1869,12 @@@ nfsd4_create_session(struct svc_rqst *r
  
        /* cache solo and embedded create sessions under the state lock */
        nfsd4_cache_create_session(cr_ses, cs_slot, status);
- out:
        nfs4_unlock_state();
+ out:
        dprintk("%s returns %d\n", __func__, ntohl(status));
        return status;
  out_free_conn:
+       nfs4_unlock_state();
        free_conn(conn);
  out_free_session:
        __free_session(new);
@@@ -2443,9 -2470,8 +2469,8 @@@ alloc_init_open_stateowner(unsigned in
  
  static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) {
        struct nfs4_openowner *oo = open->op_openowner;
-       struct nfs4_client *clp = oo->oo_owner.so_client;
  
-       init_stid(&stp->st_stid, clp, NFS4_OPEN_STID);
+       stp->st_stid.sc_type = NFS4_OPEN_STID;
        INIT_LIST_HEAD(&stp->st_lockowners);
        list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids);
        list_add(&stp->st_perfile, &fp->fi_stateids);
@@@ -4031,7 -4057,7 +4056,7 @@@ alloc_init_lock_stateid(struct nfs4_loc
        stp = nfs4_alloc_stateid(clp);
        if (stp == NULL)
                return NULL;
-       init_stid(&stp->st_stid, clp, NFS4_LOCK_STID);
+       stp->st_stid.sc_type = NFS4_LOCK_STID;
        list_add(&stp->st_perfile, &fp->fi_stateids);
        list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids);
        stp->st_stateowner = &lo->lo_owner;
@@@ -4913,16 -4939,6 +4938,6 @@@ nfs4_state_start_net(struct net *net
        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
        int ret;
  
-       /*
-        * FIXME: For now, we hang most of the pernet global stuff off of
-        * init_net until nfsd is fully containerized. Eventually, we'll
-        * need to pass a net pointer into this function, take a reference
-        * to that instead and then do most of the rest of this on a per-net
-        * basis.
-        */
-       if (net != &init_net)
-               return -EINVAL;
        ret = nfs4_state_create_net(net);
        if (ret)
                return ret;
diff --combined fs/nfsd/nfs4xdr.c
@@@ -293,13 -293,13 +293,13 @@@ nfsd4_decode_fattr(struct nfsd4_compoun
                        ace->whotype = nfs4_acl_get_whotype(buf, dummy32);
                        status = nfs_ok;
                        if (ace->whotype != NFS4_ACL_WHO_NAMED)
 -                              ace->who = 0;
 +                              ;
                        else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP)
                                status = nfsd_map_name_to_gid(argp->rqstp,
 -                                              buf, dummy32, &ace->who);
 +                                              buf, dummy32, &ace->who_gid);
                        else
                                status = nfsd_map_name_to_uid(argp->rqstp,
 -                                              buf, dummy32, &ace->who);
 +                                              buf, dummy32, &ace->who_uid);
                        if (status)
                                return status;
                }
@@@ -464,16 -464,9 +464,16 @@@ static __be32 nfsd4_decode_cb_sec(struc
                        READ32(dummy);
                        READ_BUF(dummy * 4);
                        if (cbs->flavor == (u32)(-1)) {
 -                              cbs->uid = uid;
 -                              cbs->gid = gid;
 -                              cbs->flavor = RPC_AUTH_UNIX;
 +                              kuid_t kuid = make_kuid(&init_user_ns, uid);
 +                              kgid_t kgid = make_kgid(&init_user_ns, gid);
 +                              if (uid_valid(kuid) && gid_valid(kgid)) {
 +                                      cbs->uid = kuid;
 +                                      cbs->gid = kgid;
 +                                      cbs->flavor = RPC_AUTH_UNIX;
 +                              } else {
 +                                      dprintk("RPC_AUTH_UNIX with invalid"
 +                                              "uid or gid ignoring!\n");
 +                              }
                        }
                        break;
                case RPC_AUTH_GSS:
@@@ -1933,7 -1926,7 +1933,7 @@@ static u32 nfs4_file_type(umode_t mode
  }
  
  static __be32
 -nfsd4_encode_name(struct svc_rqst *rqstp, int whotype, uid_t id, int group,
 +nfsd4_encode_name(struct svc_rqst *rqstp, int whotype, kuid_t uid, kgid_t gid,
                        __be32 **p, int *buflen)
  {
        int status;
                return nfserr_resource;
        if (whotype != NFS4_ACL_WHO_NAMED)
                status = nfs4_acl_write_who(whotype, (u8 *)(*p + 1));
 -      else if (group)
 -              status = nfsd_map_gid_to_name(rqstp, id, (u8 *)(*p + 1));
 +      else if (gid_valid(gid))
 +              status = nfsd_map_gid_to_name(rqstp, gid, (u8 *)(*p + 1));
        else
 -              status = nfsd_map_uid_to_name(rqstp, id, (u8 *)(*p + 1));
 +              status = nfsd_map_uid_to_name(rqstp, uid, (u8 *)(*p + 1));
        if (status < 0)
                return nfserrno(status);
        *p = xdr_encode_opaque(*p, NULL, status);
  }
  
  static inline __be32
 -nfsd4_encode_user(struct svc_rqst *rqstp, uid_t uid, __be32 **p, int *buflen)
 +nfsd4_encode_user(struct svc_rqst *rqstp, kuid_t user, __be32 **p, int *buflen)
  {
 -      return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, uid, 0, p, buflen);
 +      return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, user, INVALID_GID,
 +                               p, buflen);
  }
  
  static inline __be32
 -nfsd4_encode_group(struct svc_rqst *rqstp, uid_t gid, __be32 **p, int *buflen)
 +nfsd4_encode_group(struct svc_rqst *rqstp, kgid_t group, __be32 **p, int *buflen)
  {
 -      return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, gid, 1, p, buflen);
 +      return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, INVALID_UID, group,
 +                               p, buflen);
  }
  
  static inline __be32
 -nfsd4_encode_aclname(struct svc_rqst *rqstp, int whotype, uid_t id, int group,
 +nfsd4_encode_aclname(struct svc_rqst *rqstp, struct nfs4_ace *ace,
                __be32 **p, int *buflen)
  {
 -      return nfsd4_encode_name(rqstp, whotype, id, group, p, buflen);
 +      kuid_t uid = INVALID_UID;
 +      kgid_t gid = INVALID_GID;
 +
 +      if (ace->whotype == NFS4_ACL_WHO_NAMED) {
 +              if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP)
 +                      gid = ace->who_gid;
 +              else
 +                      uid = ace->who_uid;
 +      }
 +      return nfsd4_encode_name(rqstp, ace->whotype, uid, gid, p, buflen);
  }
  
  #define WORD0_ABSENT_FS_ATTRS (FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_FSID | \
@@@ -2015,7 -1997,7 +2015,7 @@@ static int get_parent_attributes(struc
                if (path.dentry != path.mnt->mnt_root)
                        break;
        }
 -      err = vfs_getattr(path.mnt, path.dentry, stat);
 +      err = vfs_getattr(&path, stat);
        path_put(&path);
        return err;
  }
   * Note: @fhp can be NULL; in this case, we might have to compose the filehandle
   * ourselves.
   *
-  * @countp is the buffer size in _words_; upon successful return this becomes
-  * replaced with the number of words written.
+  * countp is the buffer size in _words_
   */
  __be32
  nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
-               struct dentry *dentry, __be32 *buffer, int *countp, u32 *bmval,
+               struct dentry *dentry, __be32 **buffer, int count, u32 *bmval,
                struct svc_rqst *rqstp, int ignore_crossmnt)
  {
        u32 bmval0 = bmval[0];
        struct kstat stat;
        struct svc_fh tempfh;
        struct kstatfs statfs;
-       int buflen = *countp << 2;
+       int buflen = count << 2;
        __be32 *attrlenp;
        u32 dummy;
        u64 dummy64;
        u32 rdattr_err = 0;
-       __be32 *p = buffer;
+       __be32 *p = *buffer;
        __be32 status;
        int err;
        int aclsupport = 0;
                        goto out;
        }
  
 -      err = vfs_getattr(exp->ex_path.mnt, dentry, &stat);
 +      err = vfs_getattr(&path, &stat);
        if (err)
                goto out_nfserr;
        if ((bmval0 & (FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL |
                        WRITE32(ace->type);
                        WRITE32(ace->flag);
                        WRITE32(ace->access_mask & NFS4_ACE_MASK_ALL);
 -                      status = nfsd4_encode_aclname(rqstp, ace->whotype,
 -                              ace->who, ace->flag & NFS4_ACE_IDENTIFIER_GROUP,
 -                              &p, &buflen);
 +                      status = nfsd4_encode_aclname(rqstp, ace, &p, &buflen);
                        if (status == nfserr_resource)
                                goto out_resource;
                        if (status)
@@@ -2447,7 -2430,7 +2446,7 @@@ out_acl
        }
  
        *attrlenp = htonl((char *)p - (char *)attrlenp - 4);
-       *countp = p - buffer;
+       *buffer = p;
        status = nfs_ok;
  
  out:
@@@ -2459,7 -2442,6 +2458,6 @@@ out_nfserr
        status = nfserrno(err);
        goto out;
  out_resource:
-       *countp = 0;
        status = nfserr_resource;
        goto out;
  out_serverfault:
@@@ -2478,7 -2460,7 +2476,7 @@@ static inline int attributes_need_mount
  
  static __be32
  nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
-               const char *name, int namlen, __be32 *p, int *buflen)
+               const char *name, int namlen, __be32 **p, int buflen)
  {
        struct svc_export *exp = cd->rd_fhp->fh_export;
        struct dentry *dentry;
@@@ -2584,10 -2566,9 +2582,9 @@@ nfsd4_encode_dirent(void *ccdv, const c
        p = xdr_encode_hyper(p, NFS_OFFSET_MAX);    /* offset of next entry */
        p = xdr_encode_array(p, name, namlen);      /* name length & name */
  
-       nfserr = nfsd4_encode_dirent_fattr(cd, name, namlen, p, &buflen);
+       nfserr = nfsd4_encode_dirent_fattr(cd, name, namlen, &p, buflen);
        switch (nfserr) {
        case nfs_ok:
-               p += buflen;
                break;
        case nfserr_resource:
                nfserr = nfserr_toosmall;
@@@ -2714,10 -2695,8 +2711,8 @@@ nfsd4_encode_getattr(struct nfsd4_compo
  
        buflen = resp->end - resp->p - (COMPOUND_ERR_SLACK_SPACE >> 2);
        nfserr = nfsd4_encode_fattr(fhp, fhp->fh_export, fhp->fh_dentry,
-                                   resp->p, &buflen, getattr->ga_bmval,
+                                   &resp->p, buflen, getattr->ga_bmval,
                                    resp->rqstp, 0);
-       if (!nfserr)
-               resp->p += buflen;
        return nfserr;
  }
  
diff --combined fs/nfsd/nfscache.c
@@@ -9,22 -9,22 +9,22 @@@
   */
  
  #include <linux/slab.h>
+ #include <linux/sunrpc/addr.h>
+ #include <linux/highmem.h>
+ #include <net/checksum.h>
  
  #include "nfsd.h"
  #include "cache.h"
  
- /* Size of reply cache. Common values are:
-  * 4.3BSD:    128
-  * 4.4BSD:    256
-  * Solaris2:  1024
-  * DEC Unix:  512-4096
-  */
- #define CACHESIZE             1024
+ #define NFSDDBG_FACILITY      NFSDDBG_REPCACHE
  #define HASHSIZE              64
  
  static struct hlist_head *    cache_hash;
  static struct list_head       lru_head;
- static int                    cache_disabled = 1;
+ static struct kmem_cache      *drc_slab;
+ static unsigned int           num_drc_entries;
+ static unsigned int           max_drc_entries;
  
  /*
   * Calculate the hash index from an XID.
@@@ -37,6 -37,14 +37,14 @@@ static inline u32 request_hash(u32 xid
  }
  
  static int    nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *vec);
+ static void   cache_cleaner_func(struct work_struct *unused);
+ static int    nfsd_reply_cache_shrink(struct shrinker *shrink,
+                                       struct shrink_control *sc);
+ struct shrinker nfsd_reply_cache_shrinker = {
+       .shrink = nfsd_reply_cache_shrink,
+       .seeks  = 1,
+ };
  
  /*
   * locking for the reply cache:
   * Otherwise, it when accessing _prev or _next, the lock must be held.
   */
  static DEFINE_SPINLOCK(cache_lock);
+ static DECLARE_DELAYED_WORK(cache_cleaner, cache_cleaner_func);
  
- int nfsd_reply_cache_init(void)
+ /*
+  * Put a cap on the size of the DRC based on the amount of available
+  * low memory in the machine.
+  *
+  *  64MB:    8192
+  * 128MB:   11585
+  * 256MB:   16384
+  * 512MB:   23170
+  *   1GB:   32768
+  *   2GB:   46340
+  *   4GB:   65536
+  *   8GB:   92681
+  *  16GB:  131072
+  *
+  * ...with a hard cap of 256k entries. In the worst case, each entry will be
+  * ~1k, so the above numbers should give a rough max of the amount of memory
+  * used in k.
+  */
+ static unsigned int
+ nfsd_cache_size_limit(void)
+ {
+       unsigned int limit;
+       unsigned long low_pages = totalram_pages - totalhigh_pages;
+       limit = (16 * int_sqrt(low_pages)) << (PAGE_SHIFT-10);
+       return min_t(unsigned int, limit, 256*1024);
+ }
+ static struct svc_cacherep *
+ nfsd_reply_cache_alloc(void)
  {
        struct svc_cacherep     *rp;
-       int                     i;
  
-       INIT_LIST_HEAD(&lru_head);
-       i = CACHESIZE;
-       while (i) {
-               rp = kmalloc(sizeof(*rp), GFP_KERNEL);
-               if (!rp)
-                       goto out_nomem;
-               list_add(&rp->c_lru, &lru_head);
+       rp = kmem_cache_alloc(drc_slab, GFP_KERNEL);
+       if (rp) {
                rp->c_state = RC_UNUSED;
                rp->c_type = RC_NOCACHE;
+               INIT_LIST_HEAD(&rp->c_lru);
                INIT_HLIST_NODE(&rp->c_hash);
-               i--;
        }
+       return rp;
+ }
  
-       cache_hash = kcalloc (HASHSIZE, sizeof(struct hlist_head), GFP_KERNEL);
+ static void
+ nfsd_reply_cache_free_locked(struct svc_cacherep *rp)
+ {
+       if (rp->c_type == RC_REPLBUFF)
+               kfree(rp->c_replvec.iov_base);
+       hlist_del(&rp->c_hash);
+       list_del(&rp->c_lru);
+       --num_drc_entries;
+       kmem_cache_free(drc_slab, rp);
+ }
+ static void
+ nfsd_reply_cache_free(struct svc_cacherep *rp)
+ {
+       spin_lock(&cache_lock);
+       nfsd_reply_cache_free_locked(rp);
+       spin_unlock(&cache_lock);
+ }
+ int nfsd_reply_cache_init(void)
+ {
+       register_shrinker(&nfsd_reply_cache_shrinker);
+       drc_slab = kmem_cache_create("nfsd_drc", sizeof(struct svc_cacherep),
+                                       0, 0, NULL);
+       if (!drc_slab)
+               goto out_nomem;
+       cache_hash = kcalloc(HASHSIZE, sizeof(struct hlist_head), GFP_KERNEL);
        if (!cache_hash)
                goto out_nomem;
  
-       cache_disabled = 0;
+       INIT_LIST_HEAD(&lru_head);
+       max_drc_entries = nfsd_cache_size_limit();
+       num_drc_entries = 0;
        return 0;
  out_nomem:
        printk(KERN_ERR "nfsd: failed to allocate reply cache\n");
@@@ -79,27 -143,33 +143,33 @@@ void nfsd_reply_cache_shutdown(void
  {
        struct svc_cacherep     *rp;
  
+       unregister_shrinker(&nfsd_reply_cache_shrinker);
+       cancel_delayed_work_sync(&cache_cleaner);
        while (!list_empty(&lru_head)) {
                rp = list_entry(lru_head.next, struct svc_cacherep, c_lru);
-               if (rp->c_state == RC_DONE && rp->c_type == RC_REPLBUFF)
-                       kfree(rp->c_replvec.iov_base);
-               list_del(&rp->c_lru);
-               kfree(rp);
+               nfsd_reply_cache_free_locked(rp);
        }
  
-       cache_disabled = 1;
        kfree (cache_hash);
        cache_hash = NULL;
+       if (drc_slab) {
+               kmem_cache_destroy(drc_slab);
+               drc_slab = NULL;
+       }
  }
  
  /*
-  * Move cache entry to end of LRU list
+  * Move cache entry to end of LRU list, and queue the cleaner to run if it's
+  * not already scheduled.
   */
  static void
  lru_put_end(struct svc_cacherep *rp)
  {
+       rp->c_timestamp = jiffies;
        list_move_tail(&rp->c_lru, &lru_head);
+       schedule_delayed_work(&cache_cleaner, RC_EXPIRE);
  }
  
  /*
@@@ -112,82 -182,215 +182,214 @@@ hash_refile(struct svc_cacherep *rp
        hlist_add_head(&rp->c_hash, cache_hash + request_hash(rp->c_xid));
  }
  
 -      struct hlist_node       *hn;
+ static inline bool
+ nfsd_cache_entry_expired(struct svc_cacherep *rp)
+ {
+       return rp->c_state != RC_INPROG &&
+              time_after(jiffies, rp->c_timestamp + RC_EXPIRE);
+ }
+ /*
+  * Walk the LRU list and prune off entries that are older than RC_EXPIRE.
+  * Also prune the oldest ones when the total exceeds the max number of entries.
+  */
+ static void
+ prune_cache_entries(void)
+ {
+       struct svc_cacherep *rp, *tmp;
+       list_for_each_entry_safe(rp, tmp, &lru_head, c_lru) {
+               if (!nfsd_cache_entry_expired(rp) &&
+                   num_drc_entries <= max_drc_entries)
+                       break;
+               nfsd_reply_cache_free_locked(rp);
+       }
+       /*
+        * Conditionally rearm the job. If we cleaned out the list, then
+        * cancel any pending run (since there won't be any work to do).
+        * Otherwise, we rearm the job or modify the existing one to run in
+        * RC_EXPIRE since we just ran the pruner.
+        */
+       if (list_empty(&lru_head))
+               cancel_delayed_work(&cache_cleaner);
+       else
+               mod_delayed_work(system_wq, &cache_cleaner, RC_EXPIRE);
+ }
+ static void
+ cache_cleaner_func(struct work_struct *unused)
+ {
+       spin_lock(&cache_lock);
+       prune_cache_entries();
+       spin_unlock(&cache_lock);
+ }
+ static int
+ nfsd_reply_cache_shrink(struct shrinker *shrink, struct shrink_control *sc)
+ {
+       unsigned int num;
+       spin_lock(&cache_lock);
+       if (sc->nr_to_scan)
+               prune_cache_entries();
+       num = num_drc_entries;
+       spin_unlock(&cache_lock);
+       return num;
+ }
+ /*
+  * Walk an xdr_buf and get a CRC for at most the first RC_CSUMLEN bytes
+  */
+ static __wsum
+ nfsd_cache_csum(struct svc_rqst *rqstp)
+ {
+       int idx;
+       unsigned int base;
+       __wsum csum;
+       struct xdr_buf *buf = &rqstp->rq_arg;
+       const unsigned char *p = buf->head[0].iov_base;
+       size_t csum_len = min_t(size_t, buf->head[0].iov_len + buf->page_len,
+                               RC_CSUMLEN);
+       size_t len = min(buf->head[0].iov_len, csum_len);
+       /* rq_arg.head first */
+       csum = csum_partial(p, len, 0);
+       csum_len -= len;
+       /* Continue into page array */
+       idx = buf->page_base / PAGE_SIZE;
+       base = buf->page_base & ~PAGE_MASK;
+       while (csum_len) {
+               p = page_address(buf->pages[idx]) + base;
+               len = min_t(size_t, PAGE_SIZE - base, csum_len);
+               csum = csum_partial(p, len, csum);
+               csum_len -= len;
+               base = 0;
+               ++idx;
+       }
+       return csum;
+ }
+ /*
+  * Search the request hash for an entry that matches the given rqstp.
+  * Must be called with cache_lock held. Returns the found entry or
+  * NULL on failure.
+  */
+ static struct svc_cacherep *
+ nfsd_cache_search(struct svc_rqst *rqstp, __wsum csum)
+ {
+       struct svc_cacherep     *rp;
 -      hlist_for_each_entry(rp, hn, rh, c_hash) {
+       struct hlist_head       *rh;
+       __be32                  xid = rqstp->rq_xid;
+       u32                     proto =  rqstp->rq_prot,
+                               vers = rqstp->rq_vers,
+                               proc = rqstp->rq_proc;
+       rh = &cache_hash[request_hash(xid)];
++      hlist_for_each_entry(rp, rh, c_hash) {
+               if (xid == rp->c_xid && proc == rp->c_proc &&
+                   proto == rp->c_prot && vers == rp->c_vers &&
+                   rqstp->rq_arg.len == rp->c_len && csum == rp->c_csum &&
+                   rpc_cmp_addr(svc_addr(rqstp), (struct sockaddr *)&rp->c_addr) &&
+                   rpc_get_port(svc_addr(rqstp)) == rpc_get_port((struct sockaddr *)&rp->c_addr))
+                       return rp;
+       }
+       return NULL;
+ }
  /*
   * Try to find an entry matching the current call in the cache. When none
-  * is found, we grab the oldest unlocked entry off the LRU list.
-  * Note that no operation within the loop may sleep.
+  * is found, we try to grab the oldest expired entry off the LRU list. If
+  * a suitable one isn't there, then drop the cache_lock and allocate a
+  * new one, then search again in case one got inserted while this thread
+  * didn't hold the lock.
   */
  int
  nfsd_cache_lookup(struct svc_rqst *rqstp)
  {
-       struct hlist_head       *rh;
-       struct svc_cacherep     *rp;
+       struct svc_cacherep     *rp, *found;
        __be32                  xid = rqstp->rq_xid;
        u32                     proto =  rqstp->rq_prot,
                                vers = rqstp->rq_vers,
                                proc = rqstp->rq_proc;
+       __wsum                  csum;
        unsigned long           age;
        int type = rqstp->rq_cachetype;
        int rtn;
  
        rqstp->rq_cacherep = NULL;
-       if (cache_disabled || type == RC_NOCACHE) {
+       if (type == RC_NOCACHE) {
                nfsdstats.rcnocache++;
                return RC_DOIT;
        }
  
+       csum = nfsd_cache_csum(rqstp);
        spin_lock(&cache_lock);
        rtn = RC_DOIT;
  
-       rh = &cache_hash[request_hash(xid)];
-       hlist_for_each_entry(rp, rh, c_hash) {
-               if (rp->c_state != RC_UNUSED &&
-                   xid == rp->c_xid && proc == rp->c_proc &&
-                   proto == rp->c_prot && vers == rp->c_vers &&
-                   time_before(jiffies, rp->c_timestamp + 120*HZ) &&
-                   memcmp((char*)&rqstp->rq_addr, (char*)&rp->c_addr, sizeof(rp->c_addr))==0) {
-                       nfsdstats.rchits++;
-                       goto found_entry;
+       rp = nfsd_cache_search(rqstp, csum);
+       if (rp)
+               goto found_entry;
+       /* Try to use the first entry on the LRU */
+       if (!list_empty(&lru_head)) {
+               rp = list_first_entry(&lru_head, struct svc_cacherep, c_lru);
+               if (nfsd_cache_entry_expired(rp) ||
+                   num_drc_entries >= max_drc_entries) {
+                       lru_put_end(rp);
+                       prune_cache_entries();
+                       goto setup_entry;
                }
        }
-       nfsdstats.rcmisses++;
  
-       /* This loop shouldn't take more than a few iterations normally */
-       {
-       int     safe = 0;
-       list_for_each_entry(rp, &lru_head, c_lru) {
-               if (rp->c_state != RC_INPROG)
-                       break;
-               if (safe++ > CACHESIZE) {
-                       printk("nfsd: loop in repcache LRU list\n");
-                       cache_disabled = 1;
-                       goto out;
-               }
+       /* Drop the lock and allocate a new entry */
+       spin_unlock(&cache_lock);
+       rp = nfsd_reply_cache_alloc();
+       if (!rp) {
+               dprintk("nfsd: unable to allocate DRC entry!\n");
+               return RC_DOIT;
        }
+       spin_lock(&cache_lock);
+       ++num_drc_entries;
+       /*
+        * Must search again just in case someone inserted one
+        * after we dropped the lock above.
+        */
+       found = nfsd_cache_search(rqstp, csum);
+       if (found) {
+               nfsd_reply_cache_free_locked(rp);
+               rp = found;
+               goto found_entry;
        }
  
-       /* All entries on the LRU are in-progress. This should not happen */
-       if (&rp->c_lru == &lru_head) {
-               static int      complaints;
-               printk(KERN_WARNING "nfsd: all repcache entries locked!\n");
-               if (++complaints > 5) {
-                       printk(KERN_WARNING "nfsd: disabling repcache.\n");
-                       cache_disabled = 1;
-               }
-               goto out;
-       }
+       /*
+        * We're keeping the one we just allocated. Are we now over the
+        * limit? Prune one off the tip of the LRU in trade for the one we
+        * just allocated if so.
+        */
+       if (num_drc_entries >= max_drc_entries)
+               nfsd_reply_cache_free_locked(list_first_entry(&lru_head,
+                                               struct svc_cacherep, c_lru));
  
+ setup_entry:
+       nfsdstats.rcmisses++;
        rqstp->rq_cacherep = rp;
        rp->c_state = RC_INPROG;
        rp->c_xid = xid;
        rp->c_proc = proc;
-       memcpy(&rp->c_addr, svc_addr_in(rqstp), sizeof(rp->c_addr));
+       rpc_copy_addr((struct sockaddr *)&rp->c_addr, svc_addr(rqstp));
+       rpc_set_port((struct sockaddr *)&rp->c_addr, rpc_get_port(svc_addr(rqstp)));
        rp->c_prot = proto;
        rp->c_vers = vers;
-       rp->c_timestamp = jiffies;
+       rp->c_len = rqstp->rq_arg.len;
+       rp->c_csum = csum;
  
        hash_refile(rp);
+       lru_put_end(rp);
  
        /* release any buffer */
        if (rp->c_type == RC_REPLBUFF) {
        return rtn;
  
  found_entry:
+       nfsdstats.rchits++;
        /* We found a matching entry which is either in progress or done. */
        age = jiffies - rp->c_timestamp;
-       rp->c_timestamp = jiffies;
        lru_put_end(rp);
  
        rtn = RC_DROPIT;
                break;
        default:
                printk(KERN_WARNING "nfsd: bad repcache type %d\n", rp->c_type);
-               rp->c_state = RC_UNUSED;
+               nfsd_reply_cache_free_locked(rp);
        }
  
        goto out;
  void
  nfsd_cache_update(struct svc_rqst *rqstp, int cachetype, __be32 *statp)
  {
-       struct svc_cacherep *rp;
+       struct svc_cacherep *rp = rqstp->rq_cacherep;
        struct kvec     *resv = &rqstp->rq_res.head[0], *cachv;
        int             len;
  
-       if (!(rp = rqstp->rq_cacherep) || cache_disabled)
+       if (!rp)
                return;
  
        len = resv->iov_len - ((char*)statp - (char*)resv->iov_base);
  
        /* Don't cache excessive amounts of data and XDR failures */
        if (!statp || len > (256 >> 2)) {
-               rp->c_state = RC_UNUSED;
+               nfsd_reply_cache_free(rp);
                return;
        }
  
                cachv = &rp->c_replvec;
                cachv->iov_base = kmalloc(len << 2, GFP_KERNEL);
                if (!cachv->iov_base) {
-                       spin_lock(&cache_lock);
-                       rp->c_state = RC_UNUSED;
-                       spin_unlock(&cache_lock);
+                       nfsd_reply_cache_free(rp);
                        return;
                }
                cachv->iov_len = len << 2;
                memcpy(cachv->iov_base, statp, len << 2);
                break;
+       case RC_NOCACHE:
+               nfsd_reply_cache_free(rp);
+               return;
        }
        spin_lock(&cache_lock);
        lru_put_end(rp);
        rp->c_secure = rqstp->rq_secure;
        rp->c_type = cachetype;
        rp->c_state = RC_DONE;
-       rp->c_timestamp = jiffies;
        spin_unlock(&cache_lock);
        return;
  }
diff --combined fs/nfsd/nfsctl.c
@@@ -10,7 -10,7 +10,7 @@@
  
  #include <linux/sunrpc/svcsock.h>
  #include <linux/lockd/lockd.h>
- #include <linux/sunrpc/clnt.h>
+ #include <linux/sunrpc/addr.h>
  #include <linux/sunrpc/gss_api.h>
  #include <linux/sunrpc/gss_krb5_enctypes.h>
  #include <linux/sunrpc/rpc_pipe_fs.h>
@@@ -85,7 -85,7 +85,7 @@@ static ssize_t (*write_op[])(struct fil
  
  static ssize_t nfsctl_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
  {
 -      ino_t ino =  file->f_path.dentry->d_inode->i_ino;
 +      ino_t ino =  file_inode(file)->i_ino;
        char *data;
        ssize_t rv;
  
@@@ -125,11 -125,11 +125,11 @@@ static const struct file_operations tra
        .llseek         = default_llseek,
  };
  
- static int exports_open(struct inode *inode, struct file *file)
+ static int exports_net_open(struct net *net, struct file *file)
  {
        int err;
        struct seq_file *seq;
-       struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
  
        err = seq_open(file, &nfs_exports_op);
        if (err)
        return 0;
  }
  
- static const struct file_operations exports_operations = {
-       .open           = exports_open,
+ static int exports_proc_open(struct inode *inode, struct file *file)
+ {
+       return exports_net_open(current->nsproxy->net_ns, file);
+ }
+ static const struct file_operations exports_proc_operations = {
+       .open           = exports_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+       .owner          = THIS_MODULE,
+ };
+ static int exports_nfsd_open(struct inode *inode, struct file *file)
+ {
+       return exports_net_open(inode->i_sb->s_fs_info, file);
+ }
+ static const struct file_operations exports_nfsd_operations = {
+       .open           = exports_nfsd_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
        .release        = seq_release,
@@@ -220,6 -238,7 +238,7 @@@ static ssize_t write_unlock_ip(struct f
        struct sockaddr *sap = (struct sockaddr *)&address;
        size_t salen = sizeof(address);
        char *fo_path;
+       struct net *net = file->f_dentry->d_sb->s_fs_info;
  
        /* sanity check */
        if (size == 0)
        if (qword_get(&buf, fo_path, size) < 0)
                return -EINVAL;
  
-       if (rpc_pton(&init_net, fo_path, size, sap, salen) == 0)
+       if (rpc_pton(net, fo_path, size, sap, salen) == 0)
                return -EINVAL;
  
        return nlmsvc_unlock_all_by_ip(sap);
@@@ -317,6 -336,7 +336,7 @@@ static ssize_t write_filehandle(struct 
        int len;
        struct auth_domain *dom;
        struct knfsd_fh fh;
+       struct net *net = file->f_dentry->d_sb->s_fs_info;
  
        if (size == 0)
                return -EINVAL;
        if (!dom)
                return -ENOMEM;
  
-       len = exp_rootfh(&init_net, dom, path, &fh,  maxsize);
+       len = exp_rootfh(net, dom, path, &fh,  maxsize);
        auth_domain_put(dom);
        if (len)
                return len;
@@@ -396,7 -416,7 +416,7 @@@ static ssize_t write_threads(struct fil
  {
        char *mesg = buf;
        int rv;
-       struct net *net = &init_net;
+       struct net *net = file->f_dentry->d_sb->s_fs_info;
  
        if (size > 0) {
                int newthreads;
@@@ -447,7 -467,7 +467,7 @@@ static ssize_t write_pool_threads(struc
        int len;
        int npools;
        int *nthreads;
-       struct net *net = &init_net;
+       struct net *net = file->f_dentry->d_sb->s_fs_info;
  
        mutex_lock(&nfsd_mutex);
        npools = nfsd_nrpools(net);
@@@ -510,7 -530,7 +530,7 @@@ static ssize_t __write_versions(struct 
        unsigned minor;
        ssize_t tlen = 0;
        char *sep;
-       struct net *net = &init_net;
+       struct net *net = file->f_dentry->d_sb->s_fs_info;
        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
  
        if (size>0) {
                        else
                                num = simple_strtol(vers, &minorp, 0);
                        if (*minorp == '.') {
-                               if (num < 4)
+                               if (num != 4)
                                        return -EINVAL;
                                minor = simple_strtoul(minorp+1, NULL, 0);
                                if (minor == 0)
@@@ -792,7 -812,7 +812,7 @@@ static ssize_t __write_ports(struct fil
  static ssize_t write_ports(struct file *file, char *buf, size_t size)
  {
        ssize_t rv;
-       struct net *net = &init_net;
+       struct net *net = file->f_dentry->d_sb->s_fs_info;
  
        mutex_lock(&nfsd_mutex);
        rv = __write_ports(file, buf, size, net);
@@@ -827,7 -847,7 +847,7 @@@ int nfsd_max_blksize
  static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
  {
        char *mesg = buf;
-       struct net *net = &init_net;
+       struct net *net = file->f_dentry->d_sb->s_fs_info;
        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
  
        if (size > 0) {
@@@ -923,7 -943,8 +943,8 @@@ static ssize_t nfsd4_write_time(struct 
   */
  static ssize_t write_leasetime(struct file *file, char *buf, size_t size)
  {
-       struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
+       struct net *net = file->f_dentry->d_sb->s_fs_info;
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
        return nfsd4_write_time(file, buf, size, &nn->nfsd4_lease, nn);
  }
  
   */
  static ssize_t write_gracetime(struct file *file, char *buf, size_t size)
  {
-       struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
+       struct net *net = file->f_dentry->d_sb->s_fs_info;
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
        return nfsd4_write_time(file, buf, size, &nn->nfsd4_grace, nn);
  }
  
@@@ -995,7 -1017,8 +1017,8 @@@ static ssize_t __write_recoverydir(stru
  static ssize_t write_recoverydir(struct file *file, char *buf, size_t size)
  {
        ssize_t rv;
-       struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
+       struct net *net = file->f_dentry->d_sb->s_fs_info;
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
  
        mutex_lock(&nfsd_mutex);
        rv = __write_recoverydir(file, buf, size, nn);
  static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
  {
        static struct tree_descr nfsd_files[] = {
-               [NFSD_List] = {"exports", &exports_operations, S_IRUGO},
+               [NFSD_List] = {"exports", &exports_nfsd_operations, S_IRUGO},
                [NFSD_Export_features] = {"export_features",
                                        &export_features_operations, S_IRUGO},
                [NFSD_FO_UnlockIP] = {"unlock_ip",
  #endif
                /* last one */ {""}
        };
-       return simple_fill_super(sb, 0x6e667364, nfsd_files);
+       struct net *net = data;
+       int ret;
+       ret = simple_fill_super(sb, 0x6e667364, nfsd_files);
+       if (ret)
+               return ret;
+       sb->s_fs_info = get_net(net);
+       return 0;
  }
  
  static struct dentry *nfsd_mount(struct file_system_type *fs_type,
        int flags, const char *dev_name, void *data)
  {
-       return mount_single(fs_type, flags, data, nfsd_fill_super);
+       return mount_ns(fs_type, flags, current->nsproxy->net_ns, nfsd_fill_super);
+ }
+ static void nfsd_umount(struct super_block *sb)
+ {
+       struct net *net = sb->s_fs_info;
+       kill_litter_super(sb);
+       put_net(net);
  }
  
  static struct file_system_type nfsd_fs_type = {
        .owner          = THIS_MODULE,
        .name           = "nfsd",
        .mount          = nfsd_mount,
-       .kill_sb        = kill_litter_super,
+       .kill_sb        = nfsd_umount,
  };
  
  #ifdef CONFIG_PROC_FS
@@@ -1061,7 -1099,8 +1099,8 @@@ static int create_proc_exports_entry(vo
        entry = proc_mkdir("fs/nfs", NULL);
        if (!entry)
                return -ENOMEM;
-       entry = proc_create("exports", 0, entry, &exports_operations);
+       entry = proc_create("exports", 0, entry,
+                                &exports_proc_operations);
        if (!entry)
                return -ENOMEM;
        return 0;
diff --combined fs/nfsd/nfssvc.c
@@@ -59,8 -59,8 +59,8 @@@ DEFINE_MUTEX(nfsd_mutex)
   * nfsd_drc_pages_used tracks the current version 4.1 DRC memory usage.
   */
  spinlock_t    nfsd_drc_lock;
 -unsigned int  nfsd_drc_max_mem;
 -unsigned int  nfsd_drc_mem_used;
 +unsigned long nfsd_drc_max_mem;
 +unsigned long nfsd_drc_mem_used;
  
  #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
  static struct svc_stat        nfsd_acl_svcstats;
@@@ -342,7 -342,7 +342,7 @@@ static void set_max_drc(void
                                        >> NFSD_DRC_SIZE_SHIFT) * PAGE_SIZE;
        nfsd_drc_mem_used = 0;
        spin_lock_init(&nfsd_drc_lock);
 -      dprintk("%s nfsd_drc_max_mem %u \n", __func__, nfsd_drc_max_mem);
 +      dprintk("%s nfsd_drc_max_mem %lu \n", __func__, nfsd_drc_max_mem);
  }
  
  static int nfsd_get_default_max_blksize(void)
@@@ -652,7 -652,6 +652,6 @@@ nfsd_dispatch(struct svc_rqst *rqstp, _
  
        /* Check whether we have this call in the cache. */
        switch (nfsd_cache_lookup(rqstp)) {
-       case RC_INTR:
        case RC_DROPIT:
                return 0;
        case RC_REPLY:
  int nfsd_pool_stats_open(struct inode *inode, struct file *file)
  {
        int ret;
-       struct net *net = &init_net;
-       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+       struct nfsd_net *nn = net_generic(inode->i_sb->s_fs_info, nfsd_net_id);
  
        mutex_lock(&nfsd_mutex);
        if (nn->nfsd_serv == NULL) {
  int nfsd_pool_stats_release(struct inode *inode, struct file *file)
  {
        int ret = seq_release(inode, file);
-       struct net *net = &init_net;
+       struct net *net = inode->i_sb->s_fs_info;
  
        mutex_lock(&nfsd_mutex);
        /* this function really, really should have been called svc_put() */
@@@ -212,7 -212,8 +212,8 @@@ int                  nlmclnt_block(struct nlm_wait *b
  __be32                  nlmclnt_grant(const struct sockaddr *addr,
                                const struct nlm_lock *lock);
  void            nlmclnt_recovery(struct nlm_host *);
- int             nlmclnt_reclaim(struct nlm_host *, struct file_lock *);
+ int             nlmclnt_reclaim(struct nlm_host *, struct file_lock *,
+                                 struct nlm_rqst *);
  void            nlmclnt_next_cookie(struct nlm_cookie *);
  
  /*
@@@ -291,7 -292,7 +292,7 @@@ int           nlmsvc_unlock_all_by_ip(s
  
  static inline struct inode *nlmsvc_file_inode(struct nlm_file *file)
  {
 -      return file->f_file->f_path.dentry->d_inode;
 +      return file_inode(file->f_file);
  }
  
  static inline int __nlm_privileged_request4(const struct sockaddr *sap)
@@@ -182,12 -182,6 +182,6 @@@ static void rsi_request(struct cache_de
        (*bpp)[-1] = '\n';
  }
  
- static int rsi_upcall(struct cache_detail *cd, struct cache_head *h)
- {
-       return sunrpc_cache_pipe_upcall(cd, h, rsi_request);
- }
  static int rsi_parse(struct cache_detail *cd,
                    char *mesg, int mlen)
  {
@@@ -275,7 -269,7 +269,7 @@@ static struct cache_detail rsi_cache_te
        .hash_size      = RSI_HASHMAX,
        .name           = "auth.rpcsec.init",
        .cache_put      = rsi_put,
-       .cache_upcall   = rsi_upcall,
+       .cache_request  = rsi_request,
        .cache_parse    = rsi_parse,
        .match          = rsi_match,
        .init           = rsi_init,
@@@ -418,7 -412,6 +412,7 @@@ static int rsc_parse(struct cache_detai
  {
        /* contexthandle expiry [ uid gid N <n gids> mechname ...mechdata... ] */
        char *buf = mesg;
 +      int id;
        int len, rv;
        struct rsc rsci, *rscp = NULL;
        time_t expiry;
                goto out;
  
        /* uid, or NEGATIVE */
 -      rv = get_int(&mesg, &rsci.cred.cr_uid);
 +      rv = get_int(&mesg, &id);
        if (rv == -EINVAL)
                goto out;
        if (rv == -ENOENT)
        else {
                int N, i;
  
 +              /* uid */
 +              rsci.cred.cr_uid = make_kuid(&init_user_ns, id);
 +              if (!uid_valid(rsci.cred.cr_uid))
 +                      goto out;
 +
                /* gid */
 -              if (get_int(&mesg, &rsci.cred.cr_gid))
 +              if (get_int(&mesg, &id))
 +                      goto out;
 +              rsci.cred.cr_gid = make_kgid(&init_user_ns, id);
 +              if (!gid_valid(rsci.cred.cr_gid))
                        goto out;
  
                /* number of additional gid's */
                /* gid's */
                status = -EINVAL;
                for (i=0; i<N; i++) {
 -                      gid_t gid;
                        kgid_t kgid;
 -                      if (get_int(&mesg, &gid))
 +                      if (get_int(&mesg, &id))
                                goto out;
 -                      kgid = make_kgid(&init_user_ns, gid);
 +                      kgid = make_kgid(&init_user_ns, id);
                        if (!gid_valid(kgid))
                                goto out;
                        GROUP_AT(rsci.cred.cr_group_info, i) = kgid;
@@@ -825,13 -811,17 +819,17 @@@ read_u32_from_xdr_buf(struct xdr_buf *b
   *    The server uses base of head iovec as read pointer, while the
   *    client uses separate pointer. */
  static int
- unwrap_integ_data(struct xdr_buf *buf, u32 seq, struct gss_ctx *ctx)
+ unwrap_integ_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct gss_ctx *ctx)
  {
        int stat = -EINVAL;
        u32 integ_len, maj_stat;
        struct xdr_netobj mic;
        struct xdr_buf integ_buf;
  
+       /* Did we already verify the signature on the original pass through? */
+       if (rqstp->rq_deferred)
+               return 0;
        integ_len = svc_getnl(&buf->head[0]);
        if (integ_len & 3)
                return stat;
                goto out;
        if (svc_getnl(&buf->head[0]) != seq)
                goto out;
+       /* trim off the mic at the end before returning */
+       xdr_buf_trim(buf, mic.len + 4);
        stat = 0;
  out:
        kfree(mic.data);
@@@ -1198,7 -1190,7 +1198,7 @@@ svcauth_gss_accept(struct svc_rqst *rqs
                        /* placeholders for length and seq. number: */
                        svc_putnl(resv, 0);
                        svc_putnl(resv, 0);
-                       if (unwrap_integ_data(&rqstp->rq_arg,
+                       if (unwrap_integ_data(rqstp, &rqstp->rq_arg,
                                        gc->gc_seq, rsci->mechctx))
                                goto garbage_args;
                        break;
diff --combined net/sunrpc/cache.c
@@@ -196,9 -196,9 +196,9 @@@ EXPORT_SYMBOL_GPL(sunrpc_cache_update)
  
  static int cache_make_upcall(struct cache_detail *cd, struct cache_head *h)
  {
-       if (!cd->cache_upcall)
-               return -EINVAL;
-       return cd->cache_upcall(cd, h);
+       if (cd->cache_upcall)
+               return cd->cache_upcall(cd, h);
+       return sunrpc_cache_pipe_upcall(cd, h);
  }
  
  static inline int cache_is_valid(struct cache_detail *detail, struct cache_head *h)
@@@ -670,13 -670,13 +670,13 @@@ static void cache_revisit_request(struc
  {
        struct cache_deferred_req *dreq;
        struct list_head pending;
 -      struct hlist_node *lp, *tmp;
 +      struct hlist_node *tmp;
        int hash = DFR_HASH(item);
  
        INIT_LIST_HEAD(&pending);
        spin_lock(&cache_defer_lock);
  
 -      hlist_for_each_entry_safe(dreq, lp, tmp, &cache_defer_hash[hash], hash)
 +      hlist_for_each_entry_safe(dreq, tmp, &cache_defer_hash[hash], hash)
                if (dreq->item == item) {
                        __unhash_deferred_req(dreq);
                        list_add(&dreq->recent, &pending);
@@@ -750,12 -750,24 +750,24 @@@ struct cache_reader 
        int                     offset; /* if non-0, we have a refcnt on next request */
  };
  
+ static int cache_request(struct cache_detail *detail,
+                              struct cache_request *crq)
+ {
+       char *bp = crq->buf;
+       int len = PAGE_SIZE;
+       detail->cache_request(detail, crq->item, &bp, &len);
+       if (len < 0)
+               return -EAGAIN;
+       return PAGE_SIZE - len;
+ }
  static ssize_t cache_read(struct file *filp, char __user *buf, size_t count,
                          loff_t *ppos, struct cache_detail *cd)
  {
        struct cache_reader *rp = filp->private_data;
        struct cache_request *rq;
 -      struct inode *inode = filp->f_path.dentry->d_inode;
 +      struct inode *inode = file_inode(filp);
        int err;
  
        if (count == 0)
                rq->readers++;
        spin_unlock(&queue_lock);
  
+       if (rq->len == 0) {
+               err = cache_request(cd, rq);
+               if (err < 0)
+                       goto out;
+               rq->len = err;
+       }
        if (rp->offset == 0 && !test_bit(CACHE_PENDING, &rq->item->flags)) {
                err = -EAGAIN;
                spin_lock(&queue_lock);
@@@ -886,7 -905,7 +905,7 @@@ static ssize_t cache_write(struct file 
                           struct cache_detail *cd)
  {
        struct address_space *mapping = filp->f_mapping;
 -      struct inode *inode = filp->f_path.dentry->d_inode;
 +      struct inode *inode = file_inode(filp);
        ssize_t ret = -EINVAL;
  
        if (!cd->cache_parse)
@@@ -1140,17 -1159,14 +1159,14 @@@ static bool cache_listeners_exist(struc
   *
   * Each request is at most one page long.
   */
- int sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h,
-               void (*cache_request)(struct cache_detail *,
-                                     struct cache_head *,
-                                     char **,
-                                     int *))
+ int sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h)
  {
  
        char *buf;
        struct cache_request *crq;
-       char *bp;
-       int len;
+       if (!detail->cache_request)
+               return -EINVAL;
  
        if (!cache_listeners_exist(detail)) {
                warn_no_listener(detail);
                return -EAGAIN;
        }
  
-       bp = buf; len = PAGE_SIZE;
-       cache_request(detail, h, &bp, &len);
-       if (len < 0) {
-               kfree(buf);
-               kfree(crq);
-               return -EAGAIN;
-       }
        crq->q.reader = 0;
        crq->item = cache_get(h);
        crq->buf = buf;
-       crq->len = PAGE_SIZE - len;
+       crq->len = 0;
        crq->readers = 0;
        spin_lock(&queue_lock);
        list_add_tail(&crq->q.list, &detail->queue);
@@@ -1454,7 -1461,7 +1461,7 @@@ static ssize_t write_flush(struct file 
  static ssize_t cache_read_procfs(struct file *filp, char __user *buf,
                                 size_t count, loff_t *ppos)
  {
 -      struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data;
 +      struct cache_detail *cd = PDE(file_inode(filp))->data;
  
        return cache_read(filp, buf, count, ppos, cd);
  }
  static ssize_t cache_write_procfs(struct file *filp, const char __user *buf,
                                  size_t count, loff_t *ppos)
  {
 -      struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data;
 +      struct cache_detail *cd = PDE(file_inode(filp))->data;
  
        return cache_write(filp, buf, count, ppos, cd);
  }
  
  static unsigned int cache_poll_procfs(struct file *filp, poll_table *wait)
  {
 -      struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data;
 +      struct cache_detail *cd = PDE(file_inode(filp))->data;
  
        return cache_poll(filp, wait, cd);
  }
  static long cache_ioctl_procfs(struct file *filp,
                               unsigned int cmd, unsigned long arg)
  {
 -      struct inode *inode = filp->f_path.dentry->d_inode;
 +      struct inode *inode = file_inode(filp);
        struct cache_detail *cd = PDE(inode)->data;
  
        return cache_ioctl(inode, filp, cmd, arg, cd);
@@@ -1546,7 -1553,7 +1553,7 @@@ static int release_flush_procfs(struct 
  static ssize_t read_flush_procfs(struct file *filp, char __user *buf,
                            size_t count, loff_t *ppos)
  {
 -      struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data;
 +      struct cache_detail *cd = PDE(file_inode(filp))->data;
  
        return read_flush(filp, buf, count, ppos, cd);
  }
@@@ -1555,7 -1562,7 +1562,7 @@@ static ssize_t write_flush_procfs(struc
                                  const char __user *buf,
                                  size_t count, loff_t *ppos)
  {
 -      struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data;
 +      struct cache_detail *cd = PDE(file_inode(filp))->data;
  
        return write_flush(filp, buf, count, ppos, cd);
  }
@@@ -1605,7 -1612,7 +1612,7 @@@ static int create_cache_proc_entries(st
        if (p == NULL)
                goto out_nomem;
  
-       if (cd->cache_upcall || cd->cache_parse) {
+       if (cd->cache_request || cd->cache_parse) {
                p = proc_create_data("channel", S_IFREG|S_IRUSR|S_IWUSR,
                                     cd->u.procfs.proc_ent,
                                     &cache_file_operations_procfs, cd);
                        goto out_nomem;
        }
        if (cd->cache_show) {
-               p = proc_create_data("content", S_IFREG|S_IRUSR|S_IWUSR,
+               p = proc_create_data("content", S_IFREG|S_IRUSR,
                                cd->u.procfs.proc_ent,
                                &content_file_operations_procfs, cd);
                cd->u.procfs.content_ent = p;
@@@ -1686,7 -1693,7 +1693,7 @@@ EXPORT_SYMBOL_GPL(cache_destroy_net)
  static ssize_t cache_read_pipefs(struct file *filp, char __user *buf,
                                 size_t count, loff_t *ppos)
  {
 -      struct cache_detail *cd = RPC_I(filp->f_path.dentry->d_inode)->private;
 +      struct cache_detail *cd = RPC_I(file_inode(filp))->private;
  
        return cache_read(filp, buf, count, ppos, cd);
  }
  static ssize_t cache_write_pipefs(struct file *filp, const char __user *buf,
                                  size_t count, loff_t *ppos)
  {
 -      struct cache_detail *cd = RPC_I(filp->f_path.dentry->d_inode)->private;
 +      struct cache_detail *cd = RPC_I(file_inode(filp))->private;
  
        return cache_write(filp, buf, count, ppos, cd);
  }
  
  static unsigned int cache_poll_pipefs(struct file *filp, poll_table *wait)
  {
 -      struct cache_detail *cd = RPC_I(filp->f_path.dentry->d_inode)->private;
 +      struct cache_detail *cd = RPC_I(file_inode(filp))->private;
  
        return cache_poll(filp, wait, cd);
  }
  static long cache_ioctl_pipefs(struct file *filp,
                              unsigned int cmd, unsigned long arg)
  {
 -      struct inode *inode = filp->f_dentry->d_inode;
 +      struct inode *inode = file_inode(filp);
        struct cache_detail *cd = RPC_I(inode)->private;
  
        return cache_ioctl(inode, filp, cmd, arg, cd);
@@@ -1778,7 -1785,7 +1785,7 @@@ static int release_flush_pipefs(struct 
  static ssize_t read_flush_pipefs(struct file *filp, char __user *buf,
                            size_t count, loff_t *ppos)
  {
 -      struct cache_detail *cd = RPC_I(filp->f_path.dentry->d_inode)->private;
 +      struct cache_detail *cd = RPC_I(file_inode(filp))->private;
  
        return read_flush(filp, buf, count, ppos, cd);
  }
@@@ -1787,7 -1794,7 +1794,7 @@@ static ssize_t write_flush_pipefs(struc
                                  const char __user *buf,
                                  size_t count, loff_t *ppos)
  {
 -      struct cache_detail *cd = RPC_I(filp->f_path.dentry->d_inode)->private;
 +      struct cache_detail *cd = RPC_I(file_inode(filp))->private;
  
        return write_flush(filp, buf, count, ppos, cd);
  }
diff --combined net/sunrpc/clnt.c
@@@ -33,6 -33,7 +33,7 @@@
  #include <linux/rcupdate.h>
  
  #include <linux/sunrpc/clnt.h>
+ #include <linux/sunrpc/addr.h>
  #include <linux/sunrpc/rpc_pipe_fs.h>
  #include <linux/sunrpc/metrics.h>
  #include <linux/sunrpc/bc_xprt.h>
@@@ -555,7 -556,7 +556,7 @@@ EXPORT_SYMBOL_GPL(rpc_clone_client)
   * rpc_clone_client_set_auth - Clone an RPC client structure and set its auth
   *
   * @clnt: RPC client whose parameters are copied
 - * @auth: security flavor for new client
 + * @flavor: security flavor for new client
   *
   * Returns a fresh RPC client or an ERR_PTR.
   */
@@@ -610,6 -611,11 +611,6 @@@ EXPORT_SYMBOL_GPL(rpc_killall_tasks)
   */
  void rpc_shutdown_client(struct rpc_clnt *clnt)
  {
 -      /*
 -       * To avoid deadlock, never call rpc_shutdown_client from a
 -       * workqueue context!
 -       */
 -      WARN_ON_ONCE(current->flags & PF_WQ_WORKER);
        might_sleep();
  
        dprintk_rcu("RPC:       shutting down %s client for %s\n",
@@@ -1400,7 -1406,7 +1401,7 @@@ call_allocate(struct rpc_task *task
  {
        unsigned int slack = task->tk_rqstp->rq_cred->cr_auth->au_cslack;
        struct rpc_rqst *req = task->tk_rqstp;
 -      struct rpc_xprt *xprt = task->tk_xprt;
 +      struct rpc_xprt *xprt = req->rq_xprt;
        struct rpc_procinfo *proc = task->tk_msg.rpc_proc;
  
        dprint_status(task);
@@@ -1508,7 -1514,7 +1509,7 @@@ rpc_xdr_encode(struct rpc_task *task
  static void
  call_bind(struct rpc_task *task)
  {
 -      struct rpc_xprt *xprt = task->tk_xprt;
 +      struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt;
  
        dprint_status(task);
  
@@@ -1602,7 -1608,7 +1603,7 @@@ retry_timeout
  static void
  call_connect(struct rpc_task *task)
  {
 -      struct rpc_xprt *xprt = task->tk_xprt;
 +      struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt;
  
        dprintk("RPC: %5u call_connect xprt %p %s connected\n",
                        task->tk_pid, xprt,
@@@ -1685,7 -1691,7 +1686,7 @@@ call_transmit(struct rpc_task *task
        if (rpc_reply_expected(task))
                return;
        task->tk_action = rpc_exit_task;
 -      rpc_wake_up_queued_task(&task->tk_xprt->pending, task);
 +      rpc_wake_up_queued_task(&task->tk_rqstp->rq_xprt->pending, task);
  }
  
  /*
@@@ -1784,7 -1790,7 +1785,7 @@@ call_bc_transmit(struct rpc_task *task
                 */
                printk(KERN_NOTICE "RPC: Could not send backchannel reply "
                        "error: %d\n", task->tk_status);
 -              xprt_conditional_disconnect(task->tk_xprt,
 +              xprt_conditional_disconnect(req->rq_xprt,
                        req->rq_connect_cookie);
                break;
        default:
@@@ -1836,7 -1842,7 +1837,7 @@@ call_status(struct rpc_task *task
        case -ETIMEDOUT:
                task->tk_action = call_timeout;
                if (task->tk_client->cl_discrtry)
 -                      xprt_conditional_disconnect(task->tk_xprt,
 +                      xprt_conditional_disconnect(req->rq_xprt,
                                        req->rq_connect_cookie);
                break;
        case -ECONNRESET:
@@@ -1991,7 -1997,7 +1992,7 @@@ out_retry
        if (task->tk_rqstp == req) {
                req->rq_reply_bytes_recvd = req->rq_rcv_buf.len = 0;
                if (task->tk_client->cl_discrtry)
 -                      xprt_conditional_disconnect(task->tk_xprt,
 +                      xprt_conditional_disconnect(req->rq_xprt,
                                        req->rq_connect_cookie);
        }
  }
@@@ -2005,7 -2011,7 +2006,7 @@@ rpc_encode_header(struct rpc_task *task
  
        /* FIXME: check buffer size? */
  
 -      p = xprt_skip_transport_header(task->tk_xprt, p);
 +      p = xprt_skip_transport_header(req->rq_xprt, p);
        *p++ = req->rq_xid;             /* XID */
        *p++ = htonl(RPC_CALL);         /* CALL */
        *p++ = htonl(RPC_VERSION);      /* RPC version */
@@@ -6,6 -6,7 +6,7 @@@
  #include <linux/sunrpc/svcsock.h>
  #include <linux/sunrpc/svcauth.h>
  #include <linux/sunrpc/gss_api.h>
+ #include <linux/sunrpc/addr.h>
  #include <linux/err.h>
  #include <linux/seq_file.h>
  #include <linux/hash.h>
@@@ -17,7 -18,6 +18,6 @@@
  #include <linux/user_namespace.h>
  #define RPCDBG_FACILITY       RPCDBG_AUTH
  
- #include <linux/sunrpc/clnt.h>
  
  #include "netns.h"
  
@@@ -157,11 -157,6 +157,6 @@@ static void ip_map_request(struct cache
        (*bpp)[-1] = '\n';
  }
  
- static int ip_map_upcall(struct cache_detail *cd, struct cache_head *h)
- {
-       return sunrpc_cache_pipe_upcall(cd, h, ip_map_request);
- }
  static struct ip_map *__ip_map_lookup(struct cache_detail *cd, char *class, struct in6_addr *addr);
  static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm, struct unix_domain *udom, time_t expiry);
  
@@@ -415,15 -410,10 +410,15 @@@ svcauth_unix_info_release(struct svc_xp
  
  struct unix_gid {
        struct cache_head       h;
 -      uid_t                   uid;
 +      kuid_t                  uid;
        struct group_info       *gi;
  };
  
 +static int unix_gid_hash(kuid_t uid)
 +{
 +      return hash_long(from_kuid(&init_user_ns, uid), GID_HASHBITS);
 +}
 +
  static void unix_gid_put(struct kref *kref)
  {
        struct cache_head *item = container_of(kref, struct cache_head, ref);
@@@ -438,7 -428,7 +433,7 @@@ static int unix_gid_match(struct cache_
  {
        struct unix_gid *orig = container_of(corig, struct unix_gid, h);
        struct unix_gid *new = container_of(cnew, struct unix_gid, h);
 -      return orig->uid == new->uid;
 +      return uid_eq(orig->uid, new->uid);
  }
  static void unix_gid_init(struct cache_head *cnew, struct cache_head *citem)
  {
@@@ -470,24 -460,18 +465,19 @@@ static void unix_gid_request(struct cac
        char tuid[20];
        struct unix_gid *ug = container_of(h, struct unix_gid, h);
  
 -      snprintf(tuid, 20, "%u", ug->uid);
 +      snprintf(tuid, 20, "%u", from_kuid(&init_user_ns, ug->uid));
        qword_add(bpp, blen, tuid);
        (*bpp)[-1] = '\n';
  }
  
- static int unix_gid_upcall(struct cache_detail *cd, struct cache_head *h)
- {
-       return sunrpc_cache_pipe_upcall(cd, h, unix_gid_request);
- }
 -static struct unix_gid *unix_gid_lookup(struct cache_detail *cd, uid_t uid);
 +static struct unix_gid *unix_gid_lookup(struct cache_detail *cd, kuid_t uid);
  
  static int unix_gid_parse(struct cache_detail *cd,
                        char *mesg, int mlen)
  {
        /* uid expiry Ngid gid0 gid1 ... gidN-1 */
 -      int uid;
 +      int id;
 +      kuid_t uid;
        int gids;
        int rv;
        int i;
                return -EINVAL;
        mesg[mlen-1] = 0;
  
 -      rv = get_int(&mesg, &uid);
 +      rv = get_int(&mesg, &id);
        if (rv)
                return -EINVAL;
 +      uid = make_kuid(&init_user_ns, id);
 +      if (!uid_valid(uid))
 +              return -EINVAL;
        ug.uid = uid;
  
        expiry = get_expiry(&mesg);
                ug.h.expiry_time = expiry;
                ch = sunrpc_cache_update(cd,
                                         &ug.h, &ugp->h,
 -                                       hash_long(uid, GID_HASHBITS));
 +                                       unix_gid_hash(uid));
                if (!ch)
                        err = -ENOMEM;
                else {
@@@ -558,7 -539,7 +548,7 @@@ static int unix_gid_show(struct seq_fil
                         struct cache_detail *cd,
                         struct cache_head *h)
  {
 -      struct user_namespace *user_ns = current_user_ns();
 +      struct user_namespace *user_ns = &init_user_ns;
        struct unix_gid *ug;
        int i;
        int glen;
        else
                glen = 0;
  
 -      seq_printf(m, "%u %d:", ug->uid, glen);
 +      seq_printf(m, "%u %d:", from_kuid_munged(user_ns, ug->uid), glen);
        for (i = 0; i < glen; i++)
                seq_printf(m, " %d", from_kgid_munged(user_ns, GROUP_AT(ug->gi, i)));
        seq_printf(m, "\n");
@@@ -586,7 -567,7 +576,7 @@@ static struct cache_detail unix_gid_cac
        .hash_size      = GID_HASHMAX,
        .name           = "auth.unix.gid",
        .cache_put      = unix_gid_put,
-       .cache_upcall   = unix_gid_upcall,
+       .cache_request  = unix_gid_request,
        .cache_parse    = unix_gid_parse,
        .cache_show     = unix_gid_show,
        .match          = unix_gid_match,
@@@ -624,20 -605,20 +614,20 @@@ void unix_gid_cache_destroy(struct net 
        cache_destroy_net(cd, net);
  }
  
 -static struct unix_gid *unix_gid_lookup(struct cache_detail *cd, uid_t uid)
 +static struct unix_gid *unix_gid_lookup(struct cache_detail *cd, kuid_t uid)
  {
        struct unix_gid ug;
        struct cache_head *ch;
  
        ug.uid = uid;
 -      ch = sunrpc_cache_lookup(cd, &ug.h, hash_long(uid, GID_HASHBITS));
 +      ch = sunrpc_cache_lookup(cd, &ug.h, unix_gid_hash(uid));
        if (ch)
                return container_of(ch, struct unix_gid, h);
        else
                return NULL;
  }
  
 -static struct group_info *unix_gid_find(uid_t uid, struct svc_rqst *rqstp)
 +static struct group_info *unix_gid_find(kuid_t uid, struct svc_rqst *rqstp)
  {
        struct unix_gid *ug;
        struct group_info *gi;
@@@ -759,8 -740,8 +749,8 @@@ svcauth_null_accept(struct svc_rqst *rq
        }
  
        /* Signal that mapping to nobody uid/gid is required */
 -      cred->cr_uid = (uid_t) -1;
 -      cred->cr_gid = (gid_t) -1;
 +      cred->cr_uid = INVALID_UID;
 +      cred->cr_gid = INVALID_GID;
        cred->cr_group_info = groups_alloc(0);
        if (cred->cr_group_info == NULL)
                return SVC_CLOSE; /* kmalloc failure - client must retry */
@@@ -821,10 -802,8 +811,10 @@@ svcauth_unix_accept(struct svc_rqst *rq
        argv->iov_base = (void*)((__be32*)argv->iov_base + slen);       /* skip machname */
        argv->iov_len -= slen*4;
  
 -      cred->cr_uid = svc_getnl(argv);         /* uid */
 -      cred->cr_gid = svc_getnl(argv);         /* gid */
 +      cred->cr_uid = make_kuid(&init_user_ns, svc_getnl(argv)); /* uid */
 +      cred->cr_gid = make_kgid(&init_user_ns, svc_getnl(argv)); /* gid */
 +      if (!uid_valid(cred->cr_uid) || !gid_valid(cred->cr_gid))
 +              goto badcred;
        slen = svc_getnl(argv);                 /* gids length */
        if (slen > 16 || (len -= (slen + 2)*4) < 0)
                goto badcred;
@@@ -885,7 -864,7 +875,7 @@@ static struct cache_detail ip_map_cache
        .hash_size      = IP_HASHMAX,
        .name           = "auth.unix.ip",
        .cache_put      = ip_map_put,
-       .cache_upcall   = ip_map_upcall,
+       .cache_request  = ip_map_request,
        .cache_parse    = ip_map_parse,
        .cache_show     = ip_map_show,
        .match          = ip_map_match,
@@@ -51,6 -51,7 +51,7 @@@
  #include <linux/init.h>
  #include <linux/slab.h>
  #include <linux/seq_file.h>
+ #include <linux/sunrpc/addr.h>
  
  #include "xprt_rdma.h"
  
@@@ -426,8 -427,9 +427,8 @@@ xprt_rdma_set_port(struct rpc_xprt *xpr
  }
  
  static void
 -xprt_rdma_connect(struct rpc_task *task)
 +xprt_rdma_connect(struct rpc_xprt *xprt, struct rpc_task *task)
  {
 -      struct rpc_xprt *xprt = (struct rpc_xprt *)task->tk_xprt;
        struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
  
        if (r_xprt->rx_ep.rep_connected != 0) {
@@@ -474,7 -476,7 +475,7 @@@ xprt_rdma_reserve_xprt(struct rpc_xprt 
  static void *
  xprt_rdma_allocate(struct rpc_task *task, size_t size)
  {
 -      struct rpc_xprt *xprt = task->tk_xprt;
 +      struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt;
        struct rpcrdma_req *req, *nreq;
  
        req = rpcrdma_buffer_get(&rpcx_to_rdmax(xprt)->rx_buf);
@@@ -626,7 -628,7 +627,7 @@@ static in
  xprt_rdma_send_request(struct rpc_task *task)
  {
        struct rpc_rqst *rqst = task->tk_rqstp;
 -      struct rpc_xprt *xprt = task->tk_xprt;
 +      struct rpc_xprt *xprt = rqst->rq_xprt;
        struct rpcrdma_req *req = rpcr_to_rdmar(rqst);
        struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
  
diff --combined net/sunrpc/xprtsock.c
@@@ -33,6 -33,7 +33,7 @@@
  #include <linux/udp.h>
  #include <linux/tcp.h>
  #include <linux/sunrpc/clnt.h>
+ #include <linux/sunrpc/addr.h>
  #include <linux/sunrpc/sched.h>
  #include <linux/sunrpc/svcsock.h>
  #include <linux/sunrpc/xprtsock.h>
@@@ -770,7 -771,7 +771,7 @@@ static void xs_tcp_release_xprt(struct 
                goto out_release;
        if (req->rq_bytes_sent == req->rq_snd_buf.len)
                goto out_release;
 -      set_bit(XPRT_CLOSE_WAIT, &task->tk_xprt->state);
 +      set_bit(XPRT_CLOSE_WAIT, &xprt->state);
  out_release:
        xprt_release_xprt(xprt, task);
  }
@@@ -1005,7 -1006,7 +1006,7 @@@ static void xs_udp_data_ready(struct so
  
        UDPX_INC_STATS_BH(sk, UDP_MIB_INDATAGRAMS);
  
 -      xprt_adjust_cwnd(task, copied);
 +      xprt_adjust_cwnd(xprt, task, copied);
        xprt_complete_rqst(task, copied);
  
   out_unlock:
@@@ -1646,9 -1647,9 +1647,9 @@@ static void xs_udp_set_buffer_size(stru
   *
   * Adjust the congestion window after a retransmit timeout has occurred.
   */
 -static void xs_udp_timer(struct rpc_task *task)
 +static void xs_udp_timer(struct rpc_xprt *xprt, struct rpc_task *task)
  {
 -      xprt_adjust_cwnd(task, -ETIMEDOUT);
 +      xprt_adjust_cwnd(xprt, task, -ETIMEDOUT);
  }
  
  static unsigned short xs_get_random_port(void)
@@@ -1731,9 -1732,7 +1732,9 @@@ static int xs_bind(struct sock_xprt *tr
   */
  static void xs_local_rpcbind(struct rpc_task *task)
  {
 -      xprt_set_bound(task->tk_xprt);
 +      rcu_read_lock();
 +      xprt_set_bound(rcu_dereference(task->tk_client->cl_xprt));
 +      rcu_read_unlock();
  }
  
  static void xs_local_set_port(struct rpc_xprt *xprt, unsigned short port)
@@@ -1867,13 -1866,9 +1868,9 @@@ static int xs_local_finish_connecting(s
   * @xprt: RPC transport to connect
   * @transport: socket transport to connect
   * @create_sock: function to create a socket of the correct type
-  *
-  * Invoked by a work queue tasklet.
   */
- static void xs_local_setup_socket(struct work_struct *work)
+ static int xs_local_setup_socket(struct sock_xprt *transport)
  {
-       struct sock_xprt *transport =
-               container_of(work, struct sock_xprt, connect_worker.work);
        struct rpc_xprt *xprt = &transport->xprt;
        struct socket *sock;
        int status = -EIO;
        xprt_clear_connecting(xprt);
        xprt_wake_pending_tasks(xprt, status);
        current->flags &= ~PF_FSTRANS;
 -static void xs_local_connect(struct rpc_task *task)
+       return status;
+ }
 -      struct rpc_xprt *xprt = task->tk_xprt;
++static void xs_local_connect(struct rpc_xprt *xprt, struct rpc_task *task)
+ {
+       struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
+       int ret;
+        if (RPC_IS_ASYNC(task)) {
+               /*
+                * We want the AF_LOCAL connect to be resolved in the
+                * filesystem namespace of the process making the rpc
+                * call.  Thus we connect synchronously.
+                *
+                * If we want to support asynchronous AF_LOCAL calls,
+                * we'll need to figure out how to pass a namespace to
+                * connect.
+                */
+               rpc_exit(task, -ENOTCONN);
+               return;
+       }
+       ret = xs_local_setup_socket(transport);
+       if (ret && !RPC_IS_SOFTCONN(task))
+               msleep_interruptible(15000);
  }
  
  #ifdef CONFIG_SUNRPC_SWAP
@@@ -2207,7 -2227,6 +2228,7 @@@ out
  
  /**
   * xs_connect - connect a socket to a remote endpoint
 + * @xprt: pointer to transport structure
   * @task: address of RPC task that manages state of connect request
   *
   * TCP: If the remote end dropped the connection, delay reconnecting.
   * If a UDP socket connect fails, the delay behavior here prevents
   * retry floods (hard mounts).
   */
 -static void xs_connect(struct rpc_task *task)
 +static void xs_connect(struct rpc_xprt *xprt, struct rpc_task *task)
  {
 -      struct rpc_xprt *xprt = task->tk_xprt;
        struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
  
        if (transport->sock != NULL && !RPC_IS_SOFTCONN(task)) {
@@@ -2455,7 -2475,7 +2476,7 @@@ static struct rpc_xprt_ops xs_local_op
        .alloc_slot             = xprt_alloc_slot,
        .rpcbind                = xs_local_rpcbind,
        .set_port               = xs_local_set_port,
-       .connect                = xs_connect,
+       .connect                = xs_local_connect,
        .buf_alloc              = rpc_malloc,
        .buf_free               = rpc_free,
        .send_request           = xs_local_send_request,
@@@ -2628,8 -2648,6 +2649,6 @@@ static struct rpc_xprt *xs_setup_local(
                        goto out_err;
                }
                xprt_set_bound(xprt);
-               INIT_DELAYED_WORK(&transport->connect_worker,
-                                       xs_local_setup_socket);
                xs_format_peer_addresses(xprt, "local", RPCBIND_NETID_LOCAL);
                break;
        default: