Merge tag 'nfs-for-3.8-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 18 Dec 2012 17:36:34 +0000 (09:36 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 18 Dec 2012 17:36:34 +0000 (09:36 -0800)
Pull NFS client updates from Trond Myklebust:
 "Features include:

   - Full audit of BUG_ON asserts in the NFS, SUNRPC and lockd client
     code.  Remove altogether where possible, and replace with
     WARN_ON_ONCE and appropriate error returns where not.
   - NFSv4.1 client adds session dynamic slot table management.  There
     is matching server side code that has been submitted to Bruce for
     consideration.

     Together, this code allows the server to dynamically manage the
     amount of memory it allocates to the duplicate request cache for
     each client.  It will constantly resize those caches to reserve
     more memory for clients that are hot while shrinking caches for
     those that are quiescent.

  In addition, there are assorted bugfixes for the generic NFS write
  code, fixes to deal with the drop_nlink() warnings, and yet another
  fix for NFSv4 getacl."

* tag 'nfs-for-3.8-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (106 commits)
  SUNRPC: continue run over clients list on PipeFS event instead of break
  NFS: Don't use SetPageError in the NFS writeback code
  SUNRPC: variable 'svsk' is unused in function bc_send_request
  SUNRPC: Handle ECONNREFUSED in xs_local_setup_socket
  NFSv4.1: Deal effectively with interrupted RPC calls.
  NFSv4.1: Move the RPC timestamp out of the slot.
  NFSv4.1: Try to deal with NFS4ERR_SEQ_MISORDERED.
  NFS: nfs_lookup_revalidate should not trust an inode with i_nlink == 0
  NFS: Fix calls to drop_nlink()
  NFS: Ensure that we always drop inodes that have been marked as stale
  nfs: Remove unused list nfs4_clientid_list
  nfs: Remove duplicate function declaration in internal.h
  NFS: avoid NULL dereference in nfs_destroy_server
  SUNRPC handle EKEYEXPIRED in call_refreshresult
  SUNRPC set gss gc_expiry to full lifetime
  nfs: fix page dirtying in NFS DIO read codepath
  nfs: don't zero out the rest of the page if we hit the EOF on a DIO READ
  NFSv4.1: Be conservative about the client highest slotid
  NFSv4.1: Handle NFS4ERR_BADSLOT errors correctly
  nfs: don't extend writes to cover entire page if pagecache is invalid
  ...

52 files changed:
fs/lockd/clnt4xdr.c
fs/lockd/clntproc.c
fs/lockd/clntxdr.c
fs/lockd/host.c
fs/lockd/mon.c
fs/nfs/Makefile
fs/nfs/blocklayout/blocklayout.c
fs/nfs/cache_lib.c
fs/nfs/callback.h
fs/nfs/callback_proc.c
fs/nfs/callback_xdr.c
fs/nfs/client.c
fs/nfs/dir.c
fs/nfs/direct.c
fs/nfs/inode.c
fs/nfs/internal.h
fs/nfs/mount_clnt.c
fs/nfs/nfs2xdr.c
fs/nfs/nfs3proc.c
fs/nfs/nfs3xdr.c
fs/nfs/nfs4_fs.h
fs/nfs/nfs4client.c
fs/nfs/nfs4file.c
fs/nfs/nfs4filelayout.c
fs/nfs/nfs4filelayoutdev.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4session.c [new file with mode: 0644]
fs/nfs/nfs4session.h [new file with mode: 0644]
fs/nfs/nfs4state.c
fs/nfs/nfs4super.c
fs/nfs/nfs4xdr.c
fs/nfs/objlayout/objlayout.c
fs/nfs/pnfs.c
fs/nfs/proc.c
fs/nfs/super.c
fs/nfs/write.c
include/linux/nfs_fs_sb.h
include/linux/nfs_xdr.h
include/linux/sunrpc/sched.h
net/sunrpc/auth_gss/auth_gss.c
net/sunrpc/backchannel_rqst.c
net/sunrpc/bc_svc.c
net/sunrpc/cache.c
net/sunrpc/clnt.c
net/sunrpc/rpc_pipe.c
net/sunrpc/rpcb_clnt.c
net/sunrpc/sched.c
net/sunrpc/svc.c
net/sunrpc/svc_xprt.c
net/sunrpc/svcsock.c
net/sunrpc/xdr.c
net/sunrpc/xprtsock.c

index 13ad1539fbf2479cd7f69a45611cd3d6a460688f..00ec0b9c94d116fd513e356e6616a4142ef10a94 100644 (file)
@@ -64,10 +64,6 @@ static void nlm4_compute_offsets(const struct nlm_lock *lock,
 {
        const struct file_lock *fl = &lock->fl;
 
-       BUG_ON(fl->fl_start > NLM4_OFFSET_MAX);
-       BUG_ON(fl->fl_end > NLM4_OFFSET_MAX &&
-                               fl->fl_end != OFFSET_MAX);
-
        *l_offset = loff_t_to_s64(fl->fl_start);
        if (fl->fl_end == OFFSET_MAX)
                *l_len = 0;
@@ -122,7 +118,6 @@ static void encode_netobj(struct xdr_stream *xdr,
 {
        __be32 *p;
 
-       BUG_ON(length > XDR_MAX_NETOBJ);
        p = xdr_reserve_space(xdr, 4 + length);
        xdr_encode_opaque(p, data, length);
 }
@@ -156,7 +151,6 @@ out_overflow:
 static void encode_cookie(struct xdr_stream *xdr,
                          const struct nlm_cookie *cookie)
 {
-       BUG_ON(cookie->len > NLM_MAXCOOKIELEN);
        encode_netobj(xdr, (u8 *)&cookie->data, cookie->len);
 }
 
@@ -198,7 +192,6 @@ out_overflow:
  */
 static void encode_fh(struct xdr_stream *xdr, const struct nfs_fh *fh)
 {
-       BUG_ON(fh->size > NFS3_FHSIZE);
        encode_netobj(xdr, (u8 *)&fh->data, fh->size);
 }
 
@@ -336,7 +329,6 @@ static void encode_caller_name(struct xdr_stream *xdr, const char *name)
        u32 length = strlen(name);
        __be32 *p;
 
-       BUG_ON(length > NLM_MAXSTRLEN);
        p = xdr_reserve_space(xdr, 4 + length);
        xdr_encode_opaque(p, name, length);
 }
index 05d29124c6ab4150c9a5381cbc98b9a472c65b25..54f9e6ce0430ae88d742709bc47499c0d1b71731 100644 (file)
@@ -141,7 +141,7 @@ static void nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl)
 
 static void nlmclnt_release_lockargs(struct nlm_rqst *req)
 {
-       BUG_ON(req->a_args.lock.fl.fl_ops != NULL);
+       WARN_ON_ONCE(req->a_args.lock.fl.fl_ops != NULL);
 }
 
 /**
@@ -465,7 +465,6 @@ static const struct file_lock_operations nlmclnt_lock_ops = {
 
 static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *host)
 {
-       BUG_ON(fl->fl_ops != NULL);
        fl->fl_u.nfs_fl.state = 0;
        fl->fl_u.nfs_fl.owner = nlm_find_lockowner(host, fl->fl_owner);
        INIT_LIST_HEAD(&fl->fl_u.nfs_fl.list);
index 982d2676e1f813b7e011b05223606af3a63451cc..9a55797a1cd420ac6b5fa051ebfc9d5780f2ccca 100644 (file)
@@ -60,10 +60,6 @@ static void nlm_compute_offsets(const struct nlm_lock *lock,
 {
        const struct file_lock *fl = &lock->fl;
 
-       BUG_ON(fl->fl_start > NLM_OFFSET_MAX);
-       BUG_ON(fl->fl_end > NLM_OFFSET_MAX &&
-                               fl->fl_end != OFFSET_MAX);
-
        *l_offset = loff_t_to_s32(fl->fl_start);
        if (fl->fl_end == OFFSET_MAX)
                *l_len = 0;
@@ -119,7 +115,6 @@ static void encode_netobj(struct xdr_stream *xdr,
 {
        __be32 *p;
 
-       BUG_ON(length > XDR_MAX_NETOBJ);
        p = xdr_reserve_space(xdr, 4 + length);
        xdr_encode_opaque(p, data, length);
 }
@@ -153,7 +148,6 @@ out_overflow:
 static void encode_cookie(struct xdr_stream *xdr,
                          const struct nlm_cookie *cookie)
 {
-       BUG_ON(cookie->len > NLM_MAXCOOKIELEN);
        encode_netobj(xdr, (u8 *)&cookie->data, cookie->len);
 }
 
@@ -195,7 +189,6 @@ out_overflow:
  */
 static void encode_fh(struct xdr_stream *xdr, const struct nfs_fh *fh)
 {
-       BUG_ON(fh->size != NFS2_FHSIZE);
        encode_netobj(xdr, (u8 *)&fh->data, NFS2_FHSIZE);
 }
 
@@ -330,7 +323,6 @@ static void encode_caller_name(struct xdr_stream *xdr, const char *name)
        u32 length = strlen(name);
        __be32 *p;
 
-       BUG_ON(length > NLM_MAXSTRLEN);
        p = xdr_reserve_space(xdr, 4 + length);
        xdr_encode_opaque(p, name, length);
 }
index f9b22e58f78f053a05fffa2ec11feaa32bc2518a..0e17090c310f100f00573590f5653e8e93bab88a 100644 (file)
@@ -177,9 +177,6 @@ static void nlm_destroy_host_locked(struct nlm_host *host)
 
        dprintk("lockd: destroy host %s\n", host->h_name);
 
-       BUG_ON(!list_empty(&host->h_lockowners));
-       BUG_ON(atomic_read(&host->h_count));
-
        hlist_del_init(&host->h_hash);
 
        nsm_unmonitor(host);
@@ -289,13 +286,12 @@ void nlmclnt_release_host(struct nlm_host *host)
 
        dprintk("lockd: release client host %s\n", host->h_name);
 
-       BUG_ON(atomic_read(&host->h_count) < 0);
-       BUG_ON(host->h_server);
+       WARN_ON_ONCE(host->h_server);
 
        if (atomic_dec_and_test(&host->h_count)) {
-               BUG_ON(!list_empty(&host->h_lockowners));
-               BUG_ON(!list_empty(&host->h_granted));
-               BUG_ON(!list_empty(&host->h_reclaim));
+               WARN_ON_ONCE(!list_empty(&host->h_lockowners));
+               WARN_ON_ONCE(!list_empty(&host->h_granted));
+               WARN_ON_ONCE(!list_empty(&host->h_reclaim));
 
                mutex_lock(&nlm_host_mutex);
                nlm_destroy_host_locked(host);
@@ -412,8 +408,7 @@ void nlmsvc_release_host(struct nlm_host *host)
 
        dprintk("lockd: release server host %s\n", host->h_name);
 
-       BUG_ON(atomic_read(&host->h_count) < 0);
-       BUG_ON(!host->h_server);
+       WARN_ON_ONCE(!host->h_server);
        atomic_dec(&host->h_count);
 }
 
index 3d7e09bcc0e9efad7418803737e385c76d22a776..3c2cfc6836315c288e9a0a367d03f235235ebbee 100644 (file)
@@ -154,8 +154,6 @@ static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res,
                .rpc_resp       = res,
        };
 
-       BUG_ON(clnt == NULL);
-
        memset(res, 0, sizeof(*res));
 
        msg.rpc_proc = &clnt->cl_procinfo[proc];
@@ -466,7 +464,6 @@ static void encode_nsm_string(struct xdr_stream *xdr, const char *string)
        const u32 len = strlen(string);
        __be32 *p;
 
-       BUG_ON(len > SM_MAXSTRLEN);
        p = xdr_reserve_space(xdr, 4 + len);
        xdr_encode_opaque(p, string, len);
 }
index b7db60897f91d5e8be99f59400add178cd082b8e..cce2c057bd2d61142d63ed6feb6232bbfd29fcab 100644 (file)
@@ -24,7 +24,7 @@ nfsv4-y := nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o nfs4super.o nfs4file.o
          delegation.o idmap.o callback.o callback_xdr.o callback_proc.o \
          nfs4namespace.o nfs4getroot.o nfs4client.o
 nfsv4-$(CONFIG_SYSCTL) += nfs4sysctl.o
-nfsv4-$(CONFIG_NFS_V4_1)       += pnfs.o pnfs_dev.o
+nfsv4-$(CONFIG_NFS_V4_1)       += nfs4session.o pnfs.o pnfs_dev.o
 
 obj-$(CONFIG_PNFS_FILE_LAYOUT) += nfs_layout_nfsv41_files.o
 nfs_layout_nfsv41_files-y := nfs4filelayout.o nfs4filelayoutdev.o
index f1027b06a1a9625e8fe7b0e7c551ce13e510414d..4fa788c93f4655bc0d014ff6090e12f5a31ef75d 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/pagevec.h>
 
 #include "../pnfs.h"
+#include "../nfs4session.h"
 #include "../internal.h"
 #include "blocklayout.h"
 
index dded2636811182497c5c78d24f51e81577d7aad5..862a2f16db64b7335453ef88ed7bea6e153cfa91 100644 (file)
@@ -118,7 +118,6 @@ int nfs_cache_register_sb(struct super_block *sb, struct cache_detail *cd)
        struct dentry *dir;
 
        dir = rpc_d_lookup_sb(sb, "cache");
-       BUG_ON(dir == NULL);
        ret = sunrpc_cache_register_pipefs(dir, cd->name, 0600, cd);
        dput(dir);
        return ret;
index 4251c2ae06adaf432e9d4d8304f4eea1b5b72c57..efd54f0a4c468f9c7e7726b751df36c6f94d1d16 100644 (file)
@@ -142,7 +142,7 @@ extern __be32 nfs4_callback_recallany(struct cb_recallanyargs *args,
 
 struct cb_recallslotargs {
        struct sockaddr *crsa_addr;
-       uint32_t        crsa_target_max_slots;
+       uint32_t        crsa_target_highest_slotid;
 };
 extern __be32 nfs4_callback_recallslot(struct cb_recallslotargs *args,
                                         void *dummy,
@@ -167,8 +167,6 @@ extern __be32 nfs4_callback_layoutrecall(
        struct cb_layoutrecallargs *args,
        void *dummy, struct cb_process_state *cps);
 
-extern void nfs4_check_drain_bc_complete(struct nfs4_session *ses);
-
 struct cb_devicenotifyitem {
        uint32_t                cbd_notify_type;
        uint32_t                cbd_layout_type;
index 76b4a7a3e55931e0f9cc79d08c248048cbfaa961..c89b26bc9759251ab370da28eab07a266adbd573 100644 (file)
@@ -14,6 +14,7 @@
 #include "delegation.h"
 #include "internal.h"
 #include "pnfs.h"
+#include "nfs4session.h"
 
 #ifdef NFS_DEBUG
 #define NFSDBG_FACILITY NFSDBG_CALLBACK
@@ -216,7 +217,6 @@ static u32 initiate_bulk_draining(struct nfs_client *clp,
                        }
                        pnfs_get_layout_hdr(lo);
                        spin_unlock(&ino->i_lock);
-                       BUG_ON(!list_empty(&lo->plh_bulk_recall));
                        list_add(&lo->plh_bulk_recall, &recall_list);
                }
        }
@@ -562,23 +562,16 @@ __be32 nfs4_callback_recallslot(struct cb_recallslotargs *args, void *dummy,
        if (!cps->clp) /* set in cb_sequence */
                goto out;
 
-       dprintk_rcu("NFS: CB_RECALL_SLOT request from %s target max slots %d\n",
+       dprintk_rcu("NFS: CB_RECALL_SLOT request from %s target highest slotid %d\n",
                rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR),
-               args->crsa_target_max_slots);
+               args->crsa_target_highest_slotid);
 
        fc_tbl = &cps->clp->cl_session->fc_slot_table;
 
-       status = htonl(NFS4ERR_BAD_HIGH_SLOT);
-       if (args->crsa_target_max_slots > fc_tbl->max_slots ||
-           args->crsa_target_max_slots < 1)
-               goto out;
-
        status = htonl(NFS4_OK);
-       if (args->crsa_target_max_slots == fc_tbl->max_slots)
-               goto out;
 
-       fc_tbl->target_max_slots = args->crsa_target_max_slots;
-       nfs41_handle_recall_slot(cps->clp);
+       nfs41_set_target_slotid(fc_tbl, args->crsa_target_highest_slotid);
+       nfs41_server_notify_target_slotid_update(cps->clp);
 out:
        dprintk("%s: exit with status = %d\n", __func__, ntohl(status));
        return status;
index 742ff4ffced78fe9071da9c15ee22f458bfde3ca..59461c957d9d7ed7204e09f9fad1aa0b154d8486 100644 (file)
@@ -16,6 +16,7 @@
 #include "nfs4_fs.h"
 #include "callback.h"
 #include "internal.h"
+#include "nfs4session.h"
 
 #define CB_OP_TAGLEN_MAXSZ     (512)
 #define CB_OP_HDR_RES_MAXSZ    (2 + CB_OP_TAGLEN_MAXSZ)
@@ -520,7 +521,7 @@ static __be32 decode_recallslot_args(struct svc_rqst *rqstp,
        p = read_buf(xdr, 4);
        if (unlikely(p == NULL))
                return htonl(NFS4ERR_BADXDR);
-       args->crsa_target_max_slots = ntohl(*p++);
+       args->crsa_target_highest_slotid = ntohl(*p++);
        return 0;
 }
 
@@ -762,7 +763,7 @@ static void nfs4_callback_free_slot(struct nfs4_session *session)
         * A single slot, so highest used slotid is either 0 or -1
         */
        tbl->highest_used_slotid = NFS4_NO_SLOT;
-       nfs4_check_drain_bc_complete(session);
+       nfs4_session_drain_complete(session, tbl);
        spin_unlock(&tbl->slot_tbl_lock);
 }
 
index 8b39a42ac35ee5d8c081f205e631b6b2458b4be1..9f3c66438d0e52251182fdf00685488e9b2b9043 100644 (file)
@@ -277,7 +277,7 @@ void nfs_put_client(struct nfs_client *clp)
                nfs_cb_idr_remove_locked(clp);
                spin_unlock(&nn->nfs_client_lock);
 
-               BUG_ON(!list_empty(&clp->cl_superblocks));
+               WARN_ON_ONCE(!list_empty(&clp->cl_superblocks));
 
                clp->rpc_ops->free_client(clp);
        }
@@ -615,8 +615,7 @@ EXPORT_SYMBOL_GPL(nfs_create_rpc_client);
  */
 static void nfs_destroy_server(struct nfs_server *server)
 {
-       if (!(server->flags & NFS_MOUNT_LOCAL_FLOCK) ||
-                       !(server->flags & NFS_MOUNT_LOCAL_FCNTL))
+       if (server->nlm_host)
                nlmclnt_done(server->nlm_host);
 }
 
@@ -1061,10 +1060,6 @@ struct nfs_server *nfs_create_server(struct nfs_mount_info *mount_info,
        if (error < 0)
                goto error;
 
-       BUG_ON(!server->nfs_client);
-       BUG_ON(!server->nfs_client->rpc_ops);
-       BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops);
-
        /* Probe the root fh to retrieve its FSID */
        error = nfs_probe_fsinfo(server, mount_info->mntfh, fattr);
        if (error < 0)
index 1cc71f60b491e7ab7abcabeee22ae1ab54e77ab7..32e6c53520e22033237206e9264378efe33104e6 100644 (file)
@@ -979,10 +979,11 @@ static int nfs_is_exclusive_create(struct inode *dir, unsigned int flags)
  * particular file and the "nocto" mount flag is not set.
  *
  */
-static inline
+static
 int nfs_lookup_verify_inode(struct inode *inode, unsigned int flags)
 {
        struct nfs_server *server = NFS_SERVER(inode);
+       int ret;
 
        if (IS_AUTOMOUNT(inode))
                return 0;
@@ -993,9 +994,13 @@ int nfs_lookup_verify_inode(struct inode *inode, unsigned int flags)
        if ((flags & LOOKUP_OPEN) && !(server->flags & NFS_MOUNT_NOCTO) &&
            (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)))
                goto out_force;
-       return 0;
+out:
+       return (inode->i_nlink == 0) ? -ENOENT : 0;
 out_force:
-       return __nfs_revalidate_inode(server, inode);
+       ret = __nfs_revalidate_inode(server, inode);
+       if (ret != 0)
+               return ret;
+       goto out;
 }
 
 /*
@@ -1156,11 +1161,14 @@ static int nfs_dentry_delete(const struct dentry *dentry)
 
 }
 
+/* Ensure that we revalidate inode->i_nlink */
 static void nfs_drop_nlink(struct inode *inode)
 {
        spin_lock(&inode->i_lock);
-       if (inode->i_nlink > 0)
-               drop_nlink(inode);
+       /* drop the inode if we're reasonably sure this is the last link */
+       if (inode->i_nlink == 1)
+               clear_nlink(inode);
+       NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATTR;
        spin_unlock(&inode->i_lock);
 }
 
@@ -1175,8 +1183,8 @@ static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode)
                NFS_I(inode)->cache_validity |= NFS_INO_INVALID_DATA;
 
        if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
-               drop_nlink(inode);
                nfs_complete_unlink(dentry, inode);
+               nfs_drop_nlink(inode);
        }
        iput(inode);
 }
@@ -1647,10 +1655,8 @@ static int nfs_safe_remove(struct dentry *dentry)
        if (inode != NULL) {
                NFS_PROTO(inode)->return_delegation(inode);
                error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
-               /* The VFS may want to delete this inode */
                if (error == 0)
                        nfs_drop_nlink(inode);
-               nfs_mark_for_revalidate(inode);
        } else
                error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
        if (error == -ENOENT)
index cae26cbd59ee89cd5d73e719ef201b26ef9cabc3..0bd7a55a5f073befd4d0ce97e87cca2dd0d42e37 100644 (file)
@@ -266,21 +266,8 @@ static void nfs_direct_read_completion(struct nfs_pgio_header *hdr)
                struct nfs_page *req = nfs_list_entry(hdr->pages.next);
                struct page *page = req->wb_page;
 
-               if (test_bit(NFS_IOHDR_EOF, &hdr->flags)) {
-                       if (bytes > hdr->good_bytes)
-                               zero_user(page, 0, PAGE_SIZE);
-                       else if (hdr->good_bytes - bytes < PAGE_SIZE)
-                               zero_user_segment(page,
-                                       hdr->good_bytes & ~PAGE_MASK,
-                                       PAGE_SIZE);
-               }
-               if (!PageCompound(page)) {
-                       if (test_bit(NFS_IOHDR_ERROR, &hdr->flags)) {
-                               if (bytes < hdr->good_bytes)
-                                       set_page_dirty(page);
-                       } else
-                               set_page_dirty(page);
-               }
+               if (!PageCompound(page) && bytes < hdr->good_bytes)
+                       set_page_dirty(page);
                bytes += req->wb_bytes;
                nfs_list_remove_request(req);
                nfs_direct_readpage_release(req);
index 6fa01aea24889cae08385e5bfe0aab16c742adc8..2faae14d89f46e97d76f1e82c85f776426c85816 100644 (file)
@@ -107,13 +107,19 @@ u64 nfs_compat_user_ino64(u64 fileid)
        return ino;
 }
 
