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

Simple merge
Simple merge
diff --cc fs/lockd/host.c
Simple merge
Simple merge
Simple merge
diff --cc fs/nfs/super.c
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -1060,6 -1079,8 +1079,7 @@@ free_client(struct nfs4_client *clp
        }
        free_svc_cred(&clp->cl_cred);
        kfree(clp->cl_name.data);
 -      idr_remove_all(&clp->cl_stateids);
+       idr_destroy(&clp->cl_stateids);
        kfree(clp);
  }
  
Simple merge
@@@ -112,10 -182,130 +182,129 @@@ 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)
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -475,12 -465,7 +470,7 @@@ static void unix_gid_request(struct cac
        (*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)
Simple merge
        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