Merge branch 'bugfixes' into nfs-for-next
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Tue, 11 Dec 2012 14:16:26 +0000 (09:16 -0500)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Tue, 11 Dec 2012 14:16:26 +0000 (09:16 -0500)
46 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/inode.c
fs/nfs/internal.h
fs/nfs/mount_clnt.c
fs/nfs/nfs2xdr.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/nfs4xdr.c
fs/nfs/objlayout/objlayout.c
fs/nfs/pnfs.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/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..c285e0a117e4a577b7bc930c058c7db5faf6d99d 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);
        }
@@ -1061,10 +1061,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 6fa01aea24889cae08385e5bfe0aab16c742adc8..117183b1ee09e990662ce61a029ffc3b1f88d7b7 100644 (file)
@@ -112,8 +112,8 @@ 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..fb994471bd32f7debfc42033c4e4e1a18b4d6bd9 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,
@@ -474,18 +451,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 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 ea4e36241044e8bd8007b006bc784211190af5a4..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;
 }
 
@@ -332,6 +319,9 @@ 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..1e42413fab8f3c628e19c34f2fba17248699c586 100644 (file)
@@ -35,6 +35,7 @@
 
 #include <linux/sunrpc/metrics.h>
 
+#include "nfs4session.h"
 #include "internal.h"
 #include "delegation.h"
 #include "nfs4filelayout.h"
@@ -306,12 +307,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 +407,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 +446,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 +507,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 +532,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 +547,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 +571,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 +900,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 +930,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 +1178,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 05e5f6f9f2b80b22fa306d33fcdd06c6540725f3..92bd799eee012bf3eab59105a28816e631c6f58e 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;
@@ -397,97 +379,47 @@ 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)
 {
+       struct nfs4_session *session;
+       struct nfs4_slot *slot;
        unsigned long timestamp;
        struct nfs_client *clp;
 
@@ -504,31 +436,35 @@ static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *
        if (!RPC_WAS_SENT(task))
                goto out;
 
+       slot = res->sr_slot;
+       session = slot->table->session;
+
        /* 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;
+               ++slot->seq_nr;
+               timestamp = slot->renewal_time;
+               clp = session->clp;
                do_renew_lease(clp, 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 -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;
        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. */
@@ -545,55 +481,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 +509,58 @@ 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_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 +572,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 +596,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 +615,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 +635,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 +645,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 +664,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 +682,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)
@@ -1574,20 +1461,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 +1527,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 +1556,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 +1662,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 +2137,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 +2155,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 +2387,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 +2893,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 +2924,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 +3213,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 +3228,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 +3416,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 +3480,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)
@@ -4298,11 +4143,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 */
 
@@ -4548,6 +4392,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;
@@ -4556,8 +4401,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 = {
@@ -4701,8 +4544,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;
@@ -4712,20 +4556,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)
@@ -4780,12 +4616,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) {
@@ -4828,15 +4658,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);
@@ -5362,7 +5192,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)) {
@@ -5574,20 +5403,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__);
 }
 
@@ -5649,6 +5474,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);
 
@@ -5663,145 +5489,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,
@@ -5814,8 +5501,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;
@@ -5924,10 +5611,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++;
        }
@@ -5996,83 +5682,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.
  */
@@ -6138,9 +5747,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 = {
@@ -6149,7 +5756,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 = {
@@ -6171,6 +5780,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;
@@ -6186,7 +5797,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
@@ -6200,7 +5811,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;
@@ -6229,13 +5840,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)
@@ -6312,6 +5920,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;
@@ -6335,6 +5944,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
@@ -6342,16 +5952,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)
@@ -6364,7 +5972,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) {
@@ -6515,10 +6123,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)
@@ -6528,7 +6136,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);
@@ -6677,11 +6285,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
@@ -6690,7 +6299,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 */
@@ -6878,7 +6487,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;
@@ -6925,8 +6536,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;
 }
@@ -7046,7 +6658,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..ed5aa9f
--- /dev/null
@@ -0,0 +1,542 @@
+/*
+ * 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->renewal_time = jiffies;
+       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 = &(*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->renewal_time = jiffies;
+       slot->generation = tbl->generation;
+       args->sa_slot = slot;
+       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;
+       }
+}
+
+/* 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)
+{
+       unsigned int max_slotid;
+
+       if (tbl->target_highest_slotid == target_highest_slotid)
+               return;
+       tbl->target_highest_slotid = target_highest_slotid;
+       tbl->generation++;
+
+       max_slotid = min(NFS4_MAX_SLOT_TABLE - 1, tbl->target_highest_slotid);
+       tbl->max_slotid = max_slotid;
+       nfs41_wake_slot_table(tbl);
+}
+
+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;
+       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);
+       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..04f834c
--- /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;
+       unsigned long           renewal_time;
+       u32                     slot_nr;
+       u32                     seq_nr;
+};
+
+/* 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..78e90a80fc3abf25c013432c03f740eb4856aaef 100644 (file)
@@ -57,6 +57,7 @@
 #include "callback.h"
 #include "delegation.h"
 #include "internal.h"
+#include "nfs4session.h"
 #include "pnfs.h"
 #include "netns.h"
 
@@ -254,24 +255,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 +307,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 +1089,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 +1211,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
@@ -1907,14 +1943,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 +2069,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 +2099,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 +2130,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 +2150,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 142aacb924590320adaca695b2152c9585195222..26b143920433e628456476e0d1b708b8fc395d43 100644 (file)
@@ -56,6 +56,7 @@
 
 #include "nfs4_fs.h"
 #include "internal.h"
+#include "nfs4session.h"
 #include "pnfs.h"
 #include "netns.h"
 
@@ -938,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);
@@ -957,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);
 }
 
@@ -1405,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);
        }
@@ -1623,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);
@@ -1837,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);
 
@@ -1862,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 */
@@ -2029,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;
 }
@@ -5511,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);
@@ -5530,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;
@@ -5549,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 652d3f7176a98fcc4e70e6f5e3d812e4b3d90b83..e12cea4b36a53a448d57c72bcfd4298924597f79 100644 (file)
@@ -64,6 +64,7 @@
 #include "iostat.h"
 #include "internal.h"
 #include "fscache.h"
+#include "nfs4session.h"
 #include "pnfs.h"
 #include "nfs.h"
 
index eecd8b879afe85285c408e95954f30d7c55cd04f..f608ca606b2b19f32f9bcbc813854e9c6aa50a0b 100644 (file)
@@ -239,21 +239,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 +312,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 +448,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);
@@ -1727,7 +1722,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);
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..a55abd499c2110ea8810f07be057020fb00e5bc4 100644 (file)
@@ -185,23 +185,19 @@ 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 */
        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 +205,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 +224,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 +251,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 +296,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 +326,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 +347,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 +365,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 +388,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 +413,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 +424,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 +464,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 +488,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 +511,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 +523,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 +622,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 +643,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 +828,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 +860,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 +950,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 +989,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 +1036,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 +1070,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 +1157,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 +1169,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 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..c69e199b10829d2bc88ca2a435014aa66e0cbbb9 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;
@@ -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:
@@ -1654,7 +1667,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 +1750,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 +1796,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 e659def7774295794511679c75440ae971216bbf..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);
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..6db26e5538fb4cf483b04a82bea18a21be4a0f81 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);
@@ -2329,9 +2330,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;