+int nfs_drop_inode(struct inode *inode)
+{
+       return NFS_STALE(inode) || generic_drop_inode(inode);
+}
+EXPORT_SYMBOL_GPL(nfs_drop_inode);
+
 void nfs_clear_inode(struct inode *inode)
 {
        /*
         * The following should never happen...
         */
-       BUG_ON(nfs_have_writebacks(inode));
-       BUG_ON(!list_empty(&NFS_I(inode)->open_files));
+       WARN_ON_ONCE(nfs_have_writebacks(inode));
+       WARN_ON_ONCE(!list_empty(&NFS_I(inode)->open_files));
        nfs_zap_acl_cache(inode);
        nfs_access_zap_cache(inode);
        nfs_fscache_release_inode_cookie(inode);
index 05521cadac2e9821292c8c4eeefa037f5ef0a726..f0e6c7df1a072a07313de2a92203260b70f9da52 100644 (file)
@@ -18,27 +18,6 @@ struct nfs_string;
  */
 #define NFS_MAX_READAHEAD      (RPC_DEF_SLOT_TABLE - 1)
 
-/*
- * Determine if sessions are in use.
- */
-static inline int nfs4_has_session(const struct nfs_client *clp)
-{
-#ifdef CONFIG_NFS_V4_1
-       if (clp->cl_session)
-               return 1;
-#endif /* CONFIG_NFS_V4_1 */
-       return 0;
-}
-
-static inline int nfs4_has_persistent_session(const struct nfs_client *clp)
-{
-#ifdef CONFIG_NFS_V4_1
-       if (nfs4_has_session(clp))
-               return (clp->cl_session->flags & SESSION4_PERSIST);
-#endif /* CONFIG_NFS_V4_1 */
-       return 0;
-}
-
 static inline void nfs_attr_check_mountpoint(struct super_block *parent, struct nfs_fattr *fattr)
 {
        if (!nfs_fsid_equal(&NFS_SB(parent)->fsid, &fattr->fsid))
@@ -276,8 +255,6 @@ extern const u32 nfs41_maxwrite_overhead;
 extern struct rpc_procinfo nfs4_procedures[];
 #endif
 
-extern int nfs4_init_ds_session(struct nfs_client *, unsigned long);
-
 /* proc.c */
 void nfs_close_context(struct nfs_open_context *ctx, int is_sync);
 extern struct nfs_client *nfs_init_client(struct nfs_client *clp,
@@ -319,6 +296,7 @@ extern struct workqueue_struct *nfsiod_workqueue;
 extern struct inode *nfs_alloc_inode(struct super_block *sb);
 extern void nfs_destroy_inode(struct inode *);
 extern int nfs_write_inode(struct inode *, struct writeback_control *);
+extern int nfs_drop_inode(struct inode *);
 extern void nfs_clear_inode(struct inode *);
 extern void nfs_evict_inode(struct inode *);
 void nfs_zap_acl_cache(struct inode *inode);
@@ -386,9 +364,6 @@ extern int nfs_initiate_read(struct rpc_clnt *clnt,
 extern void nfs_read_prepare(struct rpc_task *task, void *calldata);
 extern int nfs_generic_pagein(struct nfs_pageio_descriptor *desc,
                              struct nfs_pgio_header *hdr);
-extern void nfs_pageio_init_read(struct nfs_pageio_descriptor *pgio,
-                       struct inode *inode,
-                       const struct nfs_pgio_completion_ops *compl_ops);
 extern void nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio);
 extern void nfs_readdata_release(struct nfs_read_data *rdata);
 
@@ -411,9 +386,6 @@ extern struct nfs_write_header *nfs_writehdr_alloc(void);
 extern void nfs_writehdr_free(struct nfs_pgio_header *hdr);
 extern int nfs_generic_flush(struct nfs_pageio_descriptor *desc,
                             struct nfs_pgio_header *hdr);
-extern void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio,
-                       struct inode *inode, int ioflags,
-                       const struct nfs_pgio_completion_ops *compl_ops);
 extern void nfs_pageio_reset_write_mds(struct nfs_pageio_descriptor *pgio);
 extern void nfs_writedata_release(struct nfs_write_data *wdata);
 extern void nfs_commit_free(struct nfs_commit_data *p);
@@ -474,18 +446,6 @@ extern struct nfs_client *nfs4_init_client(struct nfs_client *clp,
                            const struct rpc_timeout *timeparms,
                            const char *ip_addr,
                            rpc_authflavor_t authflavour);
-extern int _nfs4_call_sync(struct rpc_clnt *clnt,
-                          struct nfs_server *server,
-                          struct rpc_message *msg,
-                          struct nfs4_sequence_args *args,
-                          struct nfs4_sequence_res *res,
-                          int cache_reply);
-extern int _nfs4_call_sync_session(struct rpc_clnt *clnt,
-                                  struct nfs_server *server,
-                                  struct rpc_message *msg,
-                                  struct nfs4_sequence_args *args,
-                                  struct nfs4_sequence_res *res,
-                                  int cache_reply);
 extern int nfs40_walk_client_list(struct nfs_client *clp,
                                struct nfs_client **result,
                                struct rpc_cred *cred);
index 015f71f8f62c271ebcd6c6ec3949aeff446ce420..91a6faf811accb8e8e35ab6c3644e16058356a2a 100644 (file)
@@ -169,6 +169,9 @@ int nfs_mount(struct nfs_mount_request *info)
                (info->hostname ? info->hostname : "server"),
                        info->dirpath);
 
+       if (strlen(info->dirpath) > MNTPATHLEN)
+               return -ENAMETOOLONG;
+
        if (info->noresvport)
                args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
 
@@ -242,6 +245,9 @@ void nfs_umount(const struct nfs_mount_request *info)
        struct rpc_clnt *clnt;
        int status;
 
+       if (strlen(info->dirpath) > MNTPATHLEN)
+               return;
+
        if (info->noresvport)
                args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
 
@@ -283,7 +289,6 @@ static void encode_mntdirpath(struct xdr_stream *xdr, const char *pathname)
        const u32 pathname_len = strlen(pathname);
        __be32 *p;
 
-       BUG_ON(pathname_len > MNTPATHLEN);
        p = xdr_reserve_space(xdr, 4 + pathname_len);
        xdr_encode_opaque(p, pathname, pathname_len);
 }
index d04f0df7be553db3aa89ce5637ff3c8ef3044d07..06b9df49f7f7773fa62ad1b7215b2ffcdfee852a 100644 (file)
@@ -195,7 +195,6 @@ static void encode_fhandle(struct xdr_stream *xdr, const struct nfs_fh *fh)
 {
        __be32 *p;
 
-       BUG_ON(fh->size != NFS2_FHSIZE);
        p = xdr_reserve_space(xdr, NFS2_FHSIZE);
        memcpy(p, fh->data, NFS2_FHSIZE);
 }
@@ -388,7 +387,7 @@ static void encode_filename(struct xdr_stream *xdr,
 {
        __be32 *p;
 
-       BUG_ON(length > NFS2_MAXNAMLEN);
+       WARN_ON_ONCE(length > NFS2_MAXNAMLEN);
        p = xdr_reserve_space(xdr, 4 + length);
        xdr_encode_opaque(p, name, length);
 }
@@ -428,7 +427,6 @@ static void encode_path(struct xdr_stream *xdr, struct page **pages, u32 length)
 {
        __be32 *p;
 
-       BUG_ON(length > NFS2_MAXPATHLEN);
        p = xdr_reserve_space(xdr, 4);
        *p = cpu_to_be32(length);
        xdr_write_pages(xdr, pages, 0, length);
index 69322096c32569d4674517f7121e4fc272206ba8..70efb63b1e42f7d04f80fbb29454b0961b5c1517 100644 (file)
 
 #define NFSDBG_FACILITY                NFSDBG_PROC
 
-/* A wrapper to handle the EJUKEBOX and EKEYEXPIRED error messages */
+/* A wrapper to handle the EJUKEBOX error messages */
 static int
 nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
 {
        int res;
        do {
                res = rpc_call_sync(clnt, msg, flags);
-               if (res != -EJUKEBOX && res != -EKEYEXPIRED)
+               if (res != -EJUKEBOX)
                        break;
                freezable_schedule_timeout_killable(NFS_JUKEBOX_RETRY_TIME);
                res = -ERESTARTSYS;
@@ -44,7 +44,7 @@ nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
 static int
 nfs3_async_handle_jukebox(struct rpc_task *task, struct inode *inode)
 {
-       if (task->tk_status != -EJUKEBOX && task->tk_status != -EKEYEXPIRED)
+       if (task->tk_status != -EJUKEBOX)
                return 0;
        if (task->tk_status == -EJUKEBOX)
                nfs_inc_stats(inode, NFSIOS_DELAY);
index 6cbe89400dfcc134b9af58d6ad16ecf42bab911a..bffc32406fbf81b764d43a298e12489b5fa37faf 100644 (file)
@@ -198,7 +198,7 @@ static void encode_filename3(struct xdr_stream *xdr,
 {
        __be32 *p;
 
-       BUG_ON(length > NFS3_MAXNAMLEN);
+       WARN_ON_ONCE(length > NFS3_MAXNAMLEN);
        p = xdr_reserve_space(xdr, 4 + length);
        xdr_encode_opaque(p, name, length);
 }
@@ -238,7 +238,6 @@ out_overflow:
 static void encode_nfspath3(struct xdr_stream *xdr, struct page **pages,
                            const u32 length)
 {
-       BUG_ON(length > NFS3_MAXPATHLEN);
        encode_uint32(xdr, length);
        xdr_write_pages(xdr, pages, 0, length);
 }
@@ -388,7 +387,6 @@ out_overflow:
  */
 static void encode_ftype3(struct xdr_stream *xdr, const u32 type)
 {
-       BUG_ON(type > NF3FIFO);
        encode_uint32(xdr, type);
 }
 
@@ -443,7 +441,7 @@ static void encode_nfs_fh3(struct xdr_stream *xdr, const struct nfs_fh *fh)
 {
        __be32 *p;
 
-       BUG_ON(fh->size > NFS3_FHSIZE);
+       WARN_ON_ONCE(fh->size > NFS3_FHSIZE);
        p = xdr_reserve_space(xdr, 4 + fh->size);
        xdr_encode_opaque(p, fh->data, fh->size);
 }
@@ -1339,6 +1337,7 @@ static void nfs3_xdr_enc_setacl3args(struct rpc_rqst *req,
        error = nfsacl_encode(xdr->buf, base, args->inode,
                            (args->mask & NFS_ACL) ?
                            args->acl_access : NULL, 1, 0);
+       /* FIXME: this is just broken */
        BUG_ON(error < 0);
        error = nfsacl_encode(xdr->buf, base + error, args->inode,
                            (args->mask & NFS_DFACL) ?
index a525fdefccdeb475edb9468c1467e6196db20246..a3f488b074a2f0d55d561de8f2e529c7d4614b34 100644 (file)
@@ -11,6 +11,8 @@
 
 #if IS_ENABLED(CONFIG_NFS_V4)
 
+#define NFS4_MAX_LOOP_ON_RECOVER (10)
+
 struct idmap;
 
 enum nfs4_client_state {
@@ -21,18 +23,12 @@ enum nfs4_client_state {
        NFS4CLNT_RECLAIM_NOGRACE,
        NFS4CLNT_DELEGRETURN,
        NFS4CLNT_SESSION_RESET,
-       NFS4CLNT_RECALL_SLOT,
        NFS4CLNT_LEASE_CONFIRM,
        NFS4CLNT_SERVER_SCOPE_MISMATCH,
        NFS4CLNT_PURGE_STATE,
        NFS4CLNT_BIND_CONN_TO_SESSION,
 };
 
-enum nfs4_session_state {
-       NFS4_SESSION_INITING,
-       NFS4_SESSION_DRAINING,
-};
-
 #define NFS4_RENEW_TIMEOUT             0x01
 #define NFS4_RENEW_DELEGATION_CB       0x02
 
@@ -43,8 +39,7 @@ struct nfs4_minor_version_ops {
                        struct nfs_server *server,
                        struct rpc_message *msg,
                        struct nfs4_sequence_args *args,
-                       struct nfs4_sequence_res *res,
-                       int cache_reply);
+                       struct nfs4_sequence_res *res);
        bool    (*match_stateid)(const nfs4_stateid *,
                        const nfs4_stateid *);
        int     (*find_root_sec)(struct nfs_server *, struct nfs_fh *,
@@ -241,18 +236,14 @@ static inline struct nfs4_session *nfs4_get_session(const struct nfs_server *ser
        return server->nfs_client->cl_session;
 }
 
-extern bool nfs4_set_task_privileged(struct rpc_task *task, void *dummy);
 extern int nfs4_setup_sequence(const struct nfs_server *server,
                struct nfs4_sequence_args *args, struct nfs4_sequence_res *res,
                struct rpc_task *task);
 extern int nfs41_setup_sequence(struct nfs4_session *session,
                struct nfs4_sequence_args *args, struct nfs4_sequence_res *res,
                struct rpc_task *task);
-extern void nfs4_destroy_session(struct nfs4_session *session);
-extern struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp);
 extern int nfs4_proc_create_session(struct nfs_client *, struct rpc_cred *);
 extern int nfs4_proc_destroy_session(struct nfs4_session *, struct rpc_cred *);
-extern int nfs4_init_session(struct nfs_server *server);
 extern int nfs4_proc_get_lease_time(struct nfs_client *clp,
                struct nfs_fsinfo *fsinfo);
 extern int nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data,
@@ -280,11 +271,7 @@ static inline int nfs4_setup_sequence(const struct nfs_server *server,
                struct nfs4_sequence_args *args, struct nfs4_sequence_res *res,
                struct rpc_task *task)
 {
-       return 0;
-}
-
-static inline int nfs4_init_session(struct nfs_server *server)
-{
+       rpc_call_start(task);
        return 0;
 }
 
@@ -321,17 +308,20 @@ extern void nfs4_renew_state(struct work_struct *);
 
 /* nfs4state.c */
 struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp);
+struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp);
 struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp);
 int nfs4_discover_server_trunking(struct nfs_client *clp,
                        struct nfs_client **);
 int nfs40_discover_server_trunking(struct nfs_client *clp,
                        struct nfs_client **, struct rpc_cred *);
 #if defined(CONFIG_NFS_V4_1)
-struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp);
 struct rpc_cred *nfs4_get_exchange_id_cred(struct nfs_client *clp);
 int nfs41_discover_server_trunking(struct nfs_client *clp,
                        struct nfs_client **, struct rpc_cred *);
 extern void nfs4_schedule_session_recovery(struct nfs4_session *, int);
+extern void nfs41_server_notify_target_slotid_update(struct nfs_client *clp);
+extern void nfs41_server_notify_highest_slotid_update(struct nfs_client *clp);
+
 #else
 static inline void nfs4_schedule_session_recovery(struct nfs4_session *session, int err)
 {
@@ -349,11 +339,12 @@ extern void nfs4_state_set_mode_locked(struct nfs4_state *, fmode_t);
 extern void nfs_inode_find_state_and_recover(struct inode *inode,
                const nfs4_stateid *stateid);
 extern void nfs4_schedule_lease_recovery(struct nfs_client *);
+extern int nfs4_wait_clnt_recover(struct nfs_client *clp);
+extern int nfs4_client_recover_expired_lease(struct nfs_client *clp);
 extern void nfs4_schedule_state_manager(struct nfs_client *);
 extern void nfs4_schedule_path_down_recovery(struct nfs_client *clp);
 extern void nfs4_schedule_stateid_recovery(const struct nfs_server *, struct nfs4_state *);
 extern void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags);
-extern void nfs41_handle_recall_slot(struct nfs_client *clp);
 extern void nfs41_handle_server_scope(struct nfs_client *,
                                      struct nfs41_server_scope **);
 extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp);
index 6bacfde1319a76945a9ab9634e453f8a61def8ce..acc3472681244d004f743a198e802709a38927b4 100644 (file)
@@ -12,6 +12,7 @@
 #include "internal.h"
 #include "callback.h"
 #include "delegation.h"
+#include "nfs4session.h"
 #include "pnfs.h"
 #include "netns.h"
 
@@ -713,10 +714,6 @@ static int nfs4_server_common_setup(struct nfs_server *server,
        struct nfs_fattr *fattr;
        int error;
 
-       BUG_ON(!server->nfs_client);
-       BUG_ON(!server->nfs_client->rpc_ops);
-       BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops);
-
        /* data servers support only a subset of NFSv4.1 */
        if (is_ds_only_client(server->nfs_client))
                return -EPROTONOSUPPORT;
index afddd6639afb1bd5242e95c5b659fa2b86174181..e7699308364acf6f84fcf62e5f815ed2c74c2b5c 100644 (file)
@@ -20,7 +20,6 @@ nfs4_file_open(struct inode *inode, struct file *filp)
        struct iattr attr;
        int err;
 
-       BUG_ON(inode != dentry->d_inode);
        /*
         * If no cached dentry exists or if it's negative, NFSv4 handled the
         * opens in ->lookup() or ->create().
index 2e45fd9c02a38cc9d7b3ee0ee87150fa3a8e7ea8..194c484103365bf0e000a60cb850e915404d80c0 100644 (file)
@@ -35,6 +35,7 @@
 
 #include <linux/sunrpc/metrics.h>
 
+#include "nfs4session.h"
 #include "internal.h"
 #include "delegation.h"
 #include "nfs4filelayout.h"
@@ -178,7 +179,6 @@ static int filelayout_async_handle_error(struct rpc_task *task,
                break;
        case -NFS4ERR_DELAY:
        case -NFS4ERR_GRACE:
-       case -EKEYEXPIRED:
                rpc_delay(task, FILELAYOUT_POLL_RETRY_MAX);
                break;
        case -NFS4ERR_RETRY_UNCACHED_REP:
@@ -306,12 +306,10 @@ static void filelayout_read_prepare(struct rpc_task *task, void *data)
        }
        rdata->read_done_cb = filelayout_read_done_cb;
 
-       if (nfs41_setup_sequence(rdata->ds_clp->cl_session,
-                               &rdata->args.seq_args, &rdata->res.seq_res,
-                               task))
-               return;
-
-       rpc_call_start(task);
+       nfs41_setup_sequence(rdata->ds_clp->cl_session,
+                       &rdata->args.seq_args,
+                       &rdata->res.seq_res,
+                       task);
 }
 
 static void filelayout_read_call_done(struct rpc_task *task, void *data)
@@ -408,12 +406,10 @@ static void filelayout_write_prepare(struct rpc_task *task, void *data)
                rpc_exit(task, 0);
                return;
        }
-       if (nfs41_setup_sequence(wdata->ds_clp->cl_session,
-                               &wdata->args.seq_args, &wdata->res.seq_res,
-                               task))
-               return;
-
-       rpc_call_start(task);
+       nfs41_setup_sequence(wdata->ds_clp->cl_session,
+                       &wdata->args.seq_args,
+                       &wdata->res.seq_res,
+                       task);
 }
 
 static void filelayout_write_call_done(struct rpc_task *task, void *data)
@@ -449,12 +445,10 @@ static void filelayout_commit_prepare(struct rpc_task *task, void *data)
 {
        struct nfs_commit_data *wdata = data;
 
-       if (nfs41_setup_sequence(wdata->ds_clp->cl_session,
-                               &wdata->args.seq_args, &wdata->res.seq_res,
-                               task))
-               return;
-
-       rpc_call_start(task);
+       nfs41_setup_sequence(wdata->ds_clp->cl_session,
+                       &wdata->args.seq_args,
+                       &wdata->res.seq_res,
+                       task);
 }
 
 static void filelayout_write_commit_done(struct rpc_task *task, void *data)
@@ -512,7 +506,6 @@ filelayout_read_pagelist(struct nfs_read_data *data)
        loff_t offset = data->args.offset;
        u32 j, idx;
        struct nfs_fh *fh;
-       int status;
 
        dprintk("--> %s ino %lu pgbase %u req %Zu@%llu\n",
                __func__, hdr->inode->i_ino,
@@ -538,9 +531,8 @@ filelayout_read_pagelist(struct nfs_read_data *data)
        data->mds_offset = offset;
 
        /* Perform an asynchronous read to ds */
-       status = nfs_initiate_read(ds->ds_clp->cl_rpcclient, data,
+       nfs_initiate_read(ds->ds_clp->cl_rpcclient, data,
                                  &filelayout_read_call_ops, RPC_TASK_SOFTCONN);
-       BUG_ON(status != 0);
        return PNFS_ATTEMPTED;
 }
 
@@ -554,7 +546,6 @@ filelayout_write_pagelist(struct nfs_write_data *data, int sync)
        loff_t offset = data->args.offset;
        u32 j, idx;
        struct nfs_fh *fh;
-       int status;
 
        /* Retrieve the correct rpc_client for the byte range */
        j = nfs4_fl_calc_j_index(lseg, offset);
@@ -579,10 +570,9 @@ filelayout_write_pagelist(struct nfs_write_data *data, int sync)
        data->args.offset = filelayout_get_dserver_offset(lseg, offset);
 
        /* Perform an asynchronous write */
-       status = nfs_initiate_write(ds->ds_clp->cl_rpcclient, data,
+       nfs_initiate_write(ds->ds_clp->cl_rpcclient, data,
                                    &filelayout_write_call_ops, sync,
                                    RPC_TASK_SOFTCONN);
-       BUG_ON(status != 0);
        return PNFS_ATTEMPTED;
 }
 
@@ -909,7 +899,7 @@ static void
 filelayout_pg_init_read(struct nfs_pageio_descriptor *pgio,
                        struct nfs_page *req)
 {
-       BUG_ON(pgio->pg_lseg != NULL);
+       WARN_ON_ONCE(pgio->pg_lseg != NULL);
 
        if (req->wb_offset != req->wb_pgbase) {
                /*
@@ -939,7 +929,7 @@ filelayout_pg_init_write(struct nfs_pageio_descriptor *pgio,
        struct nfs_commit_info cinfo;
        int status;
 
-       BUG_ON(pgio->pg_lseg != NULL);
+       WARN_ON_ONCE(pgio->pg_lseg != NULL);
 
        if (req->wb_offset != req->wb_pgbase)
                goto out_mds;
@@ -1187,7 +1177,6 @@ static void filelayout_recover_commit_reqs(struct list_head *dst,
         */
        for (i = 0, b = cinfo->ds->buckets; i < cinfo->ds->nbuckets; i++, b++) {
                if (transfer_commit_list(&b->written, dst, cinfo, 0)) {
-                       BUG_ON(!list_empty(&b->written));
                        pnfs_put_lseg(b->wlseg);
                        b->wlseg = NULL;
                }
index a8eaa9b7bb0f2c8fc704b8eb752c2ebc564b52bf..b720064bcd7ff15435ce4b7a4dcb5a2d1065b29f 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/module.h>
 
 #include "internal.h"
+#include "nfs4session.h"
 #include "nfs4filelayout.h"
 
 #define NFSDBG_FACILITY                NFSDBG_PNFS_LD
@@ -162,8 +163,6 @@ nfs4_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds)
        dprintk("--> %s DS %s au_flavor %d\n", __func__, ds->ds_remotestr,
                mds_srv->nfs_client->cl_rpcclient->cl_auth->au_flavor);
 
-       BUG_ON(list_empty(&ds->ds_addrs));
-
        list_for_each_entry(da, &ds->ds_addrs, da_node) {
                dprintk("%s: DS %s: trying address %s\n",
                        __func__, ds->ds_remotestr, da->da_remotestr);
index 5eec4429970c6e98af7a18732794c6fceaba4951..493f0f41c5547d94eecf12de33bc8acf1545c2f7 100644 (file)
@@ -52,7 +52,6 @@
 #include <linux/mount.h>
 #include <linux/module.h>
 #include <linux/nfs_idmap.h>
-#include <linux/sunrpc/bc_xprt.h>
 #include <linux/xattr.h>
 #include <linux/utsname.h>
 #include <linux/freezer.h>
 #include "callback.h"
 #include "pnfs.h"
 #include "netns.h"
+#include "nfs4session.h"
+
 
 #define NFSDBG_FACILITY                NFSDBG_PROC
 
 #define NFS4_POLL_RETRY_MIN    (HZ/10)
 #define NFS4_POLL_RETRY_MAX    (15*HZ)
 
-#define NFS4_MAX_LOOP_ON_RECOVER (10)
-
 struct nfs4_opendata;
 static int _nfs4_proc_open(struct nfs4_opendata *data);
 static int _nfs4_recover_proc_open(struct nfs4_opendata *data);
@@ -206,7 +205,6 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent
 {
        __be32 *start, *p;
 
-       BUG_ON(readdir->count < 80);
        if (cookie > 2) {
                readdir->cookie = cookie;
                memcpy(&readdir->verifier, verifier, sizeof(readdir->verifier));
@@ -256,22 +254,6 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent
        kunmap_atomic(start);
 }
 
-static int nfs4_wait_clnt_recover(struct nfs_client *clp)
-{
-       int res;
-
-       might_sleep();
-
-       res = wait_on_bit(&clp->cl_state, NFS4CLNT_MANAGER_RUNNING,
-                       nfs_wait_bit_killable, TASK_KILLABLE);
-       if (res)
-               return res;
-
-       if (clp->cl_cons_state < 0)
-               return clp->cl_cons_state;
-       return 0;
-}
-
 static int nfs4_delay(struct rpc_clnt *clnt, long *timeout)
 {
        int res = 0;
@@ -351,7 +333,6 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc
                        }
                case -NFS4ERR_GRACE:
                case -NFS4ERR_DELAY:
-               case -EKEYEXPIRED:
                        ret = nfs4_delay(server->client, &exception->timeout);
                        if (ret != 0)
                                break;
@@ -397,144 +378,136 @@ static void renew_lease(const struct nfs_server *server, unsigned long timestamp
 
 #if defined(CONFIG_NFS_V4_1)
 
-/*
- * nfs4_free_slot - free a slot and efficiently update slot table.
- *
- * freeing a slot is trivially done by clearing its respective bit
- * in the bitmap.
- * If the freed slotid equals highest_used_slotid we want to update it
- * so that the server would be able to size down the slot table if needed,
- * otherwise we know that the highest_used_slotid is still in use.
- * When updating highest_used_slotid there may be "holes" in the bitmap
- * so we need to scan down from highest_used_slotid to 0 looking for the now
- * highest slotid in use.
- * If none found, highest_used_slotid is set to NFS4_NO_SLOT.
- *
- * Must be called while holding tbl->slot_tbl_lock
- */
-static void
-nfs4_free_slot(struct nfs4_slot_table *tbl, u32 slotid)
-{
-       BUG_ON(slotid >= NFS4_MAX_SLOT_TABLE);
-       /* clear used bit in bitmap */
-       __clear_bit(slotid, tbl->used_slots);
-
-       /* update highest_used_slotid when it is freed */
-       if (slotid == tbl->highest_used_slotid) {
-               slotid = find_last_bit(tbl->used_slots, tbl->max_slots);
-               if (slotid < tbl->max_slots)
-                       tbl->highest_used_slotid = slotid;
-               else
-                       tbl->highest_used_slotid = NFS4_NO_SLOT;
-       }
-       dprintk("%s: slotid %u highest_used_slotid %d\n", __func__,
-               slotid, tbl->highest_used_slotid);
-}
-
-bool nfs4_set_task_privileged(struct rpc_task *task, void *dummy)
-{
-       rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
-       return true;
-}
-
-/*
- * Signal state manager thread if session fore channel is drained
- */
-static void nfs4_check_drain_fc_complete(struct nfs4_session *ses)
-{
-       if (!test_bit(NFS4_SESSION_DRAINING, &ses->session_state)) {
-               rpc_wake_up_first(&ses->fc_slot_table.slot_tbl_waitq,
-                               nfs4_set_task_privileged, NULL);
-               return;
-       }
-
-       if (ses->fc_slot_table.highest_used_slotid != NFS4_NO_SLOT)
-               return;
-
-       dprintk("%s COMPLETE: Session Fore Channel Drained\n", __func__);
-       complete(&ses->fc_slot_table.complete);
-}
-
-/*
- * Signal state manager thread if session back channel is drained
- */
-void nfs4_check_drain_bc_complete(struct nfs4_session *ses)
-{
-       if (!test_bit(NFS4_SESSION_DRAINING, &ses->session_state) ||
-           ses->bc_slot_table.highest_used_slotid != NFS4_NO_SLOT)
-               return;
-       dprintk("%s COMPLETE: Session Back Channel Drained\n", __func__);
-       complete(&ses->bc_slot_table.complete);
-}
-
 static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
 {
+       struct nfs4_session *session;
        struct nfs4_slot_table *tbl;
+       bool send_new_highest_used_slotid = false;
 
-       tbl = &res->sr_session->fc_slot_table;
        if (!res->sr_slot) {
                /* just wake up the next guy waiting since
                 * we may have not consumed a slot after all */
                dprintk("%s: No slot\n", __func__);
                return;
        }
+       tbl = res->sr_slot->table;
+       session = tbl->session;
 
        spin_lock(&tbl->slot_tbl_lock);
-       nfs4_free_slot(tbl, res->sr_slot - tbl->slots);
-       nfs4_check_drain_fc_complete(res->sr_session);
+       /* Be nice to the server: try to ensure that the last transmitted
+        * value for highest_user_slotid <= target_highest_slotid
+        */
+       if (tbl->highest_used_slotid > tbl->target_highest_slotid)
+               send_new_highest_used_slotid = true;
+
+       if (nfs41_wake_and_assign_slot(tbl, res->sr_slot)) {
+               send_new_highest_used_slotid = false;
+               goto out_unlock;
+       }
+       nfs4_free_slot(tbl, res->sr_slot);
+
+       if (tbl->highest_used_slotid != NFS4_NO_SLOT)
+               send_new_highest_used_slotid = false;
+out_unlock:
        spin_unlock(&tbl->slot_tbl_lock);
        res->sr_slot = NULL;
+       if (send_new_highest_used_slotid)
+               nfs41_server_notify_highest_slotid_update(session->clp);
 }
 
 static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
 {
-       unsigned long timestamp;
+       struct nfs4_session *session;
+       struct nfs4_slot *slot;
        struct nfs_client *clp;
-
-       /*
-        * sr_status remains 1 if an RPC level error occurred. The server
-        * may or may not have processed the sequence operation..
-        * Proceed as if the server received and processed the sequence
-        * operation.
-        */
-       if (res->sr_status == 1)
-               res->sr_status = NFS_OK;
+       bool interrupted = false;
+       int ret = 1;
 
        /* don't increment the sequence number if the task wasn't sent */
        if (!RPC_WAS_SENT(task))
                goto out;
 
+       slot = res->sr_slot;
+       session = slot->table->session;
+
+       if (slot->interrupted) {
+               slot->interrupted = 0;
+               interrupted = true;
+       }
+
        /* Check the SEQUENCE operation status */
        switch (res->sr_status) {
        case 0:
                /* Update the slot's sequence and clientid lease timer */
-               ++res->sr_slot->seq_nr;
-               timestamp = res->sr_renewal_time;
-               clp = res->sr_session->clp;
-               do_renew_lease(clp, timestamp);
+               ++slot->seq_nr;
+               clp = session->clp;
+               do_renew_lease(clp, res->sr_timestamp);
                /* Check sequence flags */
                if (res->sr_status_flags != 0)
                        nfs4_schedule_lease_recovery(clp);
+               nfs41_update_target_slotid(slot->table, slot, res);
                break;
+       case 1:
+               /*
+                * sr_status remains 1 if an RPC level error occurred.
+                * The server may or may not have processed the sequence
+                * operation..
+                * Mark the slot as having hosted an interrupted RPC call.
+                */
+               slot->interrupted = 1;
+               goto out;
        case -NFS4ERR_DELAY:
                /* The server detected a resend of the RPC call and
                 * returned NFS4ERR_DELAY as per Section 2.10.6.2
                 * of RFC5661.
                 */
-               dprintk("%s: slot=%td seq=%d: Operation in progress\n",
+               dprintk("%s: slot=%u seq=%u: Operation in progress\n",
                        __func__,
-                       res->sr_slot - res->sr_session->fc_slot_table.slots,
-                       res->sr_slot->seq_nr);
+                       slot->slot_nr,
+                       slot->seq_nr);
                goto out_retry;
+       case -NFS4ERR_BADSLOT:
+               /*
+                * The slot id we used was probably retired. Try again
+                * using a different slot id.
+                */
+               goto retry_nowait;
+       case -NFS4ERR_SEQ_MISORDERED:
+               /*
+                * Was the last operation on this sequence interrupted?
+                * If so, retry after bumping the sequence number.
+                */
+               if (interrupted) {
+                       ++slot->seq_nr;
+                       goto retry_nowait;
+               }
+               /*
+                * Could this slot have been previously retired?
+                * If so, then the server may be expecting seq_nr = 1!
+                */
+               if (slot->seq_nr != 1) {
+                       slot->seq_nr = 1;
+                       goto retry_nowait;
+               }
+               break;
+       case -NFS4ERR_SEQ_FALSE_RETRY:
+               ++slot->seq_nr;
+               goto retry_nowait;
        default:
                /* Just update the slot sequence no. */
-               ++res->sr_slot->seq_nr;
+               ++slot->seq_nr;
        }
 out:
        /* The session may be reset by one of the error handlers. */
        dprintk("%s: Error %d free the slot \n", __func__, res->sr_status);
        nfs41_sequence_free_slot(res);
-       return 1;
+       return ret;
+retry_nowait:
+       if (rpc_restart_call_prepare(task)) {
+               task->tk_status = 0;
+               ret = 0;
+       }
+       goto out;
 out_retry:
        if (!rpc_restart_call(task))
                goto out;
@@ -545,55 +518,27 @@ out_retry:
 static int nfs4_sequence_done(struct rpc_task *task,
                               struct nfs4_sequence_res *res)
 {
-       if (res->sr_session == NULL)
+       if (res->sr_slot == NULL)
                return 1;
        return nfs41_sequence_done(task, res);
 }
 
-/*
- * nfs4_find_slot - efficiently look for a free slot
- *
- * nfs4_find_slot looks for an unset bit in the used_slots bitmap.
- * If found, we mark the slot as used, update the highest_used_slotid,
- * and respectively set up the sequence operation args.
- * The slot number is returned if found, or NFS4_NO_SLOT otherwise.
- *
- * Note: must be called with under the slot_tbl_lock.
- */
-static u32
-nfs4_find_slot(struct nfs4_slot_table *tbl)
-{
-       u32 slotid;
-       u32 ret_id = NFS4_NO_SLOT;
-
-       dprintk("--> %s used_slots=%04lx highest_used=%u max_slots=%u\n",
-               __func__, tbl->used_slots[0], tbl->highest_used_slotid,
-               tbl->max_slots);
-       slotid = find_first_zero_bit(tbl->used_slots, tbl->max_slots);
-       if (slotid >= tbl->max_slots)
-               goto out;
-       __set_bit(slotid, tbl->used_slots);
-       if (slotid > tbl->highest_used_slotid ||
-                       tbl->highest_used_slotid == NFS4_NO_SLOT)
-               tbl->highest_used_slotid = slotid;
-       ret_id = slotid;
-out:
-       dprintk("<-- %s used_slots=%04lx highest_used=%d slotid=%d \n",
-               __func__, tbl->used_slots[0], tbl->highest_used_slotid, ret_id);
-       return ret_id;
-}
-
 static void nfs41_init_sequence(struct nfs4_sequence_args *args,
                struct nfs4_sequence_res *res, int cache_reply)
 {
-       args->sa_session = NULL;
+       args->sa_slot = NULL;
        args->sa_cache_this = 0;
+       args->sa_privileged = 0;
        if (cache_reply)
                args->sa_cache_this = 1;
-       res->sr_session = NULL;
        res->sr_slot = NULL;
 }
 
+static void nfs4_set_sequence_privileged(struct nfs4_sequence_args *args)
+{
+       args->sa_privileged = 1;
+}
+
 int nfs41_setup_sequence(struct nfs4_session *session,
                                struct nfs4_sequence_args *args,
                                struct nfs4_sequence_res *res,
@@ -601,59 +546,59 @@ int nfs41_setup_sequence(struct nfs4_session *session,
 {
        struct nfs4_slot *slot;
        struct nfs4_slot_table *tbl;
-       u32 slotid;
 
        dprintk("--> %s\n", __func__);
        /* slot already allocated? */
        if (res->sr_slot != NULL)
-               return 0;
+               goto out_success;
 
        tbl = &session->fc_slot_table;
 
+       task->tk_timeout = 0;
+
        spin_lock(&tbl->slot_tbl_lock);
        if (test_bit(NFS4_SESSION_DRAINING, &session->session_state) &&
-           !rpc_task_has_priority(task, RPC_PRIORITY_PRIVILEGED)) {
+           !args->sa_privileged) {
                /* The state manager will wait until the slot table is empty */
-               rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL);
-               spin_unlock(&tbl->slot_tbl_lock);
                dprintk("%s session is draining\n", __func__);
-               return -EAGAIN;
+               goto out_sleep;
        }
 
-       if (!rpc_queue_empty(&tbl->slot_tbl_waitq) &&
-           !rpc_task_has_priority(task, RPC_PRIORITY_PRIVILEGED)) {
-               rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL);
-               spin_unlock(&tbl->slot_tbl_lock);
-               dprintk("%s enforce FIFO order\n", __func__);
-               return -EAGAIN;
-       }
-
-       slotid = nfs4_find_slot(tbl);
-       if (slotid == NFS4_NO_SLOT) {
-               rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL);
-               spin_unlock(&tbl->slot_tbl_lock);
+       slot = nfs4_alloc_slot(tbl);
+       if (IS_ERR(slot)) {
+               /* If out of memory, try again in 1/4 second */
+               if (slot == ERR_PTR(-ENOMEM))
+                       task->tk_timeout = HZ >> 2;
                dprintk("<-- %s: no free slots\n", __func__);
-               return -EAGAIN;
+               goto out_sleep;
        }
        spin_unlock(&tbl->slot_tbl_lock);
 
-       rpc_task_set_priority(task, RPC_PRIORITY_NORMAL);
-       slot = tbl->slots + slotid;
-       args->sa_session = session;
-       args->sa_slotid = slotid;
+       args->sa_slot = slot;
 
-       dprintk("<-- %s slotid=%d seqid=%d\n", __func__, slotid, slot->seq_nr);
+       dprintk("<-- %s slotid=%d seqid=%d\n", __func__,
+                       slot->slot_nr, slot->seq_nr);
 
-       res->sr_session = session;
        res->sr_slot = slot;
-       res->sr_renewal_time = jiffies;
+       res->sr_timestamp = jiffies;
        res->sr_status_flags = 0;
        /*
         * sr_status is only set in decode_sequence, and so will remain
         * set to 1 if an rpc level failure occurs.
         */
        res->sr_status = 1;
+out_success:
+       rpc_call_start(task);
        return 0;
+out_sleep:
+       /* Privileged tasks are queued with top priority */
+       if (args->sa_privileged)
+               rpc_sleep_on_priority(&tbl->slot_tbl_waitq, task,
+                               NULL, RPC_PRIORITY_PRIVILEGED);
+       else
+               rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL);
+       spin_unlock(&tbl->slot_tbl_lock);
+       return -EAGAIN;
 }
 EXPORT_SYMBOL_GPL(nfs41_setup_sequence);
 
@@ -665,12 +610,14 @@ int nfs4_setup_sequence(const struct nfs_server *server,
        struct nfs4_session *session = nfs4_get_session(server);
        int ret = 0;
 
-       if (session == NULL)
+       if (session == NULL) {
+               rpc_call_start(task);
                goto out;
+       }
 
-       dprintk("--> %s clp %p session %p sr_slot %td\n",
+       dprintk("--> %s clp %p session %p sr_slot %d\n",
                __func__, session->clp, session, res->sr_slot ?
-                       res->sr_slot - session->fc_slot_table.slots : -1);
+                       res->sr_slot->slot_nr : -1);
 
        ret = nfs41_setup_sequence(session, args, res, task);
 out:
@@ -687,19 +634,11 @@ struct nfs41_call_sync_data {
 static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata)
 {
        struct nfs41_call_sync_data *data = calldata;
+       struct nfs4_session *session = nfs4_get_session(data->seq_server);
 
        dprintk("--> %s data->seq_server %p\n", __func__, data->seq_server);
 
-       if (nfs4_setup_sequence(data->seq_server, data->seq_args,
-                               data->seq_res, task))
-               return;
-       rpc_call_start(task);
-}
-
-static void nfs41_call_priv_sync_prepare(struct rpc_task *task, void *calldata)
-{
-       rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
-       nfs41_call_sync_prepare(task, calldata);
+       nfs41_setup_sequence(session, data->seq_args, data->seq_res, task);
 }
 
 static void nfs41_call_sync_done(struct rpc_task *task, void *calldata)
@@ -714,17 +653,11 @@ static const struct rpc_call_ops nfs41_call_sync_ops = {
        .rpc_call_done = nfs41_call_sync_done,
 };
 
-static const struct rpc_call_ops nfs41_call_priv_sync_ops = {
-       .rpc_call_prepare = nfs41_call_priv_sync_prepare,
-       .rpc_call_done = nfs41_call_sync_done,
-};
-
 static int nfs4_call_sync_sequence(struct rpc_clnt *clnt,
                                   struct nfs_server *server,
                                   struct rpc_message *msg,
                                   struct nfs4_sequence_args *args,
-                                  struct nfs4_sequence_res *res,
-                                  int privileged)
+                                  struct nfs4_sequence_res *res)
 {
        int ret;
        struct rpc_task *task;
@@ -740,8 +673,6 @@ static int nfs4_call_sync_sequence(struct rpc_clnt *clnt,
                .callback_data = &data
        };
 
-       if (privileged)
-               task_setup.callback_ops = &nfs41_call_priv_sync_ops;
        task = rpc_run_task(&task_setup);
        if (IS_ERR(task))
                ret = PTR_ERR(task);
@@ -752,24 +683,18 @@ static int nfs4_call_sync_sequence(struct rpc_clnt *clnt,
        return ret;
 }
 
-int _nfs4_call_sync_session(struct rpc_clnt *clnt,
-                           struct nfs_server *server,
-                           struct rpc_message *msg,
-                           struct nfs4_sequence_args *args,
-                           struct nfs4_sequence_res *res,
-                           int cache_reply)
-{
-       nfs41_init_sequence(args, res, cache_reply);
-       return nfs4_call_sync_sequence(clnt, server, msg, args, res, 0);
-}
-
 #else
-static inline
+static
 void nfs41_init_sequence(struct nfs4_sequence_args *args,
                struct nfs4_sequence_res *res, int cache_reply)
 {
 }
 
+static void nfs4_set_sequence_privileged(struct nfs4_sequence_args *args)
+{
+}
+
+
 static int nfs4_sequence_done(struct rpc_task *task,
                               struct nfs4_sequence_res *res)
 {
@@ -777,18 +702,17 @@ static int nfs4_sequence_done(struct rpc_task *task,
 }
 #endif /* CONFIG_NFS_V4_1 */
 
+static
 int _nfs4_call_sync(struct rpc_clnt *clnt,
                    struct nfs_server *server,
                    struct rpc_message *msg,
                    struct nfs4_sequence_args *args,
-                   struct nfs4_sequence_res *res,
-                   int cache_reply)
+                   struct nfs4_sequence_res *res)
 {
-       nfs41_init_sequence(args, res, cache_reply);
        return rpc_call_sync(clnt, msg, 0);
 }
 
-static inline
+static
 int nfs4_call_sync(struct rpc_clnt *clnt,
                   struct nfs_server *server,
                   struct rpc_message *msg,
@@ -796,8 +720,9 @@ int nfs4_call_sync(struct rpc_clnt *clnt,
                   struct nfs4_sequence_res *res,
                   int cache_reply)
 {
+       nfs41_init_sequence(args, res, cache_reply);
        return server->nfs_client->cl_mvops->call_sync(clnt, server, msg,
-                                               args, res, cache_reply);
+                                               args, res);
 }
 
 static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo)
@@ -1445,13 +1370,6 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state
                                nfs_inode_find_state_and_recover(state->inode,
                                                stateid);
                                nfs4_schedule_stateid_recovery(server, state);
-                       case -EKEYEXPIRED:
-                               /*
-                                * User RPCSEC_GSS context has expired.
-                                * We cannot recover this stateid now, so
-                                * skip it and allow recovery thread to
-                                * proceed.
-                                */
                        case -ENOMEM:
                                err = 0;
                                goto out;
@@ -1574,20 +1492,12 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
                                &data->o_res.seq_res,
                                task) != 0)
                nfs_release_seqid(data->o_arg.seqid);
-       else
-               rpc_call_start(task);
        return;
 unlock_no_action:
        rcu_read_unlock();
 out_no_action:
        task->tk_action = NULL;
-
-}
-
-static void nfs4_recover_open_prepare(struct rpc_task *task, void *calldata)
-{
-       rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
-       nfs4_open_prepare(task, calldata);
+       nfs4_sequence_done(task, &data->o_res.seq_res);
 }
 
 static void nfs4_open_done(struct rpc_task *task, void *calldata)
@@ -1648,12 +1558,6 @@ static const struct rpc_call_ops nfs4_open_ops = {
        .rpc_release = nfs4_open_release,
 };
 
-static const struct rpc_call_ops nfs4_recover_open_ops = {
-       .rpc_call_prepare = nfs4_recover_open_prepare,
-       .rpc_call_done = nfs4_open_done,
-       .rpc_release = nfs4_open_release,
-};
-
 static int nfs4_run_open_task(struct nfs4_opendata *data, int isrecover)
 {
        struct inode *dir = data->dir->d_inode;
@@ -1683,7 +1587,7 @@ static int nfs4_run_open_task(struct nfs4_opendata *data, int isrecover)
        data->rpc_status = 0;
        data->cancelled = 0;
        if (isrecover)
-               task_setup_data.callback_ops = &nfs4_recover_open_ops;
+               nfs4_set_sequence_privileged(&o_arg->seq_args);
        task = rpc_run_task(&task_setup_data);
         if (IS_ERR(task))
                 return PTR_ERR(task);
@@ -1789,24 +1693,6 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
        return 0;
 }
 
-static int nfs4_client_recover_expired_lease(struct nfs_client *clp)
-{
-       unsigned int loop;
-       int ret;
-
-       for (loop = NFS4_MAX_LOOP_ON_RECOVER; loop != 0; loop--) {
-               ret = nfs4_wait_clnt_recover(clp);
-               if (ret != 0)
-                       break;
-               if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) &&
-                   !test_bit(NFS4CLNT_CHECK_LEASE,&clp->cl_state))
-                       break;
-               nfs4_schedule_state_manager(clp);
-               ret = -EIO;
-       }
-       return ret;
-}
-
 static int nfs4_recover_expired_lease(struct nfs_server *server)
 {
        return nfs4_client_recover_expired_lease(server->nfs_client);
@@ -2282,6 +2168,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
        if (!call_close) {
                /* Note: exit _without_ calling nfs4_close_done */
                task->tk_action = NULL;
+               nfs4_sequence_done(task, &calldata->res.seq_res);
                goto out;
        }
 
@@ -2299,8 +2186,6 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
                                &calldata->res.seq_res,
                                task) != 0)
                nfs_release_seqid(calldata->arg.seqid);
-       else
-               rpc_call_start(task);
 out:
        dprintk("%s: done!\n", __func__);
 }
@@ -2533,7 +2418,8 @@ static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
        rpc_authflavor_t flav_array[NFS_MAX_SECFLAVORS];
 
        len = rpcauth_list_flavors(flav_array, ARRAY_SIZE(flav_array));
-       BUG_ON(len < 0);
+       if (len < 0)
+               return len;
 
        for (i = 0; i < len; i++) {
                /* AUTH_UNIX is the default flavor if none was specified,
@@ -3038,12 +2924,10 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
 
 static void nfs4_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlinkdata *data)
 {
-       if (nfs4_setup_sequence(NFS_SERVER(data->dir),
-                               &data->args.seq_args,
-                               &data->res.seq_res,
-                               task))
-               return;
-       rpc_call_start(task);
+       nfs4_setup_sequence(NFS_SERVER(data->dir),
+                       &data->args.seq_args,
+                       &data->res.seq_res,
+                       task);
 }
 
 static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir)
@@ -3071,12 +2955,10 @@ static void nfs4_proc_rename_setup(struct rpc_message *msg, struct inode *dir)
 
 static void nfs4_proc_rename_rpc_prepare(struct rpc_task *task, struct nfs_renamedata *data)
 {
-       if (nfs4_setup_sequence(NFS_SERVER(data->old_dir),
-                               &data->args.seq_args,
-                               &data->res.seq_res,
-                               task))
-               return;
-       rpc_call_start(task);
+       nfs4_setup_sequence(NFS_SERVER(data->old_dir),
+                       &data->args.seq_args,
+                       &data->res.seq_res,
+                       task);
 }
 
 static int nfs4_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
@@ -3362,9 +3244,6 @@ static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
        int mode = sattr->ia_mode;
        int status = -ENOMEM;
 
-       BUG_ON(!(sattr->ia_valid & ATTR_MODE));
-       BUG_ON(!S_ISFIFO(mode) && !S_ISBLK(mode) && !S_ISCHR(mode) && !S_ISSOCK(mode));
-
        data = nfs4_alloc_createdata(dir, &dentry->d_name, sattr, NF4SOCK);
        if (data == NULL)
                goto out;
@@ -3380,10 +3259,13 @@ static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
                data->arg.ftype = NF4CHR;
                data->arg.u.device.specdata1 = MAJOR(rdev);
                data->arg.u.device.specdata2 = MINOR(rdev);
+       } else if (!S_ISSOCK(mode)) {
+               status = -EINVAL;
+               goto out_free;
        }
        
        status = nfs4_do_create(dir, dentry, data);
-
+out_free:
        nfs4_free_createdata(data);
 out:
        return status;
@@ -3565,12 +3447,10 @@ static void nfs4_proc_read_setup(struct nfs_read_data *data, struct rpc_message
 
 static void nfs4_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_data *data)
 {
-       if (nfs4_setup_sequence(NFS_SERVER(data->header->inode),
-                               &data->args.seq_args,
-                               &data->res.seq_res,
-                               task))
-               return;
-       rpc_call_start(task);
+       nfs4_setup_sequence(NFS_SERVER(data->header->inode),
+                       &data->args.seq_args,
+                       &data->res.seq_res,
+                       task);
 }
 
 static int nfs4_write_done_cb(struct rpc_task *task, struct nfs_write_data *data)
@@ -3631,22 +3511,18 @@ static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_messag
 
 static void nfs4_proc_write_rpc_prepare(struct rpc_task *task, struct nfs_write_data *data)
 {
-       if (nfs4_setup_sequence(NFS_SERVER(data->header->inode),
-                               &data->args.seq_args,
-                               &data->res.seq_res,
-                               task))
-               return;
-       rpc_call_start(task);
+       nfs4_setup_sequence(NFS_SERVER(data->header->inode),
+                       &data->args.seq_args,
+                       &data->res.seq_res,
+                       task);
 }
 
 static void nfs4_proc_commit_rpc_prepare(struct rpc_task *task, struct nfs_commit_data *data)
 {
-       if (nfs4_setup_sequence(NFS_SERVER(data->inode),
-                               &data->args.seq_args,
-                               &data->res.seq_res,
-                               task))
-               return;
-       rpc_call_start(task);
+       nfs4_setup_sequence(NFS_SERVER(data->inode),
+                       &data->args.seq_args,
+                       &data->res.seq_res,
+                       task);
 }
 
 static int nfs4_commit_done_cb(struct rpc_task *task, struct nfs_commit_data *data)
@@ -3937,8 +3813,13 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
                goto out_free;
        }
        nfs4_write_cached_acl(inode, pages, res.acl_data_offset, res.acl_len);
-       if (buf)
+       if (buf) {
+               if (res.acl_len > buflen) {
+                       ret = -ERANGE;
+                       goto out_free;
+               }
                _copy_from_pages(buf, pages, res.acl_data_offset, res.acl_len);
+       }
 out_ok:
        ret = res.acl_len;
 out_free:
@@ -4085,7 +3966,6 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
                case -NFS4ERR_DELAY:
                        nfs_inc_server_stats(server, NFSIOS_DELAY);
                case -NFS4ERR_GRACE:
-               case -EKEYEXPIRED:
                        rpc_delay(task, NFS4_POLL_RETRY_MAX);
                        task->tk_status = 0;
                        return -EAGAIN;
@@ -4293,11 +4173,10 @@ static void nfs4_delegreturn_prepare(struct rpc_task *task, void *data)
 
        d_data = (struct nfs4_delegreturndata *)data;
 
-       if (nfs4_setup_sequence(d_data->res.server,
-                               &d_data->args.seq_args,
-                               &d_data->res.seq_res, task))
-               return;
-       rpc_call_start(task);
+       nfs4_setup_sequence(d_data->res.server,
+                       &d_data->args.seq_args,
+                       &d_data->res.seq_res,
+                       task);
 }
 #endif /* CONFIG_NFS_V4_1 */
 
@@ -4543,6 +4422,7 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data)
        if (test_bit(NFS_LOCK_INITIALIZED, &calldata->lsp->ls_flags) == 0) {
                /* Note: exit _without_ running nfs4_locku_done */
                task->tk_action = NULL;
+               nfs4_sequence_done(task, &calldata->res.seq_res);
                return;
        }
        calldata->timestamp = jiffies;
@@ -4551,8 +4431,6 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data)
                                &calldata->res.seq_res,
                                task) != 0)
                nfs_release_seqid(calldata->arg.seqid);
-       else
-               rpc_call_start(task);
 }
 
 static const struct rpc_call_ops nfs4_locku_ops = {
@@ -4696,8 +4574,9 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
                return;
        /* Do we need to do an open_to_lock_owner? */
        if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)) {
-               if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0)
+               if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0) {
                        goto out_release_lock_seqid;
+               }
                data->arg.open_stateid = &state->stateid;
                data->arg.new_lock_owner = 1;
                data->res.open_seqid = data->arg.open_seqid;
@@ -4707,20 +4586,12 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
        if (nfs4_setup_sequence(data->server,
                                &data->arg.seq_args,
                                &data->res.seq_res,
-                               task) == 0) {
-               rpc_call_start(task);
+                               task) == 0)
                return;
-       }
        nfs_release_seqid(data->arg.open_seqid);
 out_release_lock_seqid:
        nfs_release_seqid(data->arg.lock_seqid);
-       dprintk("%s: done!, ret = %d\n", __func__, task->tk_status);
-}
-
-static void nfs4_recover_lock_prepare(struct rpc_task *task, void *calldata)
-{
-       rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
-       nfs4_lock_prepare(task, calldata);
+       dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status);
 }
 
 static void nfs4_lock_done(struct rpc_task *task, void *calldata)
@@ -4775,12 +4646,6 @@ static const struct rpc_call_ops nfs4_lock_ops = {
        .rpc_release = nfs4_lock_release,
 };
 
-static const struct rpc_call_ops nfs4_recover_lock_ops = {
-       .rpc_call_prepare = nfs4_recover_lock_prepare,
-       .rpc_call_done = nfs4_lock_done,
-       .rpc_release = nfs4_lock_release,
-};
-
 static void nfs4_handle_setlk_error(struct nfs_server *server, struct nfs4_lock_state *lsp, int new_lock_owner, int error)
 {
        switch (error) {
@@ -4823,15 +4688,15 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f
                return -ENOMEM;
        if (IS_SETLKW(cmd))
                data->arg.block = 1;
-       if (recovery_type > NFS_LOCK_NEW) {
-               if (recovery_type == NFS_LOCK_RECLAIM)
-                       data->arg.reclaim = NFS_LOCK_RECLAIM;
-               task_setup_data.callback_ops = &nfs4_recover_lock_ops;
-       }
        nfs41_init_sequence(&data->arg.seq_args, &data->res.seq_res, 1);
        msg.rpc_argp = &data->arg;
        msg.rpc_resp = &data->res;
        task_setup_data.callback_data = data;
+       if (recovery_type > NFS_LOCK_NEW) {
+               if (recovery_type == NFS_LOCK_RECLAIM)
+                       data->arg.reclaim = NFS_LOCK_RECLAIM;
+               nfs4_set_sequence_privileged(&data->arg.seq_args);
+       }
        task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task))
                return PTR_ERR(task);
@@ -5100,15 +4965,6 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl)
                                nfs4_schedule_stateid_recovery(server, state);
                                err = 0;
                                goto out;
-                       case -EKEYEXPIRED:
-                               /*
-                                * User RPCSEC_GSS context has expired.
-                                * We cannot recover this stateid now, so
-                                * skip it and allow recovery thread to
-                                * proceed.
-                                */
-                               err = 0;
-                               goto out;
                        case -ENOMEM:
                        case -NFS4ERR_DENIED:
                                /* kill_proc(fl->fl_pid, SIGLOST, 1); */
@@ -5357,7 +5213,6 @@ int nfs4_proc_bind_conn_to_session(struct nfs_client *clp, struct rpc_cred *cred
        };
 
        dprintk("--> %s\n", __func__);
-       BUG_ON(clp == NULL);
 
        res.session = kzalloc(sizeof(struct nfs4_session), GFP_NOFS);
        if (unlikely(res.session == NULL)) {
@@ -5569,20 +5424,16 @@ struct nfs4_get_lease_time_data {
 static void nfs4_get_lease_time_prepare(struct rpc_task *task,
                                        void *calldata)
 {
-       int ret;
        struct nfs4_get_lease_time_data *data =
                        (struct nfs4_get_lease_time_data *)calldata;
 
        dprintk("--> %s\n", __func__);
-       rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
        /* just setup sequence, do not trigger session recovery
           since we're invoked within one */
-       ret = nfs41_setup_sequence(data->clp->cl_session,
-                                  &data->args->la_seq_args,
-                                  &data->res->lr_seq_res, task);
-
-       BUG_ON(ret == -EAGAIN);
-       rpc_call_start(task);
+       nfs41_setup_sequence(data->clp->cl_session,
+                       &data->args->la_seq_args,
+                       &data->res->lr_seq_res,
+                       task);
        dprintk("<-- %s\n", __func__);
 }
 
@@ -5644,6 +5495,7 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo)
        int status;
 
        nfs41_init_sequence(&args.la_seq_args, &res.lr_seq_res, 0);
+       nfs4_set_sequence_privileged(&args.la_seq_args);
        dprintk("--> %s\n", __func__);
        task = rpc_run_task(&task_setup);
 
@@ -5658,145 +5510,6 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo)
        return status;
 }
 
-static struct nfs4_slot *nfs4_alloc_slots(u32 max_slots, gfp_t gfp_flags)
-{
-       return kcalloc(max_slots, sizeof(struct nfs4_slot), gfp_flags);
-}
-
-static void nfs4_add_and_init_slots(struct nfs4_slot_table *tbl,
-               struct nfs4_slot *new,
-               u32 max_slots,
-               u32 ivalue)
-{
-       struct nfs4_slot *old = NULL;
-       u32 i;
-
-       spin_lock(&tbl->slot_tbl_lock);
-       if (new) {
-               old = tbl->slots;
-               tbl->slots = new;
-               tbl->max_slots = max_slots;
-       }
-       tbl->highest_used_slotid = NFS4_NO_SLOT;
-       for (i = 0; i < tbl->max_slots; i++)
-               tbl->slots[i].seq_nr = ivalue;
-       spin_unlock(&tbl->slot_tbl_lock);
-       kfree(old);
-}
-
-/*
- * (re)Initialise a slot table
- */
-static int nfs4_realloc_slot_table(struct nfs4_slot_table *tbl, u32 max_reqs,
-                                u32 ivalue)
-{
-       struct nfs4_slot *new = NULL;
-       int ret = -ENOMEM;
-
-       dprintk("--> %s: max_reqs=%u, tbl->max_slots %d\n", __func__,
-               max_reqs, tbl->max_slots);
-
-       /* Does the newly negotiated max_reqs match the existing slot table? */
-       if (max_reqs != tbl->max_slots) {
-               new = nfs4_alloc_slots(max_reqs, GFP_NOFS);
-               if (!new)
-                       goto out;
-       }
-       ret = 0;
-
-       nfs4_add_and_init_slots(tbl, new, max_reqs, ivalue);
-       dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__,
-               tbl, tbl->slots, tbl->max_slots);
-out:
-       dprintk("<-- %s: return %d\n", __func__, ret);
-       return ret;
-}
-
-/* Destroy the slot table */
-static void nfs4_destroy_slot_tables(struct nfs4_session *session)
-{
-       if (session->fc_slot_table.slots != NULL) {
-               kfree(session->fc_slot_table.slots);
-               session->fc_slot_table.slots = NULL;
-       }
-       if (session->bc_slot_table.slots != NULL) {
-               kfree(session->bc_slot_table.slots);
-               session->bc_slot_table.slots = NULL;
-       }
-       return;
-}
-
-/*
- * Initialize or reset the forechannel and backchannel tables
- */
-static int nfs4_setup_session_slot_tables(struct nfs4_session *ses)
-{
-       struct nfs4_slot_table *tbl;
-       int status;
-
-       dprintk("--> %s\n", __func__);
-       /* Fore channel */
-       tbl = &ses->fc_slot_table;
-       status = nfs4_realloc_slot_table(tbl, ses->fc_attrs.max_reqs, 1);
-       if (status) /* -ENOMEM */
-               return status;
-       /* Back channel */
-       tbl = &ses->bc_slot_table;
-       status = nfs4_realloc_slot_table(tbl, ses->bc_attrs.max_reqs, 0);
-       if (status && tbl->slots == NULL)
-               /* Fore and back channel share a connection so get
-                * both slot tables or neither */
-               nfs4_destroy_slot_tables(ses);
-       return status;
-}
-
-struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp)
-{
-       struct nfs4_session *session;
-       struct nfs4_slot_table *tbl;
-
-       session = kzalloc(sizeof(struct nfs4_session), GFP_NOFS);
-       if (!session)
-               return NULL;
-
-       tbl = &session->fc_slot_table;
-       tbl->highest_used_slotid = NFS4_NO_SLOT;
-       spin_lock_init(&tbl->slot_tbl_lock);
-       rpc_init_priority_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table");
-       init_completion(&tbl->complete);
-
-       tbl = &session->bc_slot_table;
-       tbl->highest_used_slotid = NFS4_NO_SLOT;
-       spin_lock_init(&tbl->slot_tbl_lock);
-       rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table");
-       init_completion(&tbl->complete);
-
-       session->session_state = 1<<NFS4_SESSION_INITING;
-
-       session->clp = clp;
-       return session;
-}
-
-void nfs4_destroy_session(struct nfs4_session *session)
-{
-       struct rpc_xprt *xprt;
-       struct rpc_cred *cred;
-
-       cred = nfs4_get_exchange_id_cred(session->clp);
-       nfs4_proc_destroy_session(session, cred);
-       if (cred)
-               put_rpccred(cred);
-
-       rcu_read_lock();
-       xprt = rcu_dereference(session->clp->cl_rpcclient->cl_xprt);
-       rcu_read_unlock();
-       dprintk("%s Destroy backchannel for xprt %p\n",
-               __func__, xprt);
-       xprt_destroy_backchannel(xprt, NFS41_BC_MIN_CALLBACKS);
-       nfs4_destroy_slot_tables(session);
-       kfree(session);
-}
-
 /*
  * Initialize the values to be used by the client in CREATE_SESSION
  * If nfs4_init_session set the fore channel request and response sizes,
@@ -5809,8 +5522,8 @@ void nfs4_destroy_session(struct nfs4_session *session)
 static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args)
 {
        struct nfs4_session *session = args->client->cl_session;
-       unsigned int mxrqst_sz = session->fc_attrs.max_rqst_sz,
-                    mxresp_sz = session->fc_attrs.max_resp_sz;
+       unsigned int mxrqst_sz = session->fc_target_max_rqst_sz,
+                    mxresp_sz = session->fc_target_max_resp_sz;
 
        if (mxrqst_sz == 0)
                mxrqst_sz = NFS_MAX_FILE_IO_SIZE;
@@ -5919,10 +5632,9 @@ static int _nfs4_proc_create_session(struct nfs_client *clp,
 
        status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
 
-       if (!status)
+       if (!status) {
                /* Verify the session's negotiated channel_attrs values */
                status = nfs4_verify_channel_attrs(&args, session);
-       if (!status) {
                /* Increment the clientid slot sequence id */
                clp->cl_seqid++;
        }
@@ -5991,83 +5703,6 @@ int nfs4_proc_destroy_session(struct nfs4_session *session,
        return status;
 }
 
-/*
- * With sessions, the client is not marked ready until after a
- * successful EXCHANGE_ID and CREATE_SESSION.
- *
- * Map errors cl_cons_state errors to EPROTONOSUPPORT to indicate
- * other versions of NFS can be tried.
- */
-static int nfs41_check_session_ready(struct nfs_client *clp)
-{
-       int ret;
-       
-       if (clp->cl_cons_state == NFS_CS_SESSION_INITING) {
-               ret = nfs4_client_recover_expired_lease(clp);
-               if (ret)
-                       return ret;
-       }
-       if (clp->cl_cons_state < NFS_CS_READY)
-               return -EPROTONOSUPPORT;
-       smp_rmb();
-       return 0;
-}
-
-int nfs4_init_session(struct nfs_server *server)
-{
-       struct nfs_client *clp = server->nfs_client;
-       struct nfs4_session *session;
-       unsigned int rsize, wsize;
-
-       if (!nfs4_has_session(clp))
-               return 0;
-
-       session = clp->cl_session;
-       spin_lock(&clp->cl_lock);
-       if (test_and_clear_bit(NFS4_SESSION_INITING, &session->session_state)) {
-
-               rsize = server->rsize;
-               if (rsize == 0)
-                       rsize = NFS_MAX_FILE_IO_SIZE;
-               wsize = server->wsize;
-               if (wsize == 0)
-                       wsize = NFS_MAX_FILE_IO_SIZE;
-
-               session->fc_attrs.max_rqst_sz = wsize + nfs41_maxwrite_overhead;
-               session->fc_attrs.max_resp_sz = rsize + nfs41_maxread_overhead;
-       }
-       spin_unlock(&clp->cl_lock);
-
-       return nfs41_check_session_ready(clp);
-}
-
-int nfs4_init_ds_session(struct nfs_client *clp, unsigned long lease_time)
-{
-       struct nfs4_session *session = clp->cl_session;
-       int ret;
-
-       spin_lock(&clp->cl_lock);
-       if (test_and_clear_bit(NFS4_SESSION_INITING, &session->session_state)) {
-               /*
-                * Do not set NFS_CS_CHECK_LEASE_TIME instead set the
-                * DS lease to be equal to the MDS lease.
-                */
-               clp->cl_lease_time = lease_time;
-               clp->cl_last_renewal = jiffies;
-       }
-       spin_unlock(&clp->cl_lock);
-
-       ret = nfs41_check_session_ready(clp);
-       if (ret)
-               return ret;
-       /* Test for the DS role */
-       if (!is_ds_client(clp))
-               return -ENODEV;
-       return 0;
-}
-EXPORT_SYMBOL_GPL(nfs4_init_ds_session);
-
-
 /*
  * Renew the cl_session lease.
  */
@@ -6133,9 +5768,7 @@ static void nfs41_sequence_prepare(struct rpc_task *task, void *data)
        args = task->tk_msg.rpc_argp;
        res = task->tk_msg.rpc_resp;
 
-       if (nfs41_setup_sequence(clp->cl_session, args, res, task))
-               return;
-       rpc_call_start(task);
+       nfs41_setup_sequence(clp->cl_session, args, res, task);
 }
 
 static const struct rpc_call_ops nfs41_sequence_ops = {
@@ -6144,7 +5777,9 @@ static const struct rpc_call_ops nfs41_sequence_ops = {
        .rpc_release = nfs41_sequence_release,
 };
 
-static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred)
+static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp,
+               struct rpc_cred *cred,
+               bool is_privileged)
 {
        struct nfs4_sequence_data *calldata;
        struct rpc_message msg = {
@@ -6166,6 +5801,8 @@ static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_
                return ERR_PTR(-ENOMEM);
        }
        nfs41_init_sequence(&calldata->args, &calldata->res, 0);
+       if (is_privileged)
+               nfs4_set_sequence_privileged(&calldata->args);
        msg.rpc_argp = &calldata->args;
        msg.rpc_resp = &calldata->res;
        calldata->clp = clp;
@@ -6181,7 +5818,7 @@ static int nfs41_proc_async_sequence(struct nfs_client *clp, struct rpc_cred *cr
 
        if ((renew_flags & NFS4_RENEW_TIMEOUT) == 0)
                return 0;
-       task = _nfs41_proc_sequence(clp, cred);
+       task = _nfs41_proc_sequence(clp, cred, false);
        if (IS_ERR(task))
                ret = PTR_ERR(task);
        else
@@ -6195,7 +5832,7 @@ static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred)
        struct rpc_task *task;
        int ret;
 
-       task = _nfs41_proc_sequence(clp, cred);
+       task = _nfs41_proc_sequence(clp, cred, true);
        if (IS_ERR(task)) {
                ret = PTR_ERR(task);
                goto out;
@@ -6224,13 +5861,10 @@ static void nfs4_reclaim_complete_prepare(struct rpc_task *task, void *data)
 {
        struct nfs4_reclaim_complete_data *calldata = data;
 
-       rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
-       if (nfs41_setup_sequence(calldata->clp->cl_session,
-                               &calldata->arg.seq_args,
-                               &calldata->res.seq_res, task))
-               return;
-
-       rpc_call_start(task);
+       nfs41_setup_sequence(calldata->clp->cl_session,
+                       &calldata->arg.seq_args,
+                       &calldata->res.seq_res,
+                       task);
 }
 
 static int nfs41_reclaim_complete_handle_errors(struct rpc_task *task, struct nfs_client *clp)
@@ -6307,6 +5941,7 @@ static int nfs41_proc_reclaim_complete(struct nfs_client *clp)
        calldata->arg.one_fs = 0;
 
        nfs41_init_sequence(&calldata->arg.seq_args, &calldata->res.seq_res, 0);
+       nfs4_set_sequence_privileged(&calldata->arg.seq_args);
        msg.rpc_argp = &calldata->arg;
        msg.rpc_resp = &calldata->res;
        task_setup_data.callback_data = calldata;
@@ -6330,6 +5965,7 @@ nfs4_layoutget_prepare(struct rpc_task *task, void *calldata)
 {
        struct nfs4_layoutget *lgp = calldata;
        struct nfs_server *server = NFS_SERVER(lgp->args.inode);
+       struct nfs4_session *session = nfs4_get_session(server);
 
        dprintk("--> %s\n", __func__);
        /* Note the is a race here, where a CB_LAYOUTRECALL can come in
@@ -6337,16 +5973,14 @@ nfs4_layoutget_prepare(struct rpc_task *task, void *calldata)
         * However, that is not so catastrophic, and there seems
         * to be no way to prevent it completely.
         */
-       if (nfs4_setup_sequence(server, &lgp->args.seq_args,
+       if (nfs41_setup_sequence(session, &lgp->args.seq_args,
                                &lgp->res.seq_res, task))
                return;
        if (pnfs_choose_layoutget_stateid(&lgp->args.stateid,
                                          NFS_I(lgp->args.inode)->layout,
                                          lgp->args.ctx->state)) {
                rpc_exit(task, NFS4_OK);
-               return;
        }
-       rpc_call_start(task);
 }
 
 static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
@@ -6359,7 +5993,7 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
 
        dprintk("--> %s\n", __func__);
 
-       if (!nfs4_sequence_done(task, &lgp->res.seq_res))
+       if (!nfs41_sequence_done(task, &lgp->res.seq_res))
                goto out;
 
        switch (task->tk_status) {
@@ -6510,10 +6144,10 @@ nfs4_layoutreturn_prepare(struct rpc_task *task, void *calldata)
        struct nfs4_layoutreturn *lrp = calldata;
 
        dprintk("--> %s\n", __func__);
-       if (nfs41_setup_sequence(lrp->clp->cl_session, &lrp->args.seq_args,
-                               &lrp->res.seq_res, task))
-               return;
-       rpc_call_start(task);
+       nfs41_setup_sequence(lrp->clp->cl_session,
+                       &lrp->args.seq_args,
+                       &lrp->res.seq_res,
+                       task);
 }
 
 static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata)
@@ -6523,7 +6157,7 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata)
 
        dprintk("--> %s\n", __func__);
 
-       if (!nfs4_sequence_done(task, &lrp->res.seq_res))
+       if (!nfs41_sequence_done(task, &lrp->res.seq_res))
                return;
 
        server = NFS_SERVER(lrp->args.inode);
@@ -6672,11 +6306,12 @@ static void nfs4_layoutcommit_prepare(struct rpc_task *task, void *calldata)
 {
        struct nfs4_layoutcommit_data *data = calldata;
        struct nfs_server *server = NFS_SERVER(data->args.inode);
+       struct nfs4_session *session = nfs4_get_session(server);
 
-       if (nfs4_setup_sequence(server, &data->args.seq_args,
-                               &data->res.seq_res, task))
-               return;
-       rpc_call_start(task);
+       nfs41_setup_sequence(session,
+                       &data->args.seq_args,
+                       &data->res.seq_res,
+                       task);
 }
 
 static void
@@ -6685,7 +6320,7 @@ nfs4_layoutcommit_done(struct rpc_task *task, void *calldata)
        struct nfs4_layoutcommit_data *data = calldata;
        struct nfs_server *server = NFS_SERVER(data->args.inode);
 
-       if (!nfs4_sequence_done(task, &data->res.seq_res))
+       if (!nfs41_sequence_done(task, &data->res.seq_res))
                return;
 
        switch (task->tk_status) { /* Just ignore these failures */
@@ -6873,7 +6508,9 @@ static int _nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid)
 
        dprintk("NFS call  test_stateid %p\n", stateid);
        nfs41_init_sequence(&args.seq_args, &res.seq_res, 0);
-       status = nfs4_call_sync_sequence(server->client, server, &msg, &args.seq_args, &res.seq_res, 1);
+       nfs4_set_sequence_privileged(&args.seq_args);
+       status = nfs4_call_sync_sequence(server->client, server, &msg,
+                       &args.seq_args, &res.seq_res);
        if (status != NFS_OK) {
                dprintk("NFS reply test_stateid: failed, %d\n", status);
                return status;
@@ -6920,8 +6557,9 @@ static int _nfs4_free_stateid(struct nfs_server *server, nfs4_stateid *stateid)
 
        dprintk("NFS call  free_stateid %p\n", stateid);
        nfs41_init_sequence(&args.seq_args, &res.seq_res, 0);
+       nfs4_set_sequence_privileged(&args.seq_args);
        status = nfs4_call_sync_sequence(server->client, server, &msg,
-                                        &args.seq_args, &res.seq_res, 1);
+                       &args.seq_args, &res.seq_res);
        dprintk("NFS reply free_stateid: %d\n", status);
        return status;
 }
@@ -7041,7 +6679,7 @@ static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = {
 #if defined(CONFIG_NFS_V4_1)
 static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = {
        .minor_version = 1,
-       .call_sync = _nfs4_call_sync_session,
+       .call_sync = nfs4_call_sync_sequence,
        .match_stateid = nfs41_match_stateid,
        .find_root_sec = nfs41_find_root_sec,
        .reboot_recovery_ops = &nfs41_reboot_recovery_ops,
diff --git a/fs/nfs/nfs4session.c b/fs/nfs/nfs4session.c
new file mode 100644 (file)
index 0000000..ebda5f4
--- /dev/null
@@ -0,0 +1,552 @@
+/*
+ * fs/nfs/nfs4session.c
+ *
+ * Copyright (c) 2012 Trond Myklebust <Trond.Myklebust@netapp.com>
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/printk.h>
+#include <linux/slab.h>
+#include <linux/sunrpc/sched.h>
+#include <linux/sunrpc/bc_xprt.h>
+#include <linux/nfs.h>
+#include <linux/nfs4.h>
+#include <linux/nfs_fs.h>
+#include <linux/module.h>
+
+#include "nfs4_fs.h"
+#include "internal.h"
+#include "nfs4session.h"
+#include "callback.h"
+
+#define NFSDBG_FACILITY                NFSDBG_STATE
+
+/*
+ * nfs4_shrink_slot_table - free retired slots from the slot table
+ */
+static void nfs4_shrink_slot_table(struct nfs4_slot_table  *tbl, u32 newsize)
+{
+       struct nfs4_slot **p;
+       if (newsize >= tbl->max_slots)
+               return;
+
+       p = &tbl->slots;
+       while (newsize--)
+               p = &(*p)->next;
+       while (*p) {
+               struct nfs4_slot *slot = *p;
+
+               *p = slot->next;
+               kfree(slot);
+               tbl->max_slots--;
+       }
+}
+
+/*
+ * nfs4_free_slot - free a slot and efficiently update slot table.
+ *
+ * freeing a slot is trivially done by clearing its respective bit
+ * in the bitmap.
+ * If the freed slotid equals highest_used_slotid we want to update it
+ * so that the server would be able to size down the slot table if needed,
+ * otherwise we know that the highest_used_slotid is still in use.
+ * When updating highest_used_slotid there may be "holes" in the bitmap
+ * so we need to scan down from highest_used_slotid to 0 looking for the now
+ * highest slotid in use.
+ * If none found, highest_used_slotid is set to NFS4_NO_SLOT.
+ *
+ * Must be called while holding tbl->slot_tbl_lock
+ */
+void nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot)
+{
+       u32 slotid = slot->slot_nr;
+
+       /* clear used bit in bitmap */
+       __clear_bit(slotid, tbl->used_slots);
+
+       /* update highest_used_slotid when it is freed */
+       if (slotid == tbl->highest_used_slotid) {
+               u32 new_max = find_last_bit(tbl->used_slots, slotid);
+               if (new_max < slotid)
+                       tbl->highest_used_slotid = new_max;
+               else {
+                       tbl->highest_used_slotid = NFS4_NO_SLOT;
+                       nfs4_session_drain_complete(tbl->session, tbl);
+               }
+       }
+       dprintk("%s: slotid %u highest_used_slotid %d\n", __func__,
+               slotid, tbl->highest_used_slotid);
+}
+
+static struct nfs4_slot *nfs4_new_slot(struct nfs4_slot_table  *tbl,
+               u32 slotid, u32 seq_init, gfp_t gfp_mask)
+{
+       struct nfs4_slot *slot;
+
+       slot = kzalloc(sizeof(*slot), gfp_mask);
+       if (slot) {
+               slot->table = tbl;
+               slot->slot_nr = slotid;
+               slot->seq_nr = seq_init;
+       }
+       return slot;
+}
+
+static struct nfs4_slot *nfs4_find_or_create_slot(struct nfs4_slot_table  *tbl,
+               u32 slotid, u32 seq_init, gfp_t gfp_mask)
+{
+       struct nfs4_slot **p, *slot;
+
+       p = &tbl->slots;
+       for (;;) {
+               if (*p == NULL) {
+                       *p = nfs4_new_slot(tbl, tbl->max_slots,
+                                       seq_init, gfp_mask);
+                       if (*p == NULL)
+                               break;
+                       tbl->max_slots++;
+               }
+               slot = *p;
+               if (slot->slot_nr == slotid)
+                       return slot;
+               p = &slot->next;
+       }
+       return ERR_PTR(-ENOMEM);
+}
+
+/*
+ * nfs4_alloc_slot - efficiently look for a free slot
+ *
+ * nfs4_alloc_slot looks for an unset bit in the used_slots bitmap.
+ * If found, we mark the slot as used, update the highest_used_slotid,
+ * and respectively set up the sequence operation args.
+ *
+ * Note: must be called with under the slot_tbl_lock.
+ */
+struct nfs4_slot *nfs4_alloc_slot(struct nfs4_slot_table *tbl)
+{
+       struct nfs4_slot *ret = ERR_PTR(-EBUSY);
+       u32 slotid;
+
+       dprintk("--> %s used_slots=%04lx highest_used=%u max_slots=%u\n",
+               __func__, tbl->used_slots[0], tbl->highest_used_slotid,
+               tbl->max_slotid + 1);
+       slotid = find_first_zero_bit(tbl->used_slots, tbl->max_slotid + 1);
+       if (slotid > tbl->max_slotid)
+               goto out;
+       ret = nfs4_find_or_create_slot(tbl, slotid, 1, GFP_NOWAIT);
+       if (IS_ERR(ret))
+               goto out;
+       __set_bit(slotid, tbl->used_slots);
+       if (slotid > tbl->highest_used_slotid ||
+                       tbl->highest_used_slotid == NFS4_NO_SLOT)
+               tbl->highest_used_slotid = slotid;
+       ret->generation = tbl->generation;
+
+out:
+       dprintk("<-- %s used_slots=%04lx highest_used=%d slotid=%d \n",
+               __func__, tbl->used_slots[0], tbl->highest_used_slotid,
+               !IS_ERR(ret) ? ret->slot_nr : -1);
+       return ret;
+}
+
+static int nfs4_grow_slot_table(struct nfs4_slot_table *tbl,
+                u32 max_reqs, u32 ivalue)
+{
+       if (max_reqs <= tbl->max_slots)
+               return 0;
+       if (!IS_ERR(nfs4_find_or_create_slot(tbl, max_reqs - 1, ivalue, GFP_NOFS)))
+               return 0;
+       return -ENOMEM;
+}
+
+static void nfs4_reset_slot_table(struct nfs4_slot_table *tbl,
+               u32 server_highest_slotid,
+               u32 ivalue)
+{
+       struct nfs4_slot **p;
+
+       nfs4_shrink_slot_table(tbl, server_highest_slotid + 1);
+       p = &tbl->slots;
+       while (*p) {
+               (*p)->seq_nr = ivalue;
+               (*p)->interrupted = 0;
+               p = &(*p)->next;
+       }
+       tbl->highest_used_slotid = NFS4_NO_SLOT;
+       tbl->target_highest_slotid = server_highest_slotid;
+       tbl->server_highest_slotid = server_highest_slotid;
+       tbl->d_target_highest_slotid = 0;
+       tbl->d2_target_highest_slotid = 0;
+       tbl->max_slotid = server_highest_slotid;
+}
+
+/*
+ * (re)Initialise a slot table
+ */
+static int nfs4_realloc_slot_table(struct nfs4_slot_table *tbl,
+               u32 max_reqs, u32 ivalue)
+{
+       int ret;
+
+       dprintk("--> %s: max_reqs=%u, tbl->max_slots %d\n", __func__,
+               max_reqs, tbl->max_slots);
+
+       if (max_reqs > NFS4_MAX_SLOT_TABLE)
+               max_reqs = NFS4_MAX_SLOT_TABLE;
+
+       ret = nfs4_grow_slot_table(tbl, max_reqs, ivalue);
+       if (ret)
+               goto out;
+
+       spin_lock(&tbl->slot_tbl_lock);
+       nfs4_reset_slot_table(tbl, max_reqs - 1, ivalue);
+       spin_unlock(&tbl->slot_tbl_lock);
+
+       dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__,
+               tbl, tbl->slots, tbl->max_slots);
+out:
+       dprintk("<-- %s: return %d\n", __func__, ret);
+       return ret;
+}
+
+/* Destroy the slot table */
+static void nfs4_destroy_slot_tables(struct nfs4_session *session)
+{
+       nfs4_shrink_slot_table(&session->fc_slot_table, 0);
+       nfs4_shrink_slot_table(&session->bc_slot_table, 0);
+}
+
+static bool nfs41_assign_slot(struct rpc_task *task, void *pslot)
+{
+       struct nfs4_sequence_args *args = task->tk_msg.rpc_argp;
+       struct nfs4_sequence_res *res = task->tk_msg.rpc_resp;
+       struct nfs4_slot *slot = pslot;
+       struct nfs4_slot_table *tbl = slot->table;
+
+       if (nfs4_session_draining(tbl->session) && !args->sa_privileged)
+               return false;
+       slot->generation = tbl->generation;
+       args->sa_slot = slot;
+       res->sr_timestamp = jiffies;
+       res->sr_slot = slot;
+       res->sr_status_flags = 0;
+       res->sr_status = 1;
+       return true;
+}
+
+static bool __nfs41_wake_and_assign_slot(struct nfs4_slot_table *tbl,
+               struct nfs4_slot *slot)
+{
+       if (rpc_wake_up_first(&tbl->slot_tbl_waitq, nfs41_assign_slot, slot))
+               return true;
+       return false;
+}
+
+bool nfs41_wake_and_assign_slot(struct nfs4_slot_table *tbl,
+               struct nfs4_slot *slot)
+{
+       if (slot->slot_nr > tbl->max_slotid)
+               return false;
+       return __nfs41_wake_and_assign_slot(tbl, slot);
+}
+
+static bool nfs41_try_wake_next_slot_table_entry(struct nfs4_slot_table *tbl)
+{
+       struct nfs4_slot *slot = nfs4_alloc_slot(tbl);
+       if (!IS_ERR(slot)) {
+               bool ret = __nfs41_wake_and_assign_slot(tbl, slot);
+               if (ret)
+                       return ret;
+               nfs4_free_slot(tbl, slot);
+       }
+       return false;
+}
+
+void nfs41_wake_slot_table(struct nfs4_slot_table *tbl)
+{
+       for (;;) {
+               if (!nfs41_try_wake_next_slot_table_entry(tbl))
+                       break;
+       }
+}
+
+static void nfs41_set_max_slotid_locked(struct nfs4_slot_table *tbl,
+               u32 target_highest_slotid)
+{
+       u32 max_slotid;
+
+       max_slotid = min(NFS4_MAX_SLOT_TABLE - 1, target_highest_slotid);
+       if (max_slotid > tbl->server_highest_slotid)
+               max_slotid = tbl->server_highest_slotid;
+       if (max_slotid > tbl->target_highest_slotid)
+               max_slotid = tbl->target_highest_slotid;
+       tbl->max_slotid = max_slotid;
+       nfs41_wake_slot_table(tbl);
+}
+
+/* Update the client's idea of target_highest_slotid */
+static void nfs41_set_target_slotid_locked(struct nfs4_slot_table *tbl,
+               u32 target_highest_slotid)
+{
+       if (tbl->target_highest_slotid == target_highest_slotid)
+               return;
+       tbl->target_highest_slotid = target_highest_slotid;
+       tbl->generation++;
+}
+
+void nfs41_set_target_slotid(struct nfs4_slot_table *tbl,
+               u32 target_highest_slotid)
+{
+       spin_lock(&tbl->slot_tbl_lock);
+       nfs41_set_target_slotid_locked(tbl, target_highest_slotid);
+       tbl->d_target_highest_slotid = 0;
+       tbl->d2_target_highest_slotid = 0;
+       nfs41_set_max_slotid_locked(tbl, target_highest_slotid);
+       spin_unlock(&tbl->slot_tbl_lock);
+}
+
+static void nfs41_set_server_slotid_locked(struct nfs4_slot_table *tbl,
+               u32 highest_slotid)
+{
+       if (tbl->server_highest_slotid == highest_slotid)
+               return;
+       if (tbl->highest_used_slotid > highest_slotid)
+               return;
+       /* Deallocate slots */
+       nfs4_shrink_slot_table(tbl, highest_slotid + 1);
+       tbl->server_highest_slotid = highest_slotid;
+}
+
+static s32 nfs41_derivative_target_slotid(s32 s1, s32 s2)
+{
+       s1 -= s2;
+       if (s1 == 0)
+               return 0;
+       if (s1 < 0)
+               return (s1 - 1) >> 1;
+       return (s1 + 1) >> 1;
+}
+
+static int nfs41_sign_s32(s32 s1)
+{
+       if (s1 > 0)
+               return 1;
+       if (s1 < 0)
+               return -1;
+       return 0;
+}
+
+static bool nfs41_same_sign_or_zero_s32(s32 s1, s32 s2)
+{
+       if (!s1 || !s2)
+               return true;
+       return nfs41_sign_s32(s1) == nfs41_sign_s32(s2);
+}
+
+/* Try to eliminate outliers by checking for sharp changes in the
+ * derivatives and second derivatives
+ */
+static bool nfs41_is_outlier_target_slotid(struct nfs4_slot_table *tbl,
+               u32 new_target)
+{
+       s32 d_target, d2_target;
+       bool ret = true;
+
+       d_target = nfs41_derivative_target_slotid(new_target,
+                       tbl->target_highest_slotid);
+       d2_target = nfs41_derivative_target_slotid(d_target,
+                       tbl->d_target_highest_slotid);
+       /* Is first derivative same sign? */
+       if (nfs41_same_sign_or_zero_s32(d_target, tbl->d_target_highest_slotid))
+               ret = false;
+       /* Is second derivative same sign? */
+       if (nfs41_same_sign_or_zero_s32(d2_target, tbl->d2_target_highest_slotid))
+               ret = false;
+       tbl->d_target_highest_slotid = d_target;
+       tbl->d2_target_highest_slotid = d2_target;
+       return ret;
+}
+
+void nfs41_update_target_slotid(struct nfs4_slot_table *tbl,
+               struct nfs4_slot *slot,
+               struct nfs4_sequence_res *res)
+{
+       spin_lock(&tbl->slot_tbl_lock);
+       if (!nfs41_is_outlier_target_slotid(tbl, res->sr_target_highest_slotid))
+               nfs41_set_target_slotid_locked(tbl, res->sr_target_highest_slotid);
+       if (tbl->generation == slot->generation)
+               nfs41_set_server_slotid_locked(tbl, res->sr_highest_slotid);
+       nfs41_set_max_slotid_locked(tbl, res->sr_target_highest_slotid);
+       spin_unlock(&tbl->slot_tbl_lock);
+}
+
+/*
+ * Initialize or reset the forechannel and backchannel tables
+ */
+int nfs4_setup_session_slot_tables(struct nfs4_session *ses)
+{
+       struct nfs4_slot_table *tbl;
+       int status;
+
+       dprintk("--> %s\n", __func__);
+       /* Fore channel */
+       tbl = &ses->fc_slot_table;
+       tbl->session = ses;
+       status = nfs4_realloc_slot_table(tbl, ses->fc_attrs.max_reqs, 1);
+       if (status) /* -ENOMEM */
+               return status;
+       /* Back channel */
+       tbl = &ses->bc_slot_table;
+       tbl->session = ses;
+       status = nfs4_realloc_slot_table(tbl, ses->bc_attrs.max_reqs, 0);
+       if (status && tbl->slots == NULL)
+               /* Fore and back channel share a connection so get
+                * both slot tables or neither */
+               nfs4_destroy_slot_tables(ses);
+       return status;
+}
+
+struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp)
+{
+       struct nfs4_session *session;
+       struct nfs4_slot_table *tbl;
+
+       session = kzalloc(sizeof(struct nfs4_session), GFP_NOFS);
+       if (!session)
+               return NULL;
+
+       tbl = &session->fc_slot_table;
+       tbl->highest_used_slotid = NFS4_NO_SLOT;
+       spin_lock_init(&tbl->slot_tbl_lock);
+       rpc_init_priority_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table");
+       init_completion(&tbl->complete);
+
+       tbl = &session->bc_slot_table;
+       tbl->highest_used_slotid = NFS4_NO_SLOT;
+       spin_lock_init(&tbl->slot_tbl_lock);
+       rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table");
+       init_completion(&tbl->complete);
+
+       session->session_state = 1<<NFS4_SESSION_INITING;
+
+       session->clp = clp;
+       return session;
+}
+
+void nfs4_destroy_session(struct nfs4_session *session)
+{
+       struct rpc_xprt *xprt;
+       struct rpc_cred *cred;
+
+       cred = nfs4_get_exchange_id_cred(session->clp);
+       nfs4_proc_destroy_session(session, cred);
+       if (cred)
+               put_rpccred(cred);
+
+       rcu_read_lock();
+       xprt = rcu_dereference(session->clp->cl_rpcclient->cl_xprt);
+       rcu_read_unlock();
+       dprintk("%s Destroy backchannel for xprt %p\n",
+               __func__, xprt);
+       xprt_destroy_backchannel(xprt, NFS41_BC_MIN_CALLBACKS);
+       nfs4_destroy_slot_tables(session);
+       kfree(session);
+}
+
+/*
+ * With sessions, the client is not marked ready until after a
+ * successful EXCHANGE_ID and CREATE_SESSION.
+ *
+ * Map errors cl_cons_state errors to EPROTONOSUPPORT to indicate
+ * other versions of NFS can be tried.
+ */
+static int nfs41_check_session_ready(struct nfs_client *clp)
+{
+       int ret;
+       
+       if (clp->cl_cons_state == NFS_CS_SESSION_INITING) {
+               ret = nfs4_client_recover_expired_lease(clp);
+               if (ret)
+                       return ret;
+       }
+       if (clp->cl_cons_state < NFS_CS_READY)
+               return -EPROTONOSUPPORT;
+       smp_rmb();
+       return 0;
+}
+
+int nfs4_init_session(struct nfs_server *server)
+{
+       struct nfs_client *clp = server->nfs_client;
+       struct nfs4_session *session;
+       unsigned int target_max_rqst_sz = NFS_MAX_FILE_IO_SIZE;
+       unsigned int target_max_resp_sz = NFS_MAX_FILE_IO_SIZE;
+
+       if (!nfs4_has_session(clp))
+               return 0;
+
+       if (server->rsize != 0)
+               target_max_resp_sz = server->rsize;
+       target_max_resp_sz += nfs41_maxread_overhead;
+
+       if (server->wsize != 0)
+               target_max_rqst_sz = server->wsize;
+       target_max_rqst_sz += nfs41_maxwrite_overhead;
+
+       session = clp->cl_session;
+       spin_lock(&clp->cl_lock);
+       if (test_and_clear_bit(NFS4_SESSION_INITING, &session->session_state)) {
+               /* Initialise targets and channel attributes */
+               session->fc_target_max_rqst_sz = target_max_rqst_sz;
+               session->fc_attrs.max_rqst_sz = target_max_rqst_sz;
+               session->fc_target_max_resp_sz = target_max_resp_sz;
+               session->fc_attrs.max_resp_sz = target_max_resp_sz;
+       } else {
+               /* Just adjust the targets */
+               if (target_max_rqst_sz > session->fc_target_max_rqst_sz) {
+                       session->fc_target_max_rqst_sz = target_max_rqst_sz;
+                       set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
+               }
+               if (target_max_resp_sz > session->fc_target_max_resp_sz) {
+                       session->fc_target_max_resp_sz = target_max_resp_sz;
+                       set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
+               }
+       }
+       spin_unlock(&clp->cl_lock);
+
+       if (test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state))
+               nfs4_schedule_lease_recovery(clp);
+
+       return nfs41_check_session_ready(clp);
+}
+
+int nfs4_init_ds_session(struct nfs_client *clp, unsigned long lease_time)
+{
+       struct nfs4_session *session = clp->cl_session;
+       int ret;
+
+       spin_lock(&clp->cl_lock);
+       if (test_and_clear_bit(NFS4_SESSION_INITING, &session->session_state)) {
+               /*
+                * Do not set NFS_CS_CHECK_LEASE_TIME instead set the
+                * DS lease to be equal to the MDS lease.
+                */
+               clp->cl_lease_time = lease_time;
+               clp->cl_last_renewal = jiffies;
+       }
+       spin_unlock(&clp->cl_lock);
+
+       ret = nfs41_check_session_ready(clp);
+       if (ret)
+               return ret;
+       /* Test for the DS role */
+       if (!is_ds_client(clp))
+               return -ENODEV;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(nfs4_init_ds_session);
+
+
diff --git a/fs/nfs/nfs4session.h b/fs/nfs/nfs4session.h
new file mode 100644 (file)
index 0000000..6f3cb39
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * fs/nfs/nfs4session.h
+ *
+ * Copyright (c) 2012 Trond Myklebust <Trond.Myklebust@netapp.com>
+ *
+ */
+#ifndef __LINUX_FS_NFS_NFS4SESSION_H
+#define __LINUX_FS_NFS_NFS4SESSION_H
+
+/* maximum number of slots to use */
+#define NFS4_DEF_SLOT_TABLE_SIZE (16U)
+#define NFS4_MAX_SLOT_TABLE (1024U)
+#define NFS4_NO_SLOT ((u32)-1)
+
+#if IS_ENABLED(CONFIG_NFS_V4)
+
+/* Sessions slot seqid */
+struct nfs4_slot {
+       struct nfs4_slot_table  *table;
+       struct nfs4_slot        *next;
+       unsigned long           generation;
+       u32                     slot_nr;
+       u32                     seq_nr;
+       unsigned int            interrupted : 1;
+};
+
+/* Sessions */
+#define SLOT_TABLE_SZ DIV_ROUND_UP(NFS4_MAX_SLOT_TABLE, 8*sizeof(long))
+struct nfs4_slot_table {
+       struct nfs4_session *session;           /* Parent session */
+       struct nfs4_slot *slots;                /* seqid per slot */
+       unsigned long   used_slots[SLOT_TABLE_SZ]; /* used/unused bitmap */
+       spinlock_t      slot_tbl_lock;
+       struct rpc_wait_queue   slot_tbl_waitq; /* allocators may wait here */
+       u32             max_slots;              /* # slots in table */
+       u32             max_slotid;             /* Max allowed slotid value */
+       u32             highest_used_slotid;    /* sent to server on each SEQ.
+                                                * op for dynamic resizing */
+       u32             target_highest_slotid;  /* Server max_slot target */
+       u32             server_highest_slotid;  /* Server highest slotid */
+       s32             d_target_highest_slotid; /* Derivative */
+       s32             d2_target_highest_slotid; /* 2nd derivative */
+       unsigned long   generation;             /* Generation counter for
+                                                  target_highest_slotid */
+       struct completion complete;
+};
+
+/*
+ * Session related parameters
+ */
+struct nfs4_session {
+       struct nfs4_sessionid           sess_id;
+       u32                             flags;
+       unsigned long                   session_state;
+       u32                             hash_alg;
+       u32                             ssv_len;
+
+       /* The fore and back channel */
+       struct nfs4_channel_attrs       fc_attrs;
+       struct nfs4_slot_table          fc_slot_table;
+       struct nfs4_channel_attrs       bc_attrs;
+       struct nfs4_slot_table          bc_slot_table;
+       struct nfs_client               *clp;
+       /* Create session arguments */
+       unsigned int                    fc_target_max_rqst_sz;
+       unsigned int                    fc_target_max_resp_sz;
+};
+
+enum nfs4_session_state {
+       NFS4_SESSION_INITING,
+       NFS4_SESSION_DRAINING,
+};
+
+#if defined(CONFIG_NFS_V4_1)
+extern struct nfs4_slot *nfs4_alloc_slot(struct nfs4_slot_table *tbl);
+extern void nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot);
+
+extern void nfs41_set_target_slotid(struct nfs4_slot_table *tbl,
+               u32 target_highest_slotid);
+extern void nfs41_update_target_slotid(struct nfs4_slot_table *tbl,
+               struct nfs4_slot *slot,
+               struct nfs4_sequence_res *res);
+
+extern int nfs4_setup_session_slot_tables(struct nfs4_session *ses);
+
+extern struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp);
+extern void nfs4_destroy_session(struct nfs4_session *session);
+extern int nfs4_init_session(struct nfs_server *server);
+extern int nfs4_init_ds_session(struct nfs_client *, unsigned long);
+
+extern void nfs4_session_drain_complete(struct nfs4_session *session,
+               struct nfs4_slot_table *tbl);
+
+static inline bool nfs4_session_draining(struct nfs4_session *session)
+{
+       return !!test_bit(NFS4_SESSION_DRAINING, &session->session_state);
+}
+
+bool nfs41_wake_and_assign_slot(struct nfs4_slot_table *tbl,
+               struct nfs4_slot *slot);
+void nfs41_wake_slot_table(struct nfs4_slot_table *tbl);
+
+/*
+ * Determine if sessions are in use.
+ */
+static inline int nfs4_has_session(const struct nfs_client *clp)
+{
+       if (clp->cl_session)
+               return 1;
+       return 0;
+}
+
+static inline int nfs4_has_persistent_session(const struct nfs_client *clp)
+{
+       if (nfs4_has_session(clp))
+               return (clp->cl_session->flags & SESSION4_PERSIST);
+       return 0;
+}
+
+#else /* defined(CONFIG_NFS_V4_1) */
+
+static inline int nfs4_init_session(struct nfs_server *server)
+{
+       return 0;
+}
+
+/*
+ * Determine if sessions are in use.
+ */
+static inline int nfs4_has_session(const struct nfs_client *clp)
+{
+       return 0;
+}
+
+static inline int nfs4_has_persistent_session(const struct nfs_client *clp)
+{
+       return 0;
+}
+
+#endif /* defined(CONFIG_NFS_V4_1) */
+#endif /* IS_ENABLED(CONFIG_NFS_V4) */
+#endif /* __LINUX_FS_NFS_NFS4SESSION_H */
index c351e6b398388f7c1b4b09a6240d4ad6c2559295..9448c579d41a40068897f99cbc5db09bccf3e063 100644 (file)
@@ -57,6 +57,7 @@
 #include "callback.h"
 #include "delegation.h"
 #include "internal.h"
+#include "nfs4session.h"
 #include "pnfs.h"
 #include "netns.h"
 
@@ -66,7 +67,6 @@
 
 const nfs4_stateid zero_stateid;
 static DEFINE_MUTEX(nfs_clid_init_mutex);
-static LIST_HEAD(nfs4_clientid_list);
 
 int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)
 {
@@ -254,24 +254,27 @@ static void nfs4_end_drain_session(struct nfs_client *clp)
 {
        struct nfs4_session *ses = clp->cl_session;
        struct nfs4_slot_table *tbl;
-       int max_slots;
 
        if (ses == NULL)
                return;
        tbl = &ses->fc_slot_table;
        if (test_and_clear_bit(NFS4_SESSION_DRAINING, &ses->session_state)) {
                spin_lock(&tbl->slot_tbl_lock);
-               max_slots = tbl->max_slots;
-               while (max_slots--) {
-                       if (rpc_wake_up_first(&tbl->slot_tbl_waitq,
-                                               nfs4_set_task_privileged,
-                                               NULL) == NULL)
-                               break;
-               }
+               nfs41_wake_slot_table(tbl);
                spin_unlock(&tbl->slot_tbl_lock);
        }
 }
 
+/*
+ * Signal state manager thread if session fore channel is drained
+ */
+void nfs4_session_drain_complete(struct nfs4_session *session,
+               struct nfs4_slot_table *tbl)
+{
+       if (nfs4_session_draining(session))
+               complete(&tbl->complete);
+}
+
 static int nfs4_wait_on_slot_tbl(struct nfs4_slot_table *tbl)
 {
        spin_lock(&tbl->slot_tbl_lock);
@@ -303,7 +306,6 @@ static void nfs41_finish_session_reset(struct nfs_client *clp)
        clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
        clear_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
        /* create_session negotiated new slot table */
-       clear_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state);
        clear_bit(NFS4CLNT_BIND_CONN_TO_SESSION, &clp->cl_state);
        nfs41_setup_state_renewal(clp);
 }
@@ -1086,7 +1088,6 @@ void nfs_free_seqid(struct nfs_seqid *seqid)
  */
 static void nfs_increment_seqid(int status, struct nfs_seqid *seqid)
 {
-       BUG_ON(list_first_entry(&seqid->sequence->list, struct nfs_seqid, list) != seqid);
        switch (status) {
                case 0:
                        break;
@@ -1209,6 +1210,40 @@ void nfs4_schedule_lease_recovery(struct nfs_client *clp)
 }
 EXPORT_SYMBOL_GPL(nfs4_schedule_lease_recovery);
 
+int nfs4_wait_clnt_recover(struct nfs_client *clp)
+{
+       int res;
+
+       might_sleep();
+
+       res = wait_on_bit(&clp->cl_state, NFS4CLNT_MANAGER_RUNNING,
+                       nfs_wait_bit_killable, TASK_KILLABLE);
+       if (res)
+               return res;
+
+       if (clp->cl_cons_state < 0)
+               return clp->cl_cons_state;
+       return 0;
+}
+
+int nfs4_client_recover_expired_lease(struct nfs_client *clp)
+{
+       unsigned int loop;
+       int ret;
+
+       for (loop = NFS4_MAX_LOOP_ON_RECOVER; loop != 0; loop--) {
+               ret = nfs4_wait_clnt_recover(clp);
+               if (ret != 0)
+                       break;
+               if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) &&
+                   !test_bit(NFS4CLNT_CHECK_LEASE,&clp->cl_state))
+                       break;
+               nfs4_schedule_state_manager(clp);
+               ret = -EIO;
+       }
+       return ret;
+}
+
 /*
  * nfs40_handle_cb_pathdown - return all delegations after NFS4ERR_CB_PATH_DOWN
  * @clp: client to process
@@ -1401,14 +1436,6 @@ restart:
                                /* Mark the file as being 'closed' */
                                state->state = 0;
                                break;
-                       case -EKEYEXPIRED:
-                               /*
-                                * User RPCSEC_GSS context has expired.
-                                * We cannot recover this stateid now, so
-                                * skip it and allow recovery thread to
-                                * proceed.
-                                */
-                               break;
                        case -NFS4ERR_ADMIN_REVOKED:
                        case -NFS4ERR_STALE_STATEID:
                        case -NFS4ERR_BAD_STATEID:
@@ -1561,14 +1588,6 @@ static void nfs4_state_start_reclaim_nograce(struct nfs_client *clp)
        nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_nograce);
 }
 
-static void nfs4_warn_keyexpired(const char *s)
-{
-       printk_ratelimited(KERN_WARNING "Error: state manager"
-                       " encountered RPCSEC_GSS session"
-                       " expired against NFSv4 server %s.\n",
-                       s);
-}
-
 static int nfs4_recovery_handle_error(struct nfs_client *clp, int error)
 {
        switch (error) {
@@ -1602,10 +1621,6 @@ static int nfs4_recovery_handle_error(struct nfs_client *clp, int error)
                case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
                        set_bit(NFS4CLNT_BIND_CONN_TO_SESSION, &clp->cl_state);
                        break;
-               case -EKEYEXPIRED:
-                       /* Nothing we can do */
-                       nfs4_warn_keyexpired(clp->cl_hostname);
-                       break;
                default:
                        dprintk("%s: failed to handle error %d for server %s\n",
                                        __func__, error, clp->cl_hostname);
@@ -1722,8 +1737,6 @@ static int nfs4_handle_reclaim_lease_error(struct nfs_client *clp, int status)
                dprintk("%s: exit with error %d for server %s\n",
                                __func__, -EPROTONOSUPPORT, clp->cl_hostname);
                return -EPROTONOSUPPORT;
-       case -EKEYEXPIRED:
-               nfs4_warn_keyexpired(clp->cl_hostname);
        case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery
                                 * in nfs4_exchange_id */
        default:
@@ -1876,7 +1889,6 @@ again:
                break;
 
        case -EKEYEXPIRED:
-               nfs4_warn_keyexpired(clp->cl_hostname);
        case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery
                                 * in nfs4_exchange_id */
                status = -EKEYEXPIRED;
@@ -1907,14 +1919,23 @@ void nfs4_schedule_session_recovery(struct nfs4_session *session, int err)
 }
 EXPORT_SYMBOL_GPL(nfs4_schedule_session_recovery);
 
-void nfs41_handle_recall_slot(struct nfs_client *clp)
+static void nfs41_ping_server(struct nfs_client *clp)
 {
-       set_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state);
-       dprintk("%s: scheduling slot recall for server %s\n", __func__,
-                       clp->cl_hostname);
+       /* Use CHECK_LEASE to ping the server with a SEQUENCE */
+       set_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
        nfs4_schedule_state_manager(clp);
 }
 
+void nfs41_server_notify_target_slotid_update(struct nfs_client *clp)
+{
+       nfs41_ping_server(clp);
+}
+
+void nfs41_server_notify_highest_slotid_update(struct nfs_client *clp)
+{
+       nfs41_ping_server(clp);
+}
+
 static void nfs4_reset_all_state(struct nfs_client *clp)
 {
        if (test_and_set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0) {
@@ -2024,35 +2045,6 @@ out:
        return status;
 }
 
-static int nfs4_recall_slot(struct nfs_client *clp)
-{
-       struct nfs4_slot_table *fc_tbl;
-       struct nfs4_slot *new, *old;
-       int i;
-
-       if (!nfs4_has_session(clp))
-               return 0;
-       nfs4_begin_drain_session(clp);
-       fc_tbl = &clp->cl_session->fc_slot_table;
-       new = kmalloc(fc_tbl->target_max_slots * sizeof(struct nfs4_slot),
-                     GFP_NOFS);
-        if (!new)
-               return -ENOMEM;
-
-       spin_lock(&fc_tbl->slot_tbl_lock);
-       for (i = 0; i < fc_tbl->target_max_slots; i++)
-               new[i].seq_nr = fc_tbl->slots[i].seq_nr;
-       old = fc_tbl->slots;
-       fc_tbl->slots = new;
-       fc_tbl->max_slots = fc_tbl->target_max_slots;
-       fc_tbl->target_max_slots = 0;
-       clp->cl_session->fc_attrs.max_reqs = fc_tbl->max_slots;
-       spin_unlock(&fc_tbl->slot_tbl_lock);
-
-       kfree(old);
-       return 0;
-}
-
 static int nfs4_bind_conn_to_session(struct nfs_client *clp)
 {
        struct rpc_cred *cred;
@@ -2083,7 +2075,6 @@ static int nfs4_bind_conn_to_session(struct nfs_client *clp)
 #else /* CONFIG_NFS_V4_1 */
 static int nfs4_reset_session(struct nfs_client *clp) { return 0; }
 static int nfs4_end_drain_session(struct nfs_client *clp) { return 0; }
-static int nfs4_recall_slot(struct nfs_client *clp) { return 0; }
 
 static int nfs4_bind_conn_to_session(struct nfs_client *clp)
 {
@@ -2115,15 +2106,6 @@ static void nfs4_state_manager(struct nfs_client *clp)
                        continue;
                }
 
-               if (test_and_clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state)) {
-                       section = "check lease";
-                       status = nfs4_check_lease(clp);
-                       if (status < 0)
-                               goto out_error;
-                       if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
-                               continue;
-               }
-
                /* Initialize or reset the session */
                if (test_and_clear_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state)) {
                        section = "reset session";
@@ -2144,10 +2126,9 @@ static void nfs4_state_manager(struct nfs_client *clp)
                        continue;
                }
 
-               /* Recall session slots */
-               if (test_and_clear_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state)) {
-                       section = "recall slot";
-                       status = nfs4_recall_slot(clp);
+               if (test_and_clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state)) {
+                       section = "check lease";
+                       status = nfs4_check_lease(clp);
                        if (status < 0)
                                goto out_error;
                        continue;
index bd61221ad2c5542b08f42249d10285c159f66b1d..84d2e9e2f313b7d9e64a260f79a66ce83b377f92 100644 (file)
@@ -51,6 +51,7 @@ static const struct super_operations nfs4_sops = {
        .alloc_inode    = nfs_alloc_inode,
        .destroy_inode  = nfs_destroy_inode,
        .write_inode    = nfs4_write_inode,
+       .drop_inode     = nfs_drop_inode,
        .put_super      = nfs_put_super,
        .statfs         = nfs_statfs,
        .evict_inode    = nfs4_evict_inode,
index 40836ee5dc3a87849b9dc2fc1f1946f4acbe45b6..26b143920433e628456476e0d1b708b8fc395d43 100644 (file)
@@ -56,6 +56,7 @@
 
 #include "nfs4_fs.h"
 #include "internal.h"
+#include "nfs4session.h"
 #include "pnfs.h"
 #include "netns.h"
 
@@ -270,6 +271,8 @@ static int nfs4_stat_to_errno(int);
 
 #if defined(CONFIG_NFS_V4_1)
 #define NFS4_MAX_MACHINE_NAME_LEN (64)
+#define IMPL_NAME_LIMIT (sizeof(utsname()->sysname) + sizeof(utsname()->release) + \
+                        sizeof(utsname()->version) + sizeof(utsname()->machine) + 8)
 
 #define encode_exchange_id_maxsz (op_encode_hdr_maxsz + \
                                encode_verifier_maxsz + \
@@ -282,7 +285,7 @@ static int nfs4_stat_to_errno(int);
                                1 /* nii_domain */ + \
                                XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + \
                                1 /* nii_name */ + \
-                               XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + \
+                               XDR_QUADLEN(IMPL_NAME_LIMIT) + \
                                3 /* nii_date */)
 #define decode_exchange_id_maxsz (op_decode_hdr_maxsz + \
                                2 /* eir_clientid */ + \
@@ -936,7 +939,7 @@ static void encode_compound_hdr(struct xdr_stream *xdr,
         * but this is not required as a MUST for the server to do so. */
        hdr->replen = RPC_REPHDRSIZE + auth->au_rslack + 3 + hdr->taglen;
 
-       BUG_ON(hdr->taglen > NFS4_MAXTAGLEN);
+       WARN_ON_ONCE(hdr->taglen > NFS4_MAXTAGLEN);
        encode_string(xdr, hdr->taglen, hdr->tag);
        p = reserve_space(xdr, 8);
        *p++ = cpu_to_be32(hdr->minorversion);
@@ -955,7 +958,7 @@ static void encode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 op,
 
 static void encode_nops(struct compound_hdr *hdr)
 {
-       BUG_ON(hdr->nops > NFS4_MAX_OPS);
+       WARN_ON_ONCE(hdr->nops > NFS4_MAX_OPS);
        *hdr->nops_p = htonl(hdr->nops);
 }
 
@@ -1403,7 +1406,6 @@ static void encode_opentype(struct xdr_stream *xdr, const struct nfs_openargs *a
                *p = cpu_to_be32(NFS4_OPEN_NOCREATE);
                break;
        default:
-               BUG_ON(arg->claim != NFS4_OPEN_CLAIM_NULL);
                *p = cpu_to_be32(NFS4_OPEN_CREATE);
                encode_createmode(xdr, arg);
        }
@@ -1621,7 +1623,6 @@ encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg, struct compoun
        p = reserve_space(xdr, 2*4);
        *p++ = cpu_to_be32(1);
        *p = cpu_to_be32(FATTR4_WORD0_ACL);
-       BUG_ON(arg->acl_len % 4);
        p = reserve_space(xdr, 4);
        *p = cpu_to_be32(arg->acl_len);
        xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len);
@@ -1713,7 +1714,7 @@ static void encode_exchange_id(struct xdr_stream *xdr,
                               struct compound_hdr *hdr)
 {
        __be32 *p;
-       char impl_name[NFS4_OPAQUE_LIMIT];
+       char impl_name[IMPL_NAME_LIMIT];
        int len = 0;
 
        encode_op_hdr(xdr, OP_EXCHANGE_ID, decode_exchange_id_maxsz, hdr);
@@ -1728,7 +1729,7 @@ static void encode_exchange_id(struct xdr_stream *xdr,
        if (send_implementation_id &&
            sizeof(CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN) > 1 &&
            sizeof(CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN)
-               <= NFS4_OPAQUE_LIMIT + 1)
+               <= sizeof(impl_name) + 1)
                len = snprintf(impl_name, sizeof(impl_name), "%s %s %s %s",
                               utsname()->sysname, utsname()->release,
                               utsname()->version, utsname()->machine);
@@ -1835,18 +1836,16 @@ static void encode_sequence(struct xdr_stream *xdr,
                            struct compound_hdr *hdr)
 {
 #if defined(CONFIG_NFS_V4_1)
-       struct nfs4_session *session = args->sa_session;
+       struct nfs4_session *session;
        struct nfs4_slot_table *tp;
-       struct nfs4_slot *slot;
+       struct nfs4_slot *slot = args->sa_slot;
        __be32 *p;
 
-       if (!session)
+       if (slot == NULL)
                return;
 
-       tp = &session->fc_slot_table;
-
-       WARN_ON(args->sa_slotid == NFS4_MAX_SLOT_TABLE);
-       slot = tp->slots + args->sa_slotid;
+       tp = slot->table;
+       session = tp->session;
 
        encode_op_hdr(xdr, OP_SEQUENCE, decode_sequence_maxsz, hdr);
 
@@ -1860,12 +1859,12 @@ static void encode_sequence(struct xdr_stream *xdr,
                ((u32 *)session->sess_id.data)[1],
                ((u32 *)session->sess_id.data)[2],
                ((u32 *)session->sess_id.data)[3],
-               slot->seq_nr, args->sa_slotid,
+               slot->seq_nr, slot->slot_nr,
                tp->highest_used_slotid, args->sa_cache_this);
        p = reserve_space(xdr, NFS4_MAX_SESSIONID_LEN + 16);
        p = xdr_encode_opaque_fixed(p, session->sess_id.data, NFS4_MAX_SESSIONID_LEN);
        *p++ = cpu_to_be32(slot->seq_nr);
-       *p++ = cpu_to_be32(args->sa_slotid);
+       *p++ = cpu_to_be32(slot->slot_nr);
        *p++ = cpu_to_be32(tp->highest_used_slotid);
        *p = cpu_to_be32(args->sa_cache_this);
 #endif /* CONFIG_NFS_V4_1 */
@@ -2027,8 +2026,9 @@ static void encode_free_stateid(struct xdr_stream *xdr,
 static u32 nfs4_xdr_minorversion(const struct nfs4_sequence_args *args)
 {
 #if defined(CONFIG_NFS_V4_1)
-       if (args->sa_session)
-               return args->sa_session->clp->cl_mvops->minor_version;
+
+       if (args->sa_slot)
+               return args->sa_slot->table->session->clp->cl_mvops->minor_version;
 #endif /* CONFIG_NFS_V4_1 */
        return 0;
 }
@@ -5509,12 +5509,13 @@ static int decode_sequence(struct xdr_stream *xdr,
                           struct rpc_rqst *rqstp)
 {
 #if defined(CONFIG_NFS_V4_1)
+       struct nfs4_session *session;
        struct nfs4_sessionid id;
        u32 dummy;
        int status;
        __be32 *p;
 
-       if (!res->sr_session)
+       if (res->sr_slot == NULL)
                return 0;
 
        status = decode_op_hdr(xdr, OP_SEQUENCE);
@@ -5528,8 +5529,9 @@ static int decode_sequence(struct xdr_stream *xdr,
         * sequence number, the server is looney tunes.
         */
        status = -EREMOTEIO;
+       session = res->sr_slot->table->session;
 
-       if (memcmp(id.data, res->sr_session->sess_id.data,
+       if (memcmp(id.data, session->sess_id.data,
                   NFS4_MAX_SESSIONID_LEN)) {
                dprintk("%s Invalid session id\n", __func__);
                goto out_err;
@@ -5547,14 +5549,14 @@ static int decode_sequence(struct xdr_stream *xdr,
        }
        /* slot id */
        dummy = be32_to_cpup(p++);
-       if (dummy != res->sr_slot - res->sr_session->fc_slot_table.slots) {
+       if (dummy != res->sr_slot->slot_nr) {
                dprintk("%s Invalid slot id\n", __func__);
                goto out_err;
        }
-       /* highest slot id - currently not processed */
-       dummy = be32_to_cpup(p++);
-       /* target highest slot id - currently not processed */
-       dummy = be32_to_cpup(p++);
+       /* highest slot id */
+       res->sr_highest_slotid = be32_to_cpup(p++);
+       /* target highest slot id */
+       res->sr_target_highest_slotid = be32_to_cpup(p++);
        /* result flags */
        res->sr_status_flags = be32_to_cpup(p);
        status = 0;
index 8746135453011dc70d30ebbd5b70e2b813f7b15d..a9ebd817278b7beb301c222cb3e7abd1c183c3b4 100644 (file)
@@ -148,17 +148,6 @@ end_offset(u64 start, u64 len)
        return end >= start ? end : NFS4_MAX_UINT64;
 }
 
-/* last octet in a range */
-static inline u64
-last_byte_offset(u64 start, u64 len)
-{
-       u64 end;
-
-       BUG_ON(!len);
-       end = start + len;
-       return end > start ? end - 1 : NFS4_MAX_UINT64;
-}
-
 static void _fix_verify_io_params(struct pnfs_layout_segment *lseg,
                           struct page ***p_pages, unsigned *p_pgbase,
                           u64 offset, unsigned long count)
index 2878f97bd78d5cf5343b88cfcac9b5a48a1abe60..e7165d915362838ab485e51ddde95db97ecd96c0 100644 (file)
@@ -369,17 +369,6 @@ end_offset(u64 start, u64 len)
        return end >= start ? end : NFS4_MAX_UINT64;
 }
 
-/* last octet in a range */
-static inline u64
-last_byte_offset(u64 start, u64 len)
-{
-       u64 end;
-
-       BUG_ON(!len);
-       end = start + len;
-       return end > start ? end - 1 : NFS4_MAX_UINT64;
-}
-
 /*
  * is l2 fully contained in l1?
  *   start1                             end1
@@ -645,7 +634,6 @@ send_layoutget(struct pnfs_layout_hdr *lo,
 
        dprintk("--> %s\n", __func__);
 
-       BUG_ON(ctx == NULL);
        lgp = kzalloc(sizeof(*lgp), gfp_flags);
        if (lgp == NULL)
                return NULL;
@@ -1126,7 +1114,6 @@ pnfs_update_layout(struct inode *ino,
                 * chance of a CB_LAYOUTRECALL(FILE) coming in.
                 */
                spin_lock(&clp->cl_lock);
-               BUG_ON(!list_empty(&lo->plh_layouts));
                list_add_tail(&lo->plh_layouts, &server->layouts);
                spin_unlock(&clp->cl_lock);
        }
@@ -1222,7 +1209,7 @@ pnfs_generic_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *r
 {
        u64 rd_size = req->wb_bytes;
 
-       BUG_ON(pgio->pg_lseg != NULL);
+       WARN_ON_ONCE(pgio->pg_lseg != NULL);
 
        if (req->wb_offset != req->wb_pgbase) {
                nfs_pageio_reset_read_mds(pgio);
@@ -1251,7 +1238,7 @@ void
 pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio,
                           struct nfs_page *req, u64 wb_size)
 {
-       BUG_ON(pgio->pg_lseg != NULL);
+       WARN_ON_ONCE(pgio->pg_lseg != NULL);
 
        if (req->wb_offset != req->wb_pgbase) {
                nfs_pageio_reset_write_mds(pgio);
index 50a88c3546ed9eebdee4c4755ca5b7f6d35489f0..f084dac948e1cca5f773adb168ad9dc5faf4dbf7 100644 (file)
 
 #define NFSDBG_FACILITY                NFSDBG_PROC
 
-/*
- * wrapper to handle the -EKEYEXPIRED error message. This should generally
- * only happen if using krb5 auth and a user's TGT expires. NFSv2 doesn't
- * support the NFSERR_JUKEBOX error code, but we handle this situation in the
- * same way that we handle that error with NFSv3.
- */
-static int
-nfs_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
-{
-       int res;
-       do {
-               res = rpc_call_sync(clnt, msg, flags);
-               if (res != -EKEYEXPIRED)
-                       break;
-               freezable_schedule_timeout_killable(NFS_JUKEBOX_RETRY_TIME);
-               res = -ERESTARTSYS;
-       } while (!fatal_signal_pending(current));
-       return res;
-}
-
-#define rpc_call_sync(clnt, msg, flags)        nfs_rpc_wrapper(clnt, msg, flags)
-
-static int
-nfs_async_handle_expired_key(struct rpc_task *task)
-{
-       if (task->tk_status != -EKEYEXPIRED)
-               return 0;
-       task->tk_status = 0;
-       rpc_restart_call(task);
-       rpc_delay(task, NFS_JUKEBOX_RETRY_TIME);
-       return 1;
-}
-
 /*
  * Bare-bones access to getattr: this is for nfs_read_super.
  */
@@ -364,8 +331,6 @@ static void nfs_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlink
 
 static int nfs_proc_unlink_done(struct rpc_task *task, struct inode *dir)
 {
-       if (nfs_async_handle_expired_key(task))
-               return 0;
        nfs_mark_for_revalidate(dir);
        return 1;
 }
@@ -385,8 +350,6 @@ static int
 nfs_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
                     struct inode *new_dir)
 {
-       if (nfs_async_handle_expired_key(task))
-               return 0;
        nfs_mark_for_revalidate(old_dir);
        nfs_mark_for_revalidate(new_dir);
        return 1;
@@ -642,9 +605,6 @@ static int nfs_read_done(struct rpc_task *task, struct nfs_read_data *data)
 {
        struct inode *inode = data->header->inode;
 
-       if (nfs_async_handle_expired_key(task))
-               return -EAGAIN;
-
        nfs_invalidate_atime(inode);
        if (task->tk_status >= 0) {
                nfs_refresh_inode(inode, data->res.fattr);
@@ -671,9 +631,6 @@ static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data)
 {
        struct inode *inode = data->header->inode;
 
-       if (nfs_async_handle_expired_key(task))
-               return -EAGAIN;
-
        if (task->tk_status >= 0)
                nfs_post_op_update_inode_force_wcc(inode, data->res.fattr);
        return 0;
index 652d3f7176a98fcc4e70e6f5e3d812e4b3d90b83..aa5315bb3666817657e01323e84cb36c8c9f0078 100644 (file)
@@ -64,6 +64,7 @@
 #include "iostat.h"
 #include "internal.h"
 #include "fscache.h"
+#include "nfs4session.h"
 #include "pnfs.h"
 #include "nfs.h"
 
@@ -307,6 +308,7 @@ const struct super_operations nfs_sops = {
        .alloc_inode    = nfs_alloc_inode,
        .destroy_inode  = nfs_destroy_inode,
        .write_inode    = nfs_write_inode,
+       .drop_inode     = nfs_drop_inode,
        .put_super      = nfs_put_super,
        .statfs         = nfs_statfs,
        .evict_inode    = nfs_evict_inode,
index 9347ab7c9574fa3b2468a54449d85d366aaf6b61..5209916e1222f6217ae3ac4fa9fddf36c9c77f2a 100644 (file)
@@ -202,7 +202,6 @@ out:
 /* A writeback failed: mark the page as bad, and invalidate the page cache */
 static void nfs_set_pageerror(struct page *page)
 {
-       SetPageError(page);
        nfs_zap_mapping(page_file_mapping(page)->host, page_file_mapping(page));
 }
 
@@ -239,21 +238,18 @@ int nfs_congestion_kb;
 #define NFS_CONGESTION_OFF_THRESH      \
        (NFS_CONGESTION_ON_THRESH - (NFS_CONGESTION_ON_THRESH >> 2))
 
-static int nfs_set_page_writeback(struct page *page)
+static void nfs_set_page_writeback(struct page *page)
 {
+       struct nfs_server *nfss = NFS_SERVER(page_file_mapping(page)->host);
        int ret = test_set_page_writeback(page);
 
-       if (!ret) {
-               struct inode *inode = page_file_mapping(page)->host;
-               struct nfs_server *nfss = NFS_SERVER(inode);
+       WARN_ON_ONCE(ret != 0);
 
-               if (atomic_long_inc_return(&nfss->writeback) >
-                               NFS_CONGESTION_ON_THRESH) {
-                       set_bdi_congested(&nfss->backing_dev_info,
-                                               BLK_RW_ASYNC);
-               }
+       if (atomic_long_inc_return(&nfss->writeback) >
+                       NFS_CONGESTION_ON_THRESH) {
+               set_bdi_congested(&nfss->backing_dev_info,
+                                       BLK_RW_ASYNC);
        }
-       return ret;
 }
 
 static void nfs_end_page_writeback(struct page *page)
@@ -315,10 +311,10 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,
        if (IS_ERR(req))
                goto out;
 
-       ret = nfs_set_page_writeback(page);
-       BUG_ON(ret != 0);
-       BUG_ON(test_bit(PG_CLEAN, &req->wb_flags));
+       nfs_set_page_writeback(page);
+       WARN_ON_ONCE(test_bit(PG_CLEAN, &req->wb_flags));
 
+       ret = 0;
        if (!nfs_pageio_add_request(pgio, req)) {
                nfs_redirty_request(req);
                ret = pgio->pg_error;
@@ -451,8 +447,6 @@ static void nfs_inode_remove_request(struct nfs_page *req)
        struct inode *inode = req->wb_context->dentry->d_inode;
        struct nfs_inode *nfsi = NFS_I(inode);
 
-       BUG_ON (!NFS_WBACK_BUSY(req));
-
        spin_lock(&inode->i_lock);
        if (likely(!PageSwapCache(req->wb_page))) {
                set_page_private(req->wb_page, 0);
@@ -884,7 +878,7 @@ static bool nfs_write_pageuptodate(struct page *page, struct inode *inode)
 {
        if (nfs_have_delegated_attributes(inode))
                goto out;
-       if (NFS_I(inode)->cache_validity & NFS_INO_REVAL_PAGECACHE)
+       if (NFS_I(inode)->cache_validity & (NFS_INO_INVALID_DATA|NFS_INO_REVAL_PAGECACHE))
                return false;
 out:
        return PageUptodate(page) != 0;
@@ -1727,7 +1721,6 @@ int nfs_wb_page_cancel(struct inode *inode, struct page *page)
        struct nfs_page *req;
        int ret = 0;
 
-       BUG_ON(!PageLocked(page));
        for (;;) {
                wait_on_page_writeback(page);
                req = nfs_page_find_request(page);
@@ -1829,7 +1822,7 @@ int __init nfs_init_writepagecache(void)
                goto out_destroy_write_mempool;
 
        nfs_commit_mempool = mempool_create_slab_pool(MIN_POOL_COMMIT,
-                                                     nfs_wdata_cachep);
+                                                     nfs_cdata_cachep);
        if (nfs_commit_mempool == NULL)
                goto out_destroy_commit_cache;
 
index a9e76ee1adcae3c28c4823ae5cf7eb472bd05a03..6c6ed153a9b4833f055ac7899b066b9c87782ece 100644 (file)
@@ -198,51 +198,4 @@ struct nfs_server {
 #define NFS_CAP_POSIX_LOCK     (1U << 14)
 #define NFS_CAP_UIDGID_NOMAP   (1U << 15)
 
-
-/* maximum number of slots to use */
-#define NFS4_DEF_SLOT_TABLE_SIZE (16U)
-#define NFS4_MAX_SLOT_TABLE (256U)
-#define NFS4_NO_SLOT ((u32)-1)
-
-#if IS_ENABLED(CONFIG_NFS_V4)
-
-/* Sessions */
-#define SLOT_TABLE_SZ DIV_ROUND_UP(NFS4_MAX_SLOT_TABLE, 8*sizeof(long))
-struct nfs4_slot_table {
-       struct nfs4_slot *slots;                /* seqid per slot */
-       unsigned long   used_slots[SLOT_TABLE_SZ]; /* used/unused bitmap */
-       spinlock_t      slot_tbl_lock;
-       struct rpc_wait_queue   slot_tbl_waitq; /* allocators may wait here */
-       u32             max_slots;              /* # slots in table */
-       u32             highest_used_slotid;    /* sent to server on each SEQ.
-                                                * op for dynamic resizing */
-       u32             target_max_slots;       /* Set by CB_RECALL_SLOT as
-                                                * the new max_slots */
-       struct completion complete;
-};
-
-static inline int slot_idx(struct nfs4_slot_table *tbl, struct nfs4_slot *sp)
-{
-       return sp - tbl->slots;
-}
-
-/*
- * Session related parameters
- */
-struct nfs4_session {
-       struct nfs4_sessionid           sess_id;
-       u32                             flags;
-       unsigned long                   session_state;
-       u32                             hash_alg;
-       u32                             ssv_len;
-
-       /* The fore and back channel */
-       struct nfs4_channel_attrs       fc_attrs;
-       struct nfs4_slot_table          fc_slot_table;
-       struct nfs4_channel_attrs       bc_attrs;
-       struct nfs4_slot_table          bc_slot_table;
-       struct nfs_client               *clp;
-};
-
-#endif /* CONFIG_NFS_V4 */
 #endif
index a73ea89789d1b3375846b96656873c790d87d5a1..29adb12c7ecffad9b58d6144d742489cb974de80 100644 (file)
@@ -185,23 +185,20 @@ struct nfs4_channel_attrs {
        u32                     max_reqs;
 };
 
-/* nfs41 sessions slot seqid */
-struct nfs4_slot {
-       u32                     seq_nr;
-};
-
+struct nfs4_slot;
 struct nfs4_sequence_args {
-       struct nfs4_session     *sa_session;
-       u32                     sa_slotid;
-       u8                      sa_cache_this;
+       struct nfs4_slot        *sa_slot;
+       u8                      sa_cache_this : 1,
+                               sa_privileged : 1;
 };
 
 struct nfs4_sequence_res {
-       struct nfs4_session     *sr_session;
        struct nfs4_slot        *sr_slot;       /* slot used to send request */
+       unsigned long           sr_timestamp;
        int                     sr_status;      /* sequence operation status */
-       unsigned long           sr_renewal_time;
        u32                     sr_status_flags;
+       u32                     sr_highest_slotid;
+       u32                     sr_target_highest_slotid;
 };
 
 struct nfs4_get_lease_time_args {
@@ -209,8 +206,8 @@ struct nfs4_get_lease_time_args {
 };
 
 struct nfs4_get_lease_time_res {
-       struct nfs_fsinfo              *lr_fsinfo;
        struct nfs4_sequence_res        lr_seq_res;
+       struct nfs_fsinfo              *lr_fsinfo;
 };
 
 #define PNFS_LAYOUT_MAXSIZE 4096
@@ -228,23 +225,23 @@ struct pnfs_layout_range {
 };
 
 struct nfs4_layoutget_args {
+       struct nfs4_sequence_args seq_args;
        __u32 type;
        struct pnfs_layout_range range;
        __u64 minlength;
        __u32 maxcount;
        struct inode *inode;
        struct nfs_open_context *ctx;
-       struct nfs4_sequence_args seq_args;
        nfs4_stateid stateid;
        struct nfs4_layoutdriver_data layout;
 };
 
 struct nfs4_layoutget_res {
+       struct nfs4_sequence_res seq_res;
        __u32 return_on_close;
        struct pnfs_layout_range range;
        __u32 type;
        nfs4_stateid stateid;
-       struct nfs4_sequence_res seq_res;
        struct nfs4_layoutdriver_data *layoutp;
 };
 
@@ -255,38 +252,38 @@ struct nfs4_layoutget {
 };
 
 struct nfs4_getdevicelist_args {
+       struct nfs4_sequence_args seq_args;
        const struct nfs_fh *fh;
        u32 layoutclass;
-       struct nfs4_sequence_args seq_args;
 };
 
 struct nfs4_getdevicelist_res {
-       struct pnfs_devicelist *devlist;
        struct nfs4_sequence_res seq_res;
+       struct pnfs_devicelist *devlist;
 };
 
 struct nfs4_getdeviceinfo_args {
-       struct pnfs_device *pdev;
        struct nfs4_sequence_args seq_args;
+       struct pnfs_device *pdev;
 };
 
 struct nfs4_getdeviceinfo_res {
-       struct pnfs_device *pdev;
        struct nfs4_sequence_res seq_res;
+       struct pnfs_device *pdev;
 };
 
 struct nfs4_layoutcommit_args {
+       struct nfs4_sequence_args seq_args;
        nfs4_stateid stateid;
        __u64 lastbytewritten;
        struct inode *inode;
        const u32 *bitmask;
-       struct nfs4_sequence_args seq_args;
 };
 
 struct nfs4_layoutcommit_res {
+       struct nfs4_sequence_res seq_res;
        struct nfs_fattr *fattr;
        const struct nfs_server *server;
-       struct nfs4_sequence_res seq_res;
        int status;
 };
 
@@ -300,11 +297,11 @@ struct nfs4_layoutcommit_data {
 };
 
 struct nfs4_layoutreturn_args {
+       struct nfs4_sequence_args seq_args;
        struct pnfs_layout_hdr *layout;
        struct inode *inode;
        nfs4_stateid stateid;
        __u32   layout_type;
-       struct nfs4_sequence_args seq_args;
 };
 
 struct nfs4_layoutreturn_res {
@@ -330,6 +327,7 @@ struct stateowner_id {
  * Arguments to the open call.
  */
 struct nfs_openargs {
+       struct nfs4_sequence_args       seq_args;
        const struct nfs_fh *   fh;
        struct nfs_seqid *      seqid;
        int                     open_flags;
@@ -350,10 +348,10 @@ struct nfs_openargs {
        const u32 *             bitmask;
        const u32 *             open_bitmap;
        __u32                   claim;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs_openres {
+       struct nfs4_sequence_res        seq_res;
        nfs4_stateid            stateid;
        struct nfs_fh           fh;
        struct nfs4_change_info cinfo;
@@ -368,7 +366,6 @@ struct nfs_openres {
        __u32                   attrset[NFS4_BITMAP_SIZE];
        struct nfs4_string      *owner;
        struct nfs4_string      *group_owner;
-       struct nfs4_sequence_res        seq_res;
        __u32                   access_request;
        __u32                   access_supported;
        __u32                   access_result;
@@ -392,20 +389,20 @@ struct nfs_open_confirmres {
  * Arguments to the close call.
  */
 struct nfs_closeargs {
+       struct nfs4_sequence_args       seq_args;
        struct nfs_fh *         fh;
        nfs4_stateid *          stateid;
        struct nfs_seqid *      seqid;
        fmode_t                 fmode;
        const u32 *             bitmask;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs_closeres {
+       struct nfs4_sequence_res        seq_res;
        nfs4_stateid            stateid;
        struct nfs_fattr *      fattr;
        struct nfs_seqid *      seqid;
        const struct nfs_server *server;
-       struct nfs4_sequence_res        seq_res;
 };
 /*
  *  * Arguments to the lock,lockt, and locku call.
@@ -417,6 +414,7 @@ struct nfs_lowner {
 };
 
 struct nfs_lock_args {
+       struct nfs4_sequence_args       seq_args;
        struct nfs_fh *         fh;
        struct file_lock *      fl;
        struct nfs_seqid *      lock_seqid;
@@ -427,40 +425,39 @@ struct nfs_lock_args {
        unsigned char           block : 1;
        unsigned char           reclaim : 1;
        unsigned char           new_lock_owner : 1;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs_lock_res {
+       struct nfs4_sequence_res        seq_res;
        nfs4_stateid            stateid;
        struct nfs_seqid *      lock_seqid;
        struct nfs_seqid *      open_seqid;
-       struct nfs4_sequence_res        seq_res;
 };
 
 struct nfs_locku_args {
+       struct nfs4_sequence_args       seq_args;
        struct nfs_fh *         fh;
        struct file_lock *      fl;
        struct nfs_seqid *      seqid;
        nfs4_stateid *          stateid;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs_locku_res {
+       struct nfs4_sequence_res        seq_res;
        nfs4_stateid            stateid;
        struct nfs_seqid *      seqid;
-       struct nfs4_sequence_res        seq_res;
 };
 
 struct nfs_lockt_args {
+       struct nfs4_sequence_args       seq_args;
        struct nfs_fh *         fh;
        struct file_lock *      fl;
        struct nfs_lowner       lock_owner;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs_lockt_res {
-       struct file_lock *      denied; /* LOCK, LOCKT failed */
        struct nfs4_sequence_res        seq_res;
+       struct file_lock *      denied; /* LOCK, LOCKT failed */
 };
 
 struct nfs_release_lockowner_args {
@@ -468,22 +465,23 @@ struct nfs_release_lockowner_args {
 };
 
 struct nfs4_delegreturnargs {
+       struct nfs4_sequence_args       seq_args;
        const struct nfs_fh *fhandle;
        const nfs4_stateid *stateid;
        const u32 * bitmask;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs4_delegreturnres {
+       struct nfs4_sequence_res        seq_res;
        struct nfs_fattr * fattr;
        const struct nfs_server *server;
-       struct nfs4_sequence_res        seq_res;
 };
 
 /*
  * Arguments to the read call.
  */
 struct nfs_readargs {
+       struct nfs4_sequence_args       seq_args;
        struct nfs_fh *         fh;
        struct nfs_open_context *context;
        struct nfs_lock_context *lock_context;
@@ -491,20 +489,20 @@ struct nfs_readargs {
        __u32                   count;
        unsigned int            pgbase;
        struct page **          pages;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs_readres {
+       struct nfs4_sequence_res        seq_res;
        struct nfs_fattr *      fattr;
        __u32                   count;
        int                     eof;
-       struct nfs4_sequence_res        seq_res;
 };
 
 /*
  * Arguments to the write call.
  */
 struct nfs_writeargs {
+       struct nfs4_sequence_args       seq_args;
        struct nfs_fh *         fh;
        struct nfs_open_context *context;
        struct nfs_lock_context *lock_context;
@@ -514,7 +512,6 @@ struct nfs_writeargs {
        unsigned int            pgbase;
        struct page **          pages;
        const u32 *             bitmask;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs_write_verifier {
@@ -527,65 +524,65 @@ struct nfs_writeverf {
 };
 
 struct nfs_writeres {
+       struct nfs4_sequence_res        seq_res;
        struct nfs_fattr *      fattr;
        struct nfs_writeverf *  verf;
        __u32                   count;
        const struct nfs_server *server;
-       struct nfs4_sequence_res        seq_res;
 };
 
 /*
  * Arguments to the commit call.
  */
 struct nfs_commitargs {
+       struct nfs4_sequence_args       seq_args;
        struct nfs_fh           *fh;
        __u64                   offset;
        __u32                   count;
        const u32               *bitmask;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs_commitres {
+       struct nfs4_sequence_res        seq_res;
        struct nfs_fattr        *fattr;
        struct nfs_writeverf    *verf;
        const struct nfs_server *server;
-       struct nfs4_sequence_res        seq_res;
 };
 
 /*
  * Common arguments to the unlink call
  */
 struct nfs_removeargs {
+       struct nfs4_sequence_args       seq_args;
        const struct nfs_fh     *fh;
        struct qstr             name;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs_removeres {
+       struct nfs4_sequence_res        seq_res;
        const struct nfs_server *server;
        struct nfs_fattr        *dir_attr;
        struct nfs4_change_info cinfo;
-       struct nfs4_sequence_res        seq_res;
 };
 
 /*
  * Common arguments to the rename call
  */
 struct nfs_renameargs {
+       struct nfs4_sequence_args       seq_args;
        const struct nfs_fh             *old_dir;
        const struct nfs_fh             *new_dir;
        const struct qstr               *old_name;
        const struct qstr               *new_name;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs_renameres {
+       struct nfs4_sequence_res        seq_res;
        const struct nfs_server         *server;
        struct nfs4_change_info         old_cinfo;
        struct nfs_fattr                *old_fattr;
        struct nfs4_change_info         new_cinfo;
        struct nfs_fattr                *new_fattr;
-       struct nfs4_sequence_res        seq_res;
 };
 
 /*
@@ -626,20 +623,20 @@ struct nfs_createargs {
 };
 
 struct nfs_setattrargs {
+       struct nfs4_sequence_args       seq_args;
        struct nfs_fh *                 fh;
        nfs4_stateid                    stateid;
        struct iattr *                  iap;
        const struct nfs_server *       server; /* Needed for name mapping */
        const u32 *                     bitmask;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs_setaclargs {
+       struct nfs4_sequence_args       seq_args;
        struct nfs_fh *                 fh;
        size_t                          acl_len;
        unsigned int                    acl_pgbase;
        struct page **                  acl_pages;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs_setaclres {
@@ -647,27 +644,27 @@ struct nfs_setaclres {
 };
 
 struct nfs_getaclargs {
+       struct nfs4_sequence_args       seq_args;
        struct nfs_fh *                 fh;
        size_t                          acl_len;
        unsigned int                    acl_pgbase;
        struct page **                  acl_pages;
-       struct nfs4_sequence_args       seq_args;
 };
 
 /* getxattr ACL interface flags */
 #define NFS4_ACL_TRUNC         0x0001  /* ACL was truncated */
 struct nfs_getaclres {
+       struct nfs4_sequence_res        seq_res;
        size_t                          acl_len;
        size_t                          acl_data_offset;
        int                             acl_flags;
        struct page *                   acl_scratch;
-       struct nfs4_sequence_res        seq_res;
 };
 
 struct nfs_setattrres {
+       struct nfs4_sequence_res        seq_res;
        struct nfs_fattr *              fattr;
        const struct nfs_server *       server;
-       struct nfs4_sequence_res        seq_res;
 };
 
 struct nfs_linkargs {
@@ -832,21 +829,22 @@ struct nfs3_getaclres {
 typedef u64 clientid4;
 
 struct nfs4_accessargs {
+       struct nfs4_sequence_args       seq_args;
        const struct nfs_fh *           fh;
        const u32 *                     bitmask;
        u32                             access;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs4_accessres {
+       struct nfs4_sequence_res        seq_res;
        const struct nfs_server *       server;
        struct nfs_fattr *              fattr;
        u32                             supported;
        u32                             access;
-       struct nfs4_sequence_res        seq_res;
 };
 
 struct nfs4_create_arg {
+       struct nfs4_sequence_args       seq_args;
        u32                             ftype;
        union {
                struct {
@@ -863,88 +861,88 @@ struct nfs4_create_arg {
        const struct iattr *            attrs;
        const struct nfs_fh *           dir_fh;
        const u32 *                     bitmask;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs4_create_res {
+       struct nfs4_sequence_res        seq_res;
        const struct nfs_server *       server;
        struct nfs_fh *                 fh;
        struct nfs_fattr *              fattr;
        struct nfs4_change_info         dir_cinfo;
-       struct nfs4_sequence_res        seq_res;
 };
 
 struct nfs4_fsinfo_arg {
+       struct nfs4_sequence_args       seq_args;
        const struct nfs_fh *           fh;
        const u32 *                     bitmask;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs4_fsinfo_res {
-       struct nfs_fsinfo              *fsinfo;
        struct nfs4_sequence_res        seq_res;
+       struct nfs_fsinfo              *fsinfo;
 };
 
 struct nfs4_getattr_arg {
+       struct nfs4_sequence_args       seq_args;
        const struct nfs_fh *           fh;
        const u32 *                     bitmask;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs4_getattr_res {
+       struct nfs4_sequence_res        seq_res;
        const struct nfs_server *       server;
        struct nfs_fattr *              fattr;
-       struct nfs4_sequence_res        seq_res;
 };
 
 struct nfs4_link_arg {
+       struct nfs4_sequence_args       seq_args;
        const struct nfs_fh *           fh;
        const struct nfs_fh *           dir_fh;
        const struct qstr *             name;
        const u32 *                     bitmask;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs4_link_res {
+       struct nfs4_sequence_res        seq_res;
        const struct nfs_server *       server;
        struct nfs_fattr *              fattr;
        struct nfs4_change_info         cinfo;
        struct nfs_fattr *              dir_attr;
-       struct nfs4_sequence_res        seq_res;
 };
 
 
 struct nfs4_lookup_arg {
+       struct nfs4_sequence_args       seq_args;
        const struct nfs_fh *           dir_fh;
        const struct qstr *             name;
        const u32 *                     bitmask;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs4_lookup_res {
+       struct nfs4_sequence_res        seq_res;
        const struct nfs_server *       server;
        struct nfs_fattr *              fattr;
        struct nfs_fh *                 fh;
-       struct nfs4_sequence_res        seq_res;
 };
 
 struct nfs4_lookup_root_arg {
-       const u32 *                     bitmask;
        struct nfs4_sequence_args       seq_args;
+       const u32 *                     bitmask;
 };
 
 struct nfs4_pathconf_arg {
+       struct nfs4_sequence_args       seq_args;
        const struct nfs_fh *           fh;
        const u32 *                     bitmask;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs4_pathconf_res {
-       struct nfs_pathconf            *pathconf;
        struct nfs4_sequence_res        seq_res;
+       struct nfs_pathconf            *pathconf;
 };
 
 struct nfs4_readdir_arg {
+       struct nfs4_sequence_args       seq_args;
        const struct nfs_fh *           fh;
        u64                             cookie;
        nfs4_verifier                   verifier;
@@ -953,21 +951,20 @@ struct nfs4_readdir_arg {
        unsigned int                    pgbase; /* zero-copy data */
        const u32 *                     bitmask;
        int                             plus;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs4_readdir_res {
+       struct nfs4_sequence_res        seq_res;
        nfs4_verifier                   verifier;
        unsigned int                    pgbase;
-       struct nfs4_sequence_res        seq_res;
 };
 
 struct nfs4_readlink {
+       struct nfs4_sequence_args       seq_args;
        const struct nfs_fh *           fh;
        unsigned int                    pgbase;
        unsigned int                    pglen;   /* zero-copy data */
        struct page **                  pages;   /* zero-copy data */
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs4_readlink_res {
@@ -993,28 +990,28 @@ struct nfs4_setclientid_res {
 };
 
 struct nfs4_statfs_arg {
+       struct nfs4_sequence_args       seq_args;
        const struct nfs_fh *           fh;
        const u32 *                     bitmask;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs4_statfs_res {
-       struct nfs_fsstat              *fsstat;
        struct nfs4_sequence_res        seq_res;
+       struct nfs_fsstat              *fsstat;
 };
 
 struct nfs4_server_caps_arg {
-       struct nfs_fh                  *fhandle;
        struct nfs4_sequence_args       seq_args;
+       struct nfs_fh                  *fhandle;
 };
 
 struct nfs4_server_caps_res {
+       struct nfs4_sequence_res        seq_res;
        u32                             attr_bitmask[3];
        u32                             acl_bitmask;
        u32                             has_links;
        u32                             has_symlinks;
        u32                             fh_expire_type;
-       struct nfs4_sequence_res        seq_res;
 };
 
 #define NFS4_PATHNAME_MAXCOMPONENTS 512
@@ -1040,16 +1037,16 @@ struct nfs4_fs_locations {
 };
 
 struct nfs4_fs_locations_arg {
+       struct nfs4_sequence_args       seq_args;
        const struct nfs_fh *dir_fh;
        const struct qstr *name;
        struct page *page;
        const u32 *bitmask;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs4_fs_locations_res {
-       struct nfs4_fs_locations       *fs_locations;
        struct nfs4_sequence_res        seq_res;
+       struct nfs4_fs_locations       *fs_locations;
 };
 
 struct nfs4_secinfo_oid {
@@ -1074,14 +1071,14 @@ struct nfs4_secinfo_flavors {
 };
 
 struct nfs4_secinfo_arg {
+       struct nfs4_sequence_args       seq_args;
        const struct nfs_fh             *dir_fh;
        const struct qstr               *name;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs4_secinfo_res {
-       struct nfs4_secinfo_flavors     *flavors;
        struct nfs4_sequence_res        seq_res;
+       struct nfs4_secinfo_flavors     *flavors;
 };
 
 #endif /* CONFIG_NFS_V4 */
@@ -1161,9 +1158,9 @@ struct nfs41_create_session_res {
 };
 
 struct nfs41_reclaim_complete_args {
+       struct nfs4_sequence_args       seq_args;
        /* In the future extend to include curr_fh for use with migration */
        unsigned char                   one_fs:1;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs41_reclaim_complete_res {
@@ -1173,28 +1170,28 @@ struct nfs41_reclaim_complete_res {
 #define SECINFO_STYLE_CURRENT_FH 0
 #define SECINFO_STYLE_PARENT 1
 struct nfs41_secinfo_no_name_args {
-       int                             style;
        struct nfs4_sequence_args       seq_args;
+       int                             style;
 };
 
 struct nfs41_test_stateid_args {
-       nfs4_stateid                    *stateid;
        struct nfs4_sequence_args       seq_args;
+       nfs4_stateid                    *stateid;
 };
 
 struct nfs41_test_stateid_res {
-       unsigned int                    status;
        struct nfs4_sequence_res        seq_res;
+       unsigned int                    status;
 };
 
 struct nfs41_free_stateid_args {
-       nfs4_stateid                    *stateid;
        struct nfs4_sequence_args       seq_args;
+       nfs4_stateid                    *stateid;
 };
 
 struct nfs41_free_stateid_res {
-       unsigned int                    status;
        struct nfs4_sequence_res        seq_res;
+       unsigned int                    status;
 };
 
 #else
index dc0c3cc3ada3f8ced03b7fb00b2b1772bb722034..b64f8eb0b973973107e8c55b44b06f2b8998cff9 100644 (file)
@@ -192,7 +192,6 @@ struct rpc_wait_queue {
        pid_t                   owner;                  /* process id of last task serviced */
        unsigned char           maxpriority;            /* maximum priority (0 if queue is not a priority queue) */
        unsigned char           priority;               /* current priority */
-       unsigned char           count;                  /* # task groups remaining serviced so far */
        unsigned char           nr;                     /* # tasks remaining for cookie */
        unsigned short          qlen;                   /* total # tasks waiting in queue */
        struct rpc_timer        timer_list;
index 909dc0c31aab224a9978f4b144c825d676fa65e0..6e5c824b040b75518cb89973261c08f9a7ff2384 100644 (file)
@@ -192,17 +192,23 @@ gss_fill_context(const void *p, const void *end, struct gss_cl_ctx *ctx, struct
        const void *q;
        unsigned int seclen;
        unsigned int timeout;
+       unsigned long now = jiffies;
        u32 window_size;
        int ret;
 
-       /* First unsigned int gives the lifetime (in seconds) of the cred */
+       /* First unsigned int gives the remaining lifetime in seconds of the
+        * credential - e.g. the remaining TGT lifetime for Kerberos or
+        * the -t value passed to GSSD.
+        */
        p = simple_get_bytes(p, end, &timeout, sizeof(timeout));
        if (IS_ERR(p))
                goto err;
        if (timeout == 0)
                timeout = GSSD_MIN_TIMEOUT;
-       ctx->gc_expiry = jiffies + (unsigned long)timeout * HZ * 3 / 4;
-       /* Sequence number window. Determines the maximum number of simultaneous requests */
+       ctx->gc_expiry = now + ((unsigned long)timeout * HZ);
+       /* Sequence number window. Determines the maximum number of
+        * simultaneous requests
+        */
        p = simple_get_bytes(p, end, &window_size, sizeof(window_size));
        if (IS_ERR(p))
                goto err;
@@ -237,9 +243,12 @@ gss_fill_context(const void *p, const void *end, struct gss_cl_ctx *ctx, struct
                p = ERR_PTR(ret);
                goto err;
        }
+       dprintk("RPC:       %s Success. gc_expiry %lu now %lu timeout %u\n",
+               __func__, ctx->gc_expiry, now, timeout);
        return q;
 err:
-       dprintk("RPC:       %s returning %ld\n", __func__, -PTR_ERR(p));
+       dprintk("RPC:       %s returns %ld gc_expiry %lu now %lu timeout %u\n",
+               __func__, -PTR_ERR(p), ctx->gc_expiry, now, timeout);
        return p;
 }
 
index a9c0bbccad6bfb787b4ff1630a1eb7a28918e634..890a29912d5ab3f39d156891d4844ede04d367e8 100644 (file)
@@ -59,7 +59,7 @@ static void xprt_free_allocation(struct rpc_rqst *req)
        struct xdr_buf *xbufp;
 
        dprintk("RPC:        free allocations for req= %p\n", req);
-       BUG_ON(test_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state));
+       WARN_ON_ONCE(test_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state));
        xbufp = &req->rq_private_buf;
        free_page((unsigned long)xbufp->head[0].iov_base);
        xbufp = &req->rq_snd_buf;
@@ -191,7 +191,9 @@ void xprt_destroy_backchannel(struct rpc_xprt *xprt, unsigned int max_reqs)
 
        dprintk("RPC:        destroy backchannel transport\n");
 
-       BUG_ON(max_reqs == 0);
+       if (max_reqs == 0)
+               goto out;
+
        spin_lock_bh(&xprt->bc_pa_lock);
        xprt_dec_alloc_count(xprt, max_reqs);
        list_for_each_entry_safe(req, tmp, &xprt->bc_pa_list, rq_bc_pa_list) {
@@ -202,6 +204,7 @@ void xprt_destroy_backchannel(struct rpc_xprt *xprt, unsigned int max_reqs)
        }
        spin_unlock_bh(&xprt->bc_pa_lock);
 
+out:
        dprintk("RPC:        backchannel list empty= %s\n",
                list_empty(&xprt->bc_pa_list) ? "true" : "false");
 }
@@ -255,7 +258,7 @@ void xprt_free_bc_request(struct rpc_rqst *req)
        dprintk("RPC:       free backchannel req=%p\n", req);
 
        smp_mb__before_clear_bit();
-       BUG_ON(!test_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state));
+       WARN_ON_ONCE(!test_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state));
        clear_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state);
        smp_mb__after_clear_bit();
 
index 0b2eb388cbda3c6d863557797ad786b992444931..15c7a8a1c24fd5c68b60b1903e4272eb6a293abd 100644 (file)
@@ -53,7 +53,7 @@ int bc_send(struct rpc_rqst *req)
        if (IS_ERR(task))
                ret = PTR_ERR(task);
        else {
-               BUG_ON(atomic_read(&task->tk_count) != 1);
+               WARN_ON_ONCE(atomic_read(&task->tk_count) != 1);
                ret = task->tk_status;
                rpc_put_task(task);
        }
index fc2f7aa4dca7aa04b3e7bc45cd39d47b744a1da4..9afa4393c21728cb5c0cbd675b6c25966fe99175 100644 (file)
@@ -775,11 +775,11 @@ static ssize_t cache_read(struct file *filp, char __user *buf, size_t count,
        if (rp->q.list.next == &cd->queue) {
                spin_unlock(&queue_lock);
                mutex_unlock(&inode->i_mutex);
-               BUG_ON(rp->offset);
+               WARN_ON_ONCE(rp->offset);
                return 0;
        }
        rq = container_of(rp->q.list.next, struct cache_request, q.list);
-       BUG_ON(rq->q.reader);
+       WARN_ON_ONCE(rq->q.reader);
        if (rp->offset == 0)
                rq->readers++;
        spin_unlock(&queue_lock);
index cdc7564b4512d7f79606bc87fb7726a668a9b9a0..822f020fa7f458e07a8e216e6609447daefb8747 100644 (file)
@@ -132,8 +132,10 @@ static struct dentry *rpc_setup_pipedir_sb(struct super_block *sb,
        int error;
 
        dir = rpc_d_lookup_sb(sb, dir_name);
-       if (dir == NULL)
+       if (dir == NULL) {
+               pr_info("RPC: pipefs directory doesn't exist: %s\n", dir_name);
                return dir;
+       }
        for (;;) {
                q.len = snprintf(name, sizeof(name), "clnt%x", (unsigned int)clntid++);
                name[sizeof(name) - 1] = '\0';
@@ -192,7 +194,8 @@ static int __rpc_clnt_handle_event(struct rpc_clnt *clnt, unsigned long event,
        case RPC_PIPEFS_MOUNT:
                dentry = rpc_setup_pipedir_sb(sb, clnt,
                                              clnt->cl_program->pipe_dir_name);
-               BUG_ON(dentry == NULL);
+               if (!dentry)
+                       return -ENOENT;
                if (IS_ERR(dentry))
                        return PTR_ERR(dentry);
                clnt->cl_dentry = dentry;
@@ -234,7 +237,7 @@ static struct rpc_clnt *rpc_get_client_for_event(struct net *net, int event)
        spin_lock(&sn->rpc_client_lock);
        list_for_each_entry(clnt, &sn->all_clients, cl_clients) {
                if (clnt->cl_program->pipe_dir_name == NULL)
-                       break;
+                       continue;
                if (rpc_clnt_skip_event(clnt, event))
                        continue;
                if (atomic_inc_not_zero(&clnt->cl_count) == 0)
@@ -607,6 +610,13 @@ 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",
                        clnt->cl_protname,
                        rcu_dereference(clnt->cl_xprt)->servername);
@@ -693,21 +703,19 @@ struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *old,
                                      const struct rpc_program *program,
                                      u32 vers)
 {
+       struct rpc_create_args args = {
+               .program        = program,
+               .prognumber     = program->number,
+               .version        = vers,
+               .authflavor     = old->cl_auth->au_flavor,
+               .client_name    = old->cl_principal,
+       };
        struct rpc_clnt *clnt;
-       const struct rpc_version *version;
        int err;
 
-       BUG_ON(vers >= program->nrvers || !program->version[vers]);
-       version = program->version[vers];
-       clnt = rpc_clone_client(old);
+       clnt = __rpc_clone_client(&args, old);
        if (IS_ERR(clnt))
                goto out;
-       clnt->cl_procinfo = version->procs;
-       clnt->cl_maxproc  = version->nrprocs;
-       clnt->cl_protname = program->name;
-       clnt->cl_prog     = program->number;
-       clnt->cl_vers     = version->number;
-       clnt->cl_stats    = program->stats;
        err = rpc_ping(clnt);
        if (err != 0) {
                rpc_shutdown_client(clnt);
@@ -832,7 +840,12 @@ int rpc_call_sync(struct rpc_clnt *clnt, const struct rpc_message *msg, int flag
        };
        int status;
 
-       BUG_ON(flags & RPC_TASK_ASYNC);
+       WARN_ON_ONCE(flags & RPC_TASK_ASYNC);
+       if (flags & RPC_TASK_ASYNC) {
+               rpc_release_calldata(task_setup_data.callback_ops,
+                       task_setup_data.callback_data);
+               return -EINVAL;
+       }
 
        task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task))
@@ -908,7 +921,7 @@ struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req,
 
        task->tk_action = call_bc_transmit;
        atomic_inc(&task->tk_count);
-       BUG_ON(atomic_read(&task->tk_count) != 2);
+       WARN_ON_ONCE(atomic_read(&task->tk_count) != 2);
        rpc_execute(task);
 
 out:
@@ -1368,6 +1381,7 @@ call_refreshresult(struct rpc_task *task)
                return;
        case -ETIMEDOUT:
                rpc_delay(task, 3*HZ);
+       case -EKEYEXPIRED:
        case -EAGAIN:
                status = -EACCES;
                if (!task->tk_cred_retry)
@@ -1654,7 +1668,6 @@ call_transmit(struct rpc_task *task)
        task->tk_action = call_transmit_status;
        /* Encode here so that rpcsec_gss can use correct sequence number. */
        if (rpc_task_need_encode(task)) {
-               BUG_ON(task->tk_rqstp->rq_bytes_sent != 0);
                rpc_xdr_encode(task);
                /* Did the encode result in an error condition? */
                if (task->tk_status != 0) {
@@ -1738,7 +1751,6 @@ call_bc_transmit(struct rpc_task *task)
 {
        struct rpc_rqst *req = task->tk_rqstp;
 
-       BUG_ON(task->tk_status != 0);
        task->tk_status = xprt_prepare_transmit(task);
        if (task->tk_status == -EAGAIN) {
                /*
@@ -1785,7 +1797,7 @@ call_bc_transmit(struct rpc_task *task)
                 * We were unable to reply and will have to drop the
                 * request.  The server should reconnect and retransmit.
                 */
-               BUG_ON(task->tk_status == -EAGAIN);
+               WARN_ON_ONCE(task->tk_status == -EAGAIN);
                printk(KERN_NOTICE "RPC: Could not send backchannel reply "
                        "error: %d\n", task->tk_status);
                break;
index 80f5dd23417d92c932be96225b8c65723774aa40..fd10981ea7921774e54f19808b1c9fa9964d4d3d 100644 (file)
@@ -1093,7 +1093,7 @@ void rpc_put_sb_net(const struct net *net)
 {
        struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
 
-       BUG_ON(sn->pipefs_sb == NULL);
+       WARN_ON(sn->pipefs_sb == NULL);
        mutex_unlock(&sn->pipefs_sb_lock);
 }
 EXPORT_SYMBOL_GPL(rpc_put_sb_net);
@@ -1152,14 +1152,19 @@ static void rpc_kill_sb(struct super_block *sb)
        struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
 
        mutex_lock(&sn->pipefs_sb_lock);
+       if (sn->pipefs_sb != sb) {
+               mutex_unlock(&sn->pipefs_sb_lock);
+               goto out;
+       }
        sn->pipefs_sb = NULL;
        mutex_unlock(&sn->pipefs_sb_lock);
-       put_net(net);
        dprintk("RPC:       sending pipefs UMOUNT notification for net %p%s\n",
                net, NET_NAME(net));
        blocking_notifier_call_chain(&rpc_pipefs_notifier_list,
                                           RPC_PIPEFS_UMOUNT,
                                           sb);
+       put_net(net);
+out:
        kill_litter_super(sb);
 }
 
index a70acae496e44d6c872ba7c93d4d9ce56c2f7f00..411f332de0b316b2ae33bda6e9385a498bd7fabd 100644 (file)
@@ -884,7 +884,10 @@ static void encode_rpcb_string(struct xdr_stream *xdr, const char *string,
        u32 len;
 
        len = strlen(string);
-       BUG_ON(len > maxstrlen);
+       WARN_ON_ONCE(len > maxstrlen);
+       if (len > maxstrlen)
+               /* truncate and hope for the best */
+               len = maxstrlen;
        p = xdr_reserve_space(xdr, 4 + len);
        xdr_encode_opaque(p, string, len);
 }
index 6357fcb00c7e2046f8acb901d7005429d23158cd..d17a704aaf5f2251674b3fa23421fa087b8ddd14 100644 (file)
@@ -98,6 +98,23 @@ __rpc_add_timer(struct rpc_wait_queue *queue, struct rpc_task *task)
        list_add(&task->u.tk_wait.timer_list, &queue->timer_list.list);
 }
 
+static void rpc_set_waitqueue_priority(struct rpc_wait_queue *queue, int priority)
+{
+       queue->priority = priority;
+}
+
+static void rpc_set_waitqueue_owner(struct rpc_wait_queue *queue, pid_t pid)
+{
+       queue->owner = pid;
+       queue->nr = RPC_BATCH_COUNT;
+}
+
+static void rpc_reset_waitqueue_priority(struct rpc_wait_queue *queue)
+{
+       rpc_set_waitqueue_priority(queue, queue->maxpriority);
+       rpc_set_waitqueue_owner(queue, 0);
+}
+
 /*
  * Add new request to a priority queue.
  */
@@ -109,9 +126,11 @@ static void __rpc_add_wait_queue_priority(struct rpc_wait_queue *queue,
        struct rpc_task *t;
 
        INIT_LIST_HEAD(&task->u.tk_wait.links);
-       q = &queue->tasks[queue_priority];
        if (unlikely(queue_priority > queue->maxpriority))
-               q = &queue->tasks[queue->maxpriority];
+               queue_priority = queue->maxpriority;
+       if (queue_priority > queue->priority)
+               rpc_set_waitqueue_priority(queue, queue_priority);
+       q = &queue->tasks[queue_priority];
        list_for_each_entry(t, q, u.tk_wait.list) {
                if (t->tk_owner == task->tk_owner) {
                        list_add_tail(&task->u.tk_wait.list, &t->u.tk_wait.links);
@@ -133,7 +152,9 @@ static void __rpc_add_wait_queue(struct rpc_wait_queue *queue,
                struct rpc_task *task,
                unsigned char queue_priority)
 {
-       BUG_ON (RPC_IS_QUEUED(task));
+       WARN_ON_ONCE(RPC_IS_QUEUED(task));
+       if (RPC_IS_QUEUED(task))
+               return;
 
        if (RPC_IS_PRIORITY(queue))
                __rpc_add_wait_queue_priority(queue, task, queue_priority);
@@ -178,24 +199,6 @@ static void __rpc_remove_wait_queue(struct rpc_wait_queue *queue, struct rpc_tas
                        task->tk_pid, queue, rpc_qname(queue));
 }
 
-static inline void rpc_set_waitqueue_priority(struct rpc_wait_queue *queue, int priority)
-{
-       queue->priority = priority;
-       queue->count = 1 << (priority * 2);
-}
-
-static inline void rpc_set_waitqueue_owner(struct rpc_wait_queue *queue, pid_t pid)
-{
-       queue->owner = pid;
-       queue->nr = RPC_BATCH_COUNT;
-}
-
-static inline void rpc_reset_waitqueue_priority(struct rpc_wait_queue *queue)
-{
-       rpc_set_waitqueue_priority(queue, queue->maxpriority);
-       rpc_set_waitqueue_owner(queue, 0);
-}
-
 static void __rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qname, unsigned char nr_queues)
 {
        int i;
@@ -334,7 +337,7 @@ static void __rpc_sleep_on_priority(struct rpc_wait_queue *q,
 
        __rpc_add_wait_queue(q, task, queue_priority);
 
-       BUG_ON(task->tk_callback != NULL);
+       WARN_ON_ONCE(task->tk_callback != NULL);
        task->tk_callback = action;
        __rpc_add_timer(q, task);
 }
@@ -343,7 +346,12 @@ void rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
                                rpc_action action)
 {
        /* We shouldn't ever put an inactive task to sleep */
-       BUG_ON(!RPC_IS_ACTIVATED(task));
+       WARN_ON_ONCE(!RPC_IS_ACTIVATED(task));
+       if (!RPC_IS_ACTIVATED(task)) {
+               task->tk_status = -EIO;
+               rpc_put_task_async(task);
+               return;
+       }
 
        /*
         * Protect the queue operations.
@@ -358,7 +366,12 @@ void rpc_sleep_on_priority(struct rpc_wait_queue *q, struct rpc_task *task,
                rpc_action action, int priority)
 {
        /* We shouldn't ever put an inactive task to sleep */
-       BUG_ON(!RPC_IS_ACTIVATED(task));
+       WARN_ON_ONCE(!RPC_IS_ACTIVATED(task));
+       if (!RPC_IS_ACTIVATED(task)) {
+               task->tk_status = -EIO;
+               rpc_put_task_async(task);
+               return;
+       }
 
        /*
         * Protect the queue operations.
@@ -367,6 +380,7 @@ void rpc_sleep_on_priority(struct rpc_wait_queue *q, struct rpc_task *task,
        __rpc_sleep_on_priority(q, task, action, priority - RPC_PRIORITY_LOW);
        spin_unlock_bh(&q->lock);
 }
+EXPORT_SYMBOL_GPL(rpc_sleep_on_priority);
 
 /**
  * __rpc_do_wake_up_task - wake up a single rpc_task
@@ -451,8 +465,7 @@ static struct rpc_task *__rpc_find_next_queued_priority(struct rpc_wait_queue *q
                /*
                 * Check if we need to switch queues.
                 */
-               if (--queue->count)
-                       goto new_owner;
+               goto new_owner;
        }
 
        /*
@@ -697,7 +710,9 @@ static void __rpc_execute(struct rpc_task *task)
        dprintk("RPC: %5u __rpc_execute flags=0x%x\n",
                        task->tk_pid, task->tk_flags);
 
-       BUG_ON(RPC_IS_QUEUED(task));
+       WARN_ON_ONCE(RPC_IS_QUEUED(task));
+       if (RPC_IS_QUEUED(task))
+               return;
 
        for (;;) {
                void (*do_action)(struct rpc_task *);
@@ -981,7 +996,7 @@ static void rpc_release_task(struct rpc_task *task)
 {
        dprintk("RPC: %5u release task\n", task->tk_pid);
 
-       BUG_ON (RPC_IS_QUEUED(task));
+       WARN_ON_ONCE(RPC_IS_QUEUED(task));
 
        rpc_release_resources_task(task);
 
index 3ee7461926d8a01318ed2876e37651506c6b3c4b..dfa4ba69ff4503748ed22bad836643540221af39 100644 (file)
@@ -324,7 +324,9 @@ svc_pool_map_set_cpumask(struct task_struct *task, unsigned int pidx)
         * The caller checks for sv_nrpools > 1, which
         * implies that we've been initialized.
         */
-       BUG_ON(m->count == 0);
+       WARN_ON_ONCE(m->count == 0);
+       if (m->count == 0)
+               return;
 
        switch (m->mode) {
        case SVC_POOL_PERCPU:
@@ -585,7 +587,9 @@ svc_init_buffer(struct svc_rqst *rqstp, unsigned int size, int node)
                                       * We assume one is at most one page
                                       */
        arghi = 0;
-       BUG_ON(pages > RPCSVC_MAXPAGES);
+       WARN_ON_ONCE(pages > RPCSVC_MAXPAGES);
+       if (pages > RPCSVC_MAXPAGES)
+               pages = RPCSVC_MAXPAGES;
        while (pages) {
                struct page *p = alloc_pages_node(node, GFP_KERNEL, 0);
                if (!p)
@@ -946,7 +950,9 @@ int svc_register(const struct svc_serv *serv, struct net *net,
        unsigned int            i;
        int                     error = 0;
 
-       BUG_ON(proto == 0 && port == 0);
+       WARN_ON_ONCE(proto == 0 && port == 0);
+       if (proto == 0 && port == 0)
+               return -EINVAL;
 
        for (progp = serv->sv_program; progp; progp = progp->pg_next) {
                for (i = 0; i < progp->pg_nvers; i++) {
index 194d865fae722216b71a7e78c84328b2d70b1b9b..b8e47fac731557bdde5bc5d96250e30a822f6c6c 100644 (file)
@@ -218,7 +218,9 @@ static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl,
  */
 static void svc_xprt_received(struct svc_xprt *xprt)
 {
-       BUG_ON(!test_bit(XPT_BUSY, &xprt->xpt_flags));
+       WARN_ON_ONCE(!test_bit(XPT_BUSY, &xprt->xpt_flags));
+       if (!test_bit(XPT_BUSY, &xprt->xpt_flags))
+               return;
        /* As soon as we clear busy, the xprt could be closed and
         * 'put', so we need a reference to call svc_xprt_enqueue with:
         */
@@ -577,7 +579,10 @@ int svc_alloc_arg(struct svc_rqst *rqstp)
 
        /* now allocate needed pages.  If we get a failure, sleep briefly */
        pages = (serv->sv_max_mesg + PAGE_SIZE) / PAGE_SIZE;
-       BUG_ON(pages >= RPCSVC_MAXPAGES);
+       WARN_ON_ONCE(pages >= RPCSVC_MAXPAGES);
+       if (pages >= RPCSVC_MAXPAGES)
+               /* use as many pages as possible */
+               pages = RPCSVC_MAXPAGES - 1;
        for (i = 0; i < pages ; i++)
                while (rqstp->rq_pages[i] == NULL) {
                        struct page *p = alloc_page(GFP_KERNEL);
@@ -926,7 +931,7 @@ static void svc_delete_xprt(struct svc_xprt *xprt)
        spin_lock_bh(&serv->sv_lock);
        if (!test_and_set_bit(XPT_DETACHED, &xprt->xpt_flags))
                list_del_init(&xprt->xpt_list);
-       BUG_ON(!list_empty(&xprt->xpt_ready));
+       WARN_ON_ONCE(!list_empty(&xprt->xpt_ready));
        if (test_bit(XPT_TEMP, &xprt->xpt_flags))
                serv->sv_tmpcnt--;
        spin_unlock_bh(&serv->sv_lock);
index 03827cef1fa783174409e23b2241bba903809e3a..cc3020d1678905a9f6930cab28753dfbbe99713e 100644 (file)
@@ -84,7 +84,11 @@ static struct lock_class_key svc_slock_key[2];
 static void svc_reclassify_socket(struct socket *sock)
 {
        struct sock *sk = sock->sk;
-       BUG_ON(sock_owned_by_user(sk));
+
+       WARN_ON_ONCE(sock_owned_by_user(sk));
+       if (sock_owned_by_user(sk))
+               return;
+
        switch (sk->sk_family) {
        case AF_INET:
                sock_lock_init_class_and_name(sk, "slock-AF_INET-NFSD",
index 08f50afd5f2a1d9dedc53ed1157d94be7e1e964d..56055632f1518323f68be9e8bcd3e59d7441be2c 100644 (file)
@@ -318,7 +318,10 @@ xdr_shrink_bufhead(struct xdr_buf *buf, size_t len)
 
        tail = buf->tail;
        head = buf->head;
-       BUG_ON (len > head->iov_len);
+
+       WARN_ON_ONCE(len > head->iov_len);
+       if (len > head->iov_len)
+               len = head->iov_len;
 
        /* Shift the tail first */
        if (tail->iov_len != 0) {
index 75853cabf4c97b153873eda4ce67cd228581fd15..68b0a81c31d5665314e86c84a254b672c8010dd0 100644 (file)
@@ -1746,7 +1746,6 @@ static inline void xs_reclassify_socketu(struct socket *sock)
 {
        struct sock *sk = sock->sk;
 
-       BUG_ON(sock_owned_by_user(sk));
        sock_lock_init_class_and_name(sk, "slock-AF_LOCAL-RPC",
                &xs_slock_key[1], "sk_lock-AF_LOCAL-RPC", &xs_key[1]);
 }
@@ -1755,7 +1754,6 @@ static inline void xs_reclassify_socket4(struct socket *sock)
 {
        struct sock *sk = sock->sk;
 
-       BUG_ON(sock_owned_by_user(sk));
        sock_lock_init_class_and_name(sk, "slock-AF_INET-RPC",
                &xs_slock_key[0], "sk_lock-AF_INET-RPC", &xs_key[0]);
 }
@@ -1764,13 +1762,16 @@ static inline void xs_reclassify_socket6(struct socket *sock)
 {
        struct sock *sk = sock->sk;
 
-       BUG_ON(sock_owned_by_user(sk));
        sock_lock_init_class_and_name(sk, "slock-AF_INET6-RPC",
                &xs_slock_key[1], "sk_lock-AF_INET6-RPC", &xs_key[1]);
 }
 
 static inline void xs_reclassify_socket(int family, struct socket *sock)
 {
+       WARN_ON_ONCE(sock_owned_by_user(sock->sk));
+       if (sock_owned_by_user(sock->sk))
+               return;
+
        switch (family) {
        case AF_LOCAL:
                xs_reclassify_socketu(sock);
@@ -1901,6 +1902,10 @@ static void xs_local_setup_socket(struct work_struct *work)
                dprintk("RPC:       xprt %p: socket %s does not exist\n",
                                xprt, xprt->address_strings[RPC_DISPLAY_ADDR]);
                break;
+       case -ECONNREFUSED:
+               dprintk("RPC:       xprt %p: connection refused for %s\n",
+                               xprt, xprt->address_strings[RPC_DISPLAY_ADDR]);
+               break;
        default:
                printk(KERN_ERR "%s: unhandled error (%d) connecting to %s\n",
                                __func__, -status,
@@ -2329,9 +2334,11 @@ static void *bc_malloc(struct rpc_task *task, size_t size)
        struct page *page;
        struct rpc_buffer *buf;
 
-       BUG_ON(size > PAGE_SIZE - sizeof(struct rpc_buffer));
-       page = alloc_page(GFP_KERNEL);
+       WARN_ON_ONCE(size > PAGE_SIZE - sizeof(struct rpc_buffer));
+       if (size > PAGE_SIZE - sizeof(struct rpc_buffer))
+               return NULL;
 
+       page = alloc_page(GFP_KERNEL);
        if (!page)
                return NULL;
 
@@ -2393,7 +2400,6 @@ static int bc_send_request(struct rpc_task *task)
 {
        struct rpc_rqst *req = task->tk_rqstp;
        struct svc_xprt *xprt;
-       struct svc_sock         *svsk;
        u32                     len;
 
        dprintk("sending request with xid: %08x\n", ntohl(req->rq_xid));
@@ -2401,7 +2407,6 @@ static int bc_send_request(struct rpc_task *task)
         * Get the server socket associated with this callback xprt
         */
        xprt = req->rq_xprt->bc_xprt;
-       svsk = container_of(xprt, struct svc_sock, sk_xprt);
 
        /*
         * Grab the mutex to serialize data as the connection is shared