]> rtime.felk.cvut.cz Git - linux-imx.git/blobdiff - fs/nfs/nfs4proc.c
NFS: start printks w/ NFS: even if __func__ shown
[linux-imx.git] / fs / nfs / nfs4proc.c
index d9f4d78c34131264ba1b58bd36b1ec3cd35e5d6d..482ed97189c9c292f205e21fd270bc0336c84146 100644 (file)
 #include <linux/namei.h>
 #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 "nfs4_fs.h"
 #include "delegation.h"
@@ -80,8 +82,8 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
                            struct nfs_fattr *fattr, struct iattr *sattr,
                            struct nfs4_state *state);
 #ifdef CONFIG_NFS_V4_1
-static int nfs41_test_stateid(struct nfs_server *, struct nfs4_state *);
-static int nfs41_free_stateid(struct nfs_server *, struct nfs4_state *);
+static int nfs41_test_stateid(struct nfs_server *, nfs4_stateid *);
+static int nfs41_free_stateid(struct nfs_server *, nfs4_stateid *);
 #endif
 /* Prevent leaks of NFSv4 errors into userland */
 static int nfs4_map_errors(int err)
@@ -243,7 +245,7 @@ static int nfs4_delay(struct rpc_clnt *clnt, long *timeout)
                *timeout = NFS4_POLL_RETRY_MIN;
        if (*timeout > NFS4_POLL_RETRY_MAX)
                *timeout = NFS4_POLL_RETRY_MAX;
-       schedule_timeout_killable(*timeout);
+       freezable_schedule_timeout_killable(*timeout);
        if (fatal_signal_pending(current))
                res = -ERESTARTSYS;
        *timeout <<= 1;
@@ -363,9 +365,8 @@ static void renew_lease(const struct nfs_server *server, unsigned long timestamp
  * Must be called while holding tbl->slot_tbl_lock
  */
 static void
-nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *free_slot)
+nfs4_free_slot(struct nfs4_slot_table *tbl, u8 free_slotid)
 {
-       int free_slotid = free_slot - tbl->slots;
        int slotid = free_slotid;
 
        BUG_ON(slotid < 0 || slotid >= NFS4_MAX_SLOT_TABLE);
@@ -384,17 +385,20 @@ nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *free_slot)
                free_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)
 {
-       struct rpc_task *task;
-
        if (!test_bit(NFS4_SESSION_DRAINING, &ses->session_state)) {
-               task = rpc_wake_up_next(&ses->fc_slot_table.slot_tbl_waitq);
-               if (task)
-                       rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
+               rpc_wake_up_first(&ses->fc_slot_table.slot_tbl_waitq,
+                               nfs4_set_task_privileged, NULL);
                return;
        }
 
@@ -430,7 +434,7 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
        }
 
        spin_lock(&tbl->slot_tbl_lock);
-       nfs4_free_slot(tbl, res->sr_slot);
+       nfs4_free_slot(tbl, res->sr_slot - tbl->slots);
        nfs4_check_drain_fc_complete(res->sr_session);
        spin_unlock(&tbl->slot_tbl_lock);
        res->sr_slot = NULL;
@@ -533,10 +537,20 @@ out:
        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_cache_this = 0;
+       if (cache_reply)
+               args->sa_cache_this = 1;
+       res->sr_session = NULL;
+       res->sr_slot = NULL;
+}
+
 int nfs41_setup_sequence(struct nfs4_session *session,
                                struct nfs4_sequence_args *args,
                                struct nfs4_sequence_res *res,
-                               int cache_reply,
                                struct rpc_task *task)
 {
        struct nfs4_slot *slot;
@@ -553,13 +567,10 @@ int nfs41_setup_sequence(struct nfs4_session *session,
        spin_lock(&tbl->slot_tbl_lock);
        if (test_bit(NFS4_SESSION_DRAINING, &session->session_state) &&
            !rpc_task_has_priority(task, RPC_PRIORITY_PRIVILEGED)) {
-               /*
-                * The state manager will wait until the slot table is empty.
-                * Schedule the reset thread
-                */
+               /* 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 Schedule Session Reset\n", __func__);
+               dprintk("%s session is draining\n", __func__);
                return -EAGAIN;
        }
 
@@ -584,7 +595,6 @@ int nfs41_setup_sequence(struct nfs4_session *session,
        slot = tbl->slots + slotid;
        args->sa_session = session;
        args->sa_slotid = slotid;
-       args->sa_cache_this = cache_reply;
 
        dprintk("<-- %s slotid=%d seqid=%d\n", __func__, slotid, slot->seq_nr);
 
@@ -604,24 +614,19 @@ EXPORT_SYMBOL_GPL(nfs41_setup_sequence);
 int nfs4_setup_sequence(const struct nfs_server *server,
                        struct nfs4_sequence_args *args,
                        struct nfs4_sequence_res *res,
-                       int cache_reply,
                        struct rpc_task *task)
 {
        struct nfs4_session *session = nfs4_get_session(server);
        int ret = 0;
 
-       if (session == NULL) {
-               args->sa_session = NULL;
-               res->sr_session = NULL;
+       if (session == NULL)
                goto out;
-       }
 
        dprintk("--> %s clp %p session %p sr_slot %td\n",
                __func__, session->clp, session, res->sr_slot ?
                        res->sr_slot - session->fc_slot_table.slots : -1);
 
-       ret = nfs41_setup_sequence(session, args, res, cache_reply,
-                                  task);
+       ret = nfs41_setup_sequence(session, args, res, task);
 out:
        dprintk("<-- %s status=%d\n", __func__, ret);
        return ret;
@@ -631,7 +636,6 @@ struct nfs41_call_sync_data {
        const struct nfs_server *seq_server;
        struct nfs4_sequence_args *seq_args;
        struct nfs4_sequence_res *seq_res;
-       int cache_reply;
 };
 
 static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata)
@@ -641,7 +645,7 @@ static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata)
        dprintk("--> %s data->seq_server %p\n", __func__, data->seq_server);
 
        if (nfs4_setup_sequence(data->seq_server, data->seq_args,
-                               data->seq_res, data->cache_reply, task))
+                               data->seq_res, task))
                return;
        rpc_call_start(task);
 }
@@ -674,7 +678,6 @@ static int nfs4_call_sync_sequence(struct rpc_clnt *clnt,
                                   struct rpc_message *msg,
                                   struct nfs4_sequence_args *args,
                                   struct nfs4_sequence_res *res,
-                                  int cache_reply,
                                   int privileged)
 {
        int ret;
@@ -683,7 +686,6 @@ static int nfs4_call_sync_sequence(struct rpc_clnt *clnt,
                .seq_server = server,
                .seq_args = args,
                .seq_res = res,
-               .cache_reply = cache_reply,
        };
        struct rpc_task_setup task_setup = {
                .rpc_client = clnt,
@@ -692,7 +694,6 @@ static int nfs4_call_sync_sequence(struct rpc_clnt *clnt,
                .callback_data = &data
        };
 
-       res->sr_slot = NULL;
        if (privileged)
                task_setup.callback_ops = &nfs41_call_priv_sync_ops;
        task = rpc_run_task(&task_setup);
@@ -712,10 +713,17 @@ int _nfs4_call_sync_session(struct rpc_clnt *clnt,
                            struct nfs4_sequence_res *res,
                            int cache_reply)
 {
-       return nfs4_call_sync_sequence(clnt, server, msg, args, res, cache_reply, 0);
+       nfs41_init_sequence(args, res, cache_reply);
+       return nfs4_call_sync_sequence(clnt, server, msg, args, res, 0);
 }
 
 #else
+static inline
+void nfs41_init_sequence(struct nfs4_sequence_args *args,
+               struct nfs4_sequence_res *res, int cache_reply)
+{
+}
+
 static int nfs4_sequence_done(struct rpc_task *task,
                               struct nfs4_sequence_res *res)
 {
@@ -730,7 +738,7 @@ int _nfs4_call_sync(struct rpc_clnt *clnt,
                    struct nfs4_sequence_res *res,
                    int cache_reply)
 {
-       args->sa_session = res->sr_session = NULL;
+       nfs41_init_sequence(args, res, cache_reply);
        return rpc_call_sync(clnt, msg, 0);
 }
 
@@ -764,6 +772,8 @@ struct nfs4_opendata {
        struct nfs_openres o_res;
        struct nfs_open_confirmargs c_arg;
        struct nfs_open_confirmres c_res;
+       struct nfs4_string owner_name;
+       struct nfs4_string group_name;
        struct nfs_fattr f_attr;
        struct nfs_fattr dir_attr;
        struct dentry *dir;
@@ -787,6 +797,7 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p)
        p->o_res.server = p->o_arg.server;
        nfs_fattr_init(&p->f_attr);
        nfs_fattr_init(&p->dir_attr);
+       nfs_fattr_init_names(&p->f_attr, &p->owner_name, &p->group_name);
 }
 
 static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
@@ -814,12 +825,13 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
        p->o_arg.open_flags = flags;
        p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE);
        p->o_arg.clientid = server->nfs_client->cl_clientid;
-       p->o_arg.id = sp->so_owner_id.id;
+       p->o_arg.id = sp->so_seqid.owner_id;
        p->o_arg.name = &dentry->d_name;
        p->o_arg.server = server;
        p->o_arg.bitmask = server->attr_bitmask;
+       p->o_arg.dir_bitmask = server->cache_consistency_bitmask;
        p->o_arg.claim = NFS4_OPEN_CLAIM_NULL;
-       if (flags & O_CREAT) {
+       if (attrs != NULL && attrs->ia_valid != 0) {
                u32 *s;
 
                p->o_arg.u.attrs = &p->attrs;
@@ -854,6 +866,7 @@ static void nfs4_opendata_free(struct kref *kref)
        dput(p->dir);
        dput(p->dentry);
        nfs_sb_deactive(sb);
+       nfs_fattr_free_names(&p->f_attr);
        kfree(p);
 }
 
@@ -875,7 +888,7 @@ static int can_open_cached(struct nfs4_state *state, fmode_t mode, int open_mode
 {
        int ret = 0;
 
-       if (open_mode & O_EXCL)
+       if (open_mode & (O_EXCL|O_TRUNC))
                goto out;
        switch (mode & (FMODE_READ|FMODE_WRITE)) {
                case FMODE_READ:
@@ -1023,7 +1036,7 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)
        struct nfs4_state *state = opendata->state;
        struct nfs_inode *nfsi = NFS_I(state->inode);
        struct nfs_delegation *delegation;
-       int open_mode = opendata->o_arg.open_flags & O_EXCL;
+       int open_mode = opendata->o_arg.open_flags & (O_EXCL|O_TRUNC);
        fmode_t fmode = opendata->o_arg.fmode;
        nfs4_stateid stateid;
        int ret = -EAGAIN;
@@ -1437,7 +1450,7 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
                rcu_read_unlock();
        }
        /* Update sequence id. */
-       data->o_arg.id = sp->so_owner_id.id;
+       data->o_arg.id = sp->so_seqid.owner_id;
        data->o_arg.clientid = sp->so_server->nfs_client->cl_clientid;
        if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) {
                task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR];
@@ -1446,7 +1459,7 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
        data->timestamp = jiffies;
        if (nfs4_setup_sequence(data->o_arg.server,
                                &data->o_arg.seq_args,
-                               &data->o_res.seq_res, 1, task))
+                               &data->o_res.seq_res, task))
                return;
        rpc_call_start(task);
        return;
@@ -1548,6 +1561,7 @@ static int nfs4_run_open_task(struct nfs4_opendata *data, int isrecover)
        };
        int status;
 
+       nfs41_init_sequence(&o_arg->seq_args, &o_res->seq_res, 1);
        kref_get(&data->kref);
        data->rpc_done = 0;
        data->rpc_status = 0;
@@ -1578,6 +1592,8 @@ static int _nfs4_recover_proc_open(struct nfs4_opendata *data)
        if (status != 0 || !data->rpc_done)
                return status;
 
+       nfs_fattr_map_and_free_names(NFS_SERVER(dir), &data->f_attr);
+
        nfs_refresh_inode(dir, o_res->dir_attr);
 
        if (o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) {
@@ -1610,6 +1626,8 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
                return status;
        }
 
+       nfs_fattr_map_and_free_names(server, &data->f_attr);
+
        if (o_arg->open_flags & O_CREAT) {
                update_changeattr(dir, &o_res->cinfo);
                nfs_post_op_update_inode(dir, o_res->dir_attr);
@@ -1705,15 +1723,32 @@ static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *sta
 }
 
 #if defined(CONFIG_NFS_V4_1)
-static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state)
+static int nfs41_check_expired_stateid(struct nfs4_state *state, nfs4_stateid *stateid, unsigned int flags)
 {
-       int status;
+       int status = NFS_OK;
        struct nfs_server *server = NFS_SERVER(state->inode);
 
-       status = nfs41_test_stateid(server, state);
-       if (status == NFS_OK)
-               return 0;
-       nfs41_free_stateid(server, state);
+       if (state->flags & flags) {
+               status = nfs41_test_stateid(server, stateid);
+               if (status != NFS_OK) {
+                       nfs41_free_stateid(server, stateid);
+                       state->flags &= ~flags;
+               }
+       }
+       return status;
+}
+
+static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state)
+{
+       int deleg_status, open_status;
+       int deleg_flags = 1 << NFS_DELEGATED_STATE;
+       int open_flags = (1 << NFS_O_RDONLY_STATE) | (1 << NFS_O_WRONLY_STATE) | (1 << NFS_O_RDWR_STATE);
+
+       deleg_status = nfs41_check_expired_stateid(state, &state->stateid, deleg_flags);
+       open_status = nfs41_check_expired_stateid(state,  &state->open_stateid, open_flags);
+
+       if ((deleg_status == NFS_OK) && (open_status == NFS_OK))
+               return NFS_OK;
        return nfs4_open_expired(sp, state);
 }
 #endif
@@ -1747,7 +1782,8 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, fmode_t fmode
 
        /* Protect against reboot recovery conflicts */
        status = -ENOMEM;
-       if (!(sp = nfs4_get_state_owner(server, cred))) {
+       sp = nfs4_get_state_owner(server, cred, GFP_KERNEL);
+       if (sp == NULL) {
                dprintk("nfs4_do_open: nfs4_get_state_owner failed!\n");
                goto out_err;
        }
@@ -2022,8 +2058,9 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
        nfs_fattr_init(calldata->res.fattr);
        calldata->timestamp = jiffies;
        if (nfs4_setup_sequence(NFS_SERVER(calldata->inode),
-                               &calldata->arg.seq_args, &calldata->res.seq_res,
-                               1, task))
+                               &calldata->arg.seq_args,
+                               &calldata->res.seq_res,
+                               task))
                return;
        rpc_call_start(task);
 }
@@ -2067,6 +2104,7 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc)
        calldata = kzalloc(sizeof(*calldata), gfp_mask);
        if (calldata == NULL)
                goto out;
+       nfs41_init_sequence(&calldata->arg.seq_args, &calldata->res.seq_res, 1);
        calldata->inode = state->inode;
        calldata->state = state;
        calldata->arg.fh = NFS_FH(state->inode);
@@ -2413,6 +2451,10 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
                }
        }
 
+       /* Deal with open(O_TRUNC) */
+       if (sattr->ia_valid & ATTR_OPEN)
+               sattr->ia_valid &= ~(ATTR_MTIME|ATTR_CTIME|ATTR_OPEN);
+
        status = nfs4_do_setattr(inode, cred, fattr, sattr, state);
        if (status == 0)
                nfs_setattr_update_inode(inode, sattr);
@@ -2487,7 +2529,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
        struct nfs_server *server = NFS_SERVER(inode);
        struct nfs4_accessargs args = {
                .fh = NFS_FH(inode),
-               .bitmask = server->attr_bitmask,
+               .bitmask = server->cache_consistency_bitmask,
        };
        struct nfs4_accessres res = {
                .server = server,
@@ -2705,8 +2747,8 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
 
        args->bitmask = server->cache_consistency_bitmask;
        res->server = server;
-       res->seq_res.sr_slot = NULL;
        msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE];
+       nfs41_init_sequence(&args->seq_args, &res->seq_res, 1);
 }
 
 static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir)
@@ -2731,6 +2773,7 @@ static void nfs4_proc_rename_setup(struct rpc_message *msg, struct inode *dir)
        msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME];
        arg->bitmask = server->attr_bitmask;
        res->server = server;
+       nfs41_init_sequence(&arg->seq_args, &res->seq_res, 1);
 }
 
 static int nfs4_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
@@ -3225,6 +3268,7 @@ static void nfs4_proc_read_setup(struct nfs_read_data *data, struct rpc_message
        data->timestamp   = jiffies;
        data->read_done_cb = nfs4_read_done_cb;
        msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ];
+       nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 0);
 }
 
 /* Reset the the nfs_read_data to send the read to the MDS. */
@@ -3298,6 +3342,7 @@ static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_messag
        data->timestamp   = jiffies;
 
        msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE];
+       nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
 }
 
 static int nfs4_commit_done_cb(struct rpc_task *task, struct nfs_write_data *data)
@@ -3332,6 +3377,7 @@ static void nfs4_proc_commit_setup(struct nfs_write_data *data, struct rpc_messa
                data->write_done_cb = nfs4_commit_done_cb;
        data->res.server = server;
        msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT];
+       nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
 }
 
 struct nfs4_renewdata {
@@ -3430,19 +3476,6 @@ static inline int nfs4_server_supports_acls(struct nfs_server *server)
  */
 #define NFS4ACL_MAXPAGES (XATTR_SIZE_MAX >> PAGE_CACHE_SHIFT)
 
-static void buf_to_pages(const void *buf, size_t buflen,
-               struct page **pages, unsigned int *pgbase)
-{
-       const void *p = buf;
-
-       *pgbase = offset_in_page(buf);
-       p -= *pgbase;
-       while (p < buf + buflen) {
-               *(pages++) = virt_to_page(p);
-               p += PAGE_CACHE_SIZE;
-       }
-}
-
 static int buf_to_pages_noslab(const void *buf, size_t buflen,
                struct page **pages, unsigned int *pgbase)
 {
@@ -3539,9 +3572,19 @@ out:
        nfs4_set_cached_acl(inode, acl);
 }
 
+/*
+ * The getxattr API returns the required buffer length when called with a
+ * NULL buf. The NFSv4 acl tool then calls getxattr again after allocating
+ * the required buf.  On a NULL buf, we send a page of data to the server
+ * guessing that the ACL request can be serviced by a page. If so, we cache
+ * up to the page of ACL data, and the 2nd call to getxattr is serviced by
+ * the cache. If not so, we throw away the page, and cache the required
+ * length. The next getxattr call will then produce another round trip to
+ * the server, this time with the input buf of the required size.
+ */
 static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen)
 {
-       struct page *pages[NFS4ACL_MAXPAGES];
+       struct page *pages[NFS4ACL_MAXPAGES] = {NULL, };
        struct nfs_getaclargs args = {
                .fh = NFS_FH(inode),
                .acl_pages = pages,
@@ -3556,41 +3599,60 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
                .rpc_argp = &args,
                .rpc_resp = &res,
        };
-       struct page *localpage = NULL;
-       int ret;
+       int ret = -ENOMEM, npages, i, acl_len = 0;
 
-       if (buflen < PAGE_SIZE) {
-               /* As long as we're doing a round trip to the server anyway,
-                * let's be prepared for a page of acl data. */
-               localpage = alloc_page(GFP_KERNEL);
-               resp_buf = page_address(localpage);
-               if (localpage == NULL)
-                       return -ENOMEM;
-               args.acl_pages[0] = localpage;
-               args.acl_pgbase = 0;
-               args.acl_len = PAGE_SIZE;
-       } else {
-               resp_buf = buf;
-               buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase);
+       npages = (buflen + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       /* As long as we're doing a round trip to the server anyway,
+        * let's be prepared for a page of acl data. */
+       if (npages == 0)
+               npages = 1;
+
+       for (i = 0; i < npages; i++) {
+               pages[i] = alloc_page(GFP_KERNEL);
+               if (!pages[i])
+                       goto out_free;
        }
-       ret = nfs4_call_sync(NFS_SERVER(inode)->client, NFS_SERVER(inode), &msg, &args.seq_args, &res.seq_res, 0);
+       if (npages > 1) {
+               /* for decoding across pages */
+               args.acl_scratch = alloc_page(GFP_KERNEL);
+               if (!args.acl_scratch)
+                       goto out_free;
+       }
+       args.acl_len = npages * PAGE_SIZE;
+       args.acl_pgbase = 0;
+       /* Let decode_getfacl know not to fail if the ACL data is larger than
+        * the page we send as a guess */
+       if (buf == NULL)
+               res.acl_flags |= NFS4_ACL_LEN_REQUEST;
+       resp_buf = page_address(pages[0]);
+
+       dprintk("%s  buf %p buflen %zu npages %d args.acl_len %zu\n",
+               __func__, buf, buflen, npages, args.acl_len);
+       ret = nfs4_call_sync(NFS_SERVER(inode)->client, NFS_SERVER(inode),
+                            &msg, &args.seq_args, &res.seq_res, 0);
        if (ret)
                goto out_free;
-       if (res.acl_len > args.acl_len)
-               nfs4_write_cached_acl(inode, NULL, res.acl_len);
+
+       acl_len = res.acl_len - res.acl_data_offset;
+       if (acl_len > args.acl_len)
+               nfs4_write_cached_acl(inode, NULL, acl_len);
        else
-               nfs4_write_cached_acl(inode, resp_buf, res.acl_len);
+               nfs4_write_cached_acl(inode, resp_buf + res.acl_data_offset,
+                                     acl_len);
        if (buf) {
                ret = -ERANGE;
-               if (res.acl_len > buflen)
+               if (acl_len > buflen)
                        goto out_free;
-               if (localpage)
-                       memcpy(buf, resp_buf, res.acl_len);
+               _copy_from_pages(buf, pages, res.acl_data_offset,
+                               res.acl_len);
        }
-       ret = res.acl_len;
+       ret = acl_len;
 out_free:
-       if (localpage)
-               __free_page(localpage);
+       for (i = 0; i < npages; i++)
+               if (pages[i])
+                       __free_page(pages[i]);
+       if (args.acl_scratch)
+               __free_page(args.acl_scratch);
        return ret;
 }
 
@@ -3621,6 +3683,8 @@ static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen)
                nfs_zap_acl_cache(inode);
        ret = nfs4_read_cached_acl(inode, buf, buflen);
        if (ret != -ENOENT)
+               /* -ENOENT is returned if there is no ACL or if there is an ACL
+                * but no cached acl data, just the acl length */
                return ret;
        return nfs4_get_acl_uncached(inode, buf, buflen);
 }
@@ -3866,7 +3930,7 @@ static void nfs4_delegreturn_prepare(struct rpc_task *task, void *data)
 
        if (nfs4_setup_sequence(d_data->res.server,
                                &d_data->args.seq_args,
-                               &d_data->res.seq_res, 1, task))
+                               &d_data->res.seq_res, task))
                return;
        rpc_call_start(task);
 }
@@ -3900,6 +3964,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
        data = kzalloc(sizeof(*data), GFP_NOFS);
        if (data == NULL)
                return -ENOMEM;
+       nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
        data->args.fhandle = &data->fh;
        data->args.stateid = &data->stateid;
        data->args.bitmask = server->attr_bitmask;
@@ -3958,7 +4023,7 @@ int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4
 static unsigned long
 nfs4_set_lock_task_retry(unsigned long timeout)
 {
-       schedule_timeout_killable(timeout);
+       freezable_schedule_timeout_killable(timeout);
        timeout <<= 1;
        if (timeout > NFS4_LOCK_MAXTIMEOUT)
                return NFS4_LOCK_MAXTIMEOUT;
@@ -3991,7 +4056,7 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock
        if (status != 0)
                goto out;
        lsp = request->fl_u.nfs4_fl.owner;
-       arg.lock_owner.id = lsp->ls_id.id;
+       arg.lock_owner.id = lsp->ls_seqid.owner_id;
        arg.lock_owner.s_dev = server->s_dev;
        status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
        switch (status) {
@@ -4117,7 +4182,7 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data)
        calldata->timestamp = jiffies;
        if (nfs4_setup_sequence(calldata->server,
                                &calldata->arg.seq_args,
-                               &calldata->res.seq_res, 1, task))
+                               &calldata->res.seq_res, task))
                return;
        rpc_call_start(task);
 }
@@ -4157,6 +4222,7 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl,
                return ERR_PTR(-ENOMEM);
        }
 
+       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;
@@ -4236,7 +4302,7 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl,
                goto out_free_seqid;
        p->arg.lock_stateid = &lsp->ls_stateid;
        p->arg.lock_owner.clientid = server->nfs_client->cl_clientid;
-       p->arg.lock_owner.id = lsp->ls_id.id;
+       p->arg.lock_owner.id = lsp->ls_seqid.owner_id;
        p->arg.lock_owner.s_dev = server->s_dev;
        p->res.lock_seqid = p->arg.lock_seqid;
        p->lsp = lsp;
@@ -4272,7 +4338,7 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
        data->timestamp = jiffies;
        if (nfs4_setup_sequence(data->server,
                                &data->arg.seq_args,
-                               &data->res.seq_res, 1, task))
+                               &data->res.seq_res, task))
                return;
        rpc_call_start(task);
        dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status);
@@ -4390,6 +4456,7 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f
                        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;
@@ -4454,15 +4521,34 @@ out:
 }
 
 #if defined(CONFIG_NFS_V4_1)
-static int nfs41_lock_expired(struct nfs4_state *state, struct file_lock *request)
+static int nfs41_check_expired_locks(struct nfs4_state *state)
 {
-       int status;
+       int status, ret = NFS_OK;
+       struct nfs4_lock_state *lsp;
        struct nfs_server *server = NFS_SERVER(state->inode);
 
-       status = nfs41_test_stateid(server, state);
+       list_for_each_entry(lsp, &state->lock_states, ls_locks) {
+               if (lsp->ls_flags & NFS_LOCK_INITIALIZED) {
+                       status = nfs41_test_stateid(server, &lsp->ls_stateid);
+                       if (status != NFS_OK) {
+                               nfs41_free_stateid(server, &lsp->ls_stateid);
+                               lsp->ls_flags &= ~NFS_LOCK_INITIALIZED;
+                               ret = status;
+                       }
+               }
+       };
+
+       return ret;
+}
+
+static int nfs41_lock_expired(struct nfs4_state *state, struct file_lock *request)
+{
+       int status = NFS_OK;
+
+       if (test_bit(LK_STATE_IN_USE, &state->flags))
+               status = nfs41_check_expired_locks(state);
        if (status == NFS_OK)
-               return 0;
-       nfs41_free_stateid(server, state);
+               return status;
        return nfs4_lock_expired(state, request);
 }
 #endif
@@ -4498,7 +4584,8 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock
        /* Note: we always want to sleep here! */
        request->fl_flags = fl_flags | FL_SLEEP;
        if (do_vfs_lock(request->fl_file, request) < 0)
-               printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __func__);
+               printk(KERN_WARNING "NFS: %s: VFS is out of sync with lock "
+                       "manager!\n", __func__);
 out_unlock:
        up_read(&nfsi->rwsem);
 out:
@@ -4578,8 +4665,8 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl)
                err = _nfs4_do_setlk(state, F_SETLK, fl, NFS_LOCK_NEW);
                switch (err) {
                        default:
-                               printk(KERN_ERR "%s: unhandled error %d.\n",
-                                               __func__, err);
+                               printk(KERN_ERR "NFS: %s: unhandled error "
+                                       "%d.\n", __func__, err);
                        case 0:
                        case -ESTALE:
                                goto out;
@@ -4653,7 +4740,7 @@ void nfs4_release_lockowner(const struct nfs4_lock_state *lsp)
        if (!args)
                return;
        args->lock_owner.clientid = server->nfs_client->cl_clientid;
-       args->lock_owner.id = lsp->ls_id.id;
+       args->lock_owner.id = lsp->ls_seqid.owner_id;
        args->lock_owner.s_dev = server->s_dev;
        msg.rpc_argp = args;
        rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, args);
@@ -4905,7 +4992,7 @@ static void nfs4_get_lease_time_prepare(struct rpc_task *task,
           since we're invoked within one */
        ret = nfs41_setup_sequence(data->clp->cl_session,
                                   &data->args->la_seq_args,
-                                  &data->res->lr_seq_res, 0, task);
+                                  &data->res->lr_seq_res, task);
 
        BUG_ON(ret == -EAGAIN);
        rpc_call_start(task);
@@ -4969,6 +5056,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);
        dprintk("--> %s\n", __func__);
        task = rpc_run_task(&task_setup);
 
@@ -5021,23 +5109,6 @@ out:
        return ret;
 }
 
-/*
- * Reset the forechannel and backchannel slot tables
- */
-static int nfs4_reset_slot_tables(struct nfs4_session *session)
-{
-       int status;
-
-       status = nfs4_reset_slot_table(&session->fc_slot_table,
-                       session->fc_attrs.max_reqs, 1);
-       if (status)
-               return status;
-
-       status = nfs4_reset_slot_table(&session->bc_slot_table,
-                       session->bc_attrs.max_reqs, 0);
-       return status;
-}
-
 /* Destroy the slot table */
 static void nfs4_destroy_slot_tables(struct nfs4_session *session)
 {
@@ -5083,29 +5154,35 @@ out:
 }
 
 /*
- * Initialize the forechannel and backchannel tables
+ * Initialize or reset the forechannel and backchannel tables
  */
-static int nfs4_init_slot_tables(struct nfs4_session *session)
+static int nfs4_setup_session_slot_tables(struct nfs4_session *ses)
 {
        struct nfs4_slot_table *tbl;
-       int status = 0;
+       int status;
 
-       tbl = &session->fc_slot_table;
+       dprintk("--> %s\n", __func__);
+       /* Fore channel */
+       tbl = &ses->fc_slot_table;
        if (tbl->slots == NULL) {
-               status = nfs4_init_slot_table(tbl,
-                               session->fc_attrs.max_reqs, 1);
+               status = nfs4_init_slot_table(tbl, ses->fc_attrs.max_reqs, 1);
+               if (status) /* -ENOMEM */
+                       return status;
+       } else {
+               status = nfs4_reset_slot_table(tbl, ses->fc_attrs.max_reqs, 1);
                if (status)
                        return status;
        }
-
-       tbl = &session->bc_slot_table;
+       /* Back channel */
+       tbl = &ses->bc_slot_table;
        if (tbl->slots == NULL) {
-               status = nfs4_init_slot_table(tbl,
-                               session->bc_attrs.max_reqs, 0);
+               status = nfs4_init_slot_table(tbl, ses->bc_attrs.max_reqs, 0);
                if (status)
-                       nfs4_destroy_slot_tables(session);
-       }
-
+                       /* Fore and back channel share a connection so get
+                        * both slot tables or neither */
+                       nfs4_destroy_slot_tables(ses);
+       } else
+               status = nfs4_reset_slot_table(tbl, ses->bc_attrs.max_reqs, 0);
        return status;
 }
 
@@ -5293,13 +5370,9 @@ int nfs4_proc_create_session(struct nfs_client *clp)
        if (status)
                goto out;
 
-       /* Init and reset the fore channel */
-       status = nfs4_init_slot_tables(session);
-       dprintk("slot table initialization returned %d\n", status);
-       if (status)
-               goto out;
-       status = nfs4_reset_slot_tables(session);
-       dprintk("slot table reset returned %d\n", status);
+       /* Init or reset the session slot tables */
+       status = nfs4_setup_session_slot_tables(session);
+       dprintk("slot table setup returned %d\n", status);
        if (status)
                goto out;
 
@@ -5334,7 +5407,7 @@ int nfs4_proc_destroy_session(struct nfs4_session *session)
 
        if (status)
                printk(KERN_WARNING
-                       "Got error %d from the server on DESTROY_SESSION. "
+                       "NFS: Got error %d from the server on DESTROY_SESSION. "
                        "Session has been destroyed regardless...\n", status);
 
        dprintk("<-- nfs4_proc_destroy_session\n");
@@ -5457,7 +5530,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, 0, task))
+       if (nfs41_setup_sequence(clp->cl_session, args, res, task))
                return;
        rpc_call_start(task);
 }
@@ -5489,6 +5562,7 @@ static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_
                nfs_put_client(clp);
                return ERR_PTR(-ENOMEM);
        }
+       nfs41_init_sequence(&calldata->args, &calldata->res, 0);
        msg.rpc_argp = &calldata->args;
        msg.rpc_resp = &calldata->res;
        calldata->clp = clp;
@@ -5550,7 +5624,7 @@ static void nfs4_reclaim_complete_prepare(struct rpc_task *task, void *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, 0, task))
+                               &calldata->res.seq_res, task))
                return;
 
        rpc_call_start(task);
@@ -5629,6 +5703,7 @@ static int nfs41_proc_reclaim_complete(struct nfs_client *clp)
        calldata->clp = clp;
        calldata->arg.one_fs = 0;
 
+       nfs41_init_sequence(&calldata->arg.seq_args, &calldata->res.seq_res, 0);
        msg.rpc_argp = &calldata->arg;
        msg.rpc_resp = &calldata->res;
        task_setup_data.callback_data = calldata;
@@ -5660,7 +5735,7 @@ nfs4_layoutget_prepare(struct rpc_task *task, void *calldata)
         * to be no way to prevent it completely.
         */
        if (nfs4_setup_sequence(server, &lgp->args.seq_args,
-                               &lgp->res.seq_res, 0, task))
+                               &lgp->res.seq_res, task))
                return;
        if (pnfs_choose_layoutget_stateid(&lgp->args.stateid,
                                          NFS_I(lgp->args.inode)->layout,
@@ -5735,6 +5810,7 @@ int nfs4_proc_layoutget(struct nfs4_layoutget *lgp)
 
        lgp->res.layoutp = &lgp->args.layout;
        lgp->res.seq_res.sr_slot = NULL;
+       nfs41_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0);
        task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task))
                return PTR_ERR(task);
@@ -5755,7 +5831,7 @@ nfs4_layoutreturn_prepare(struct rpc_task *task, void *calldata)
 
        dprintk("--> %s\n", __func__);
        if (nfs41_setup_sequence(lrp->clp->cl_session, &lrp->args.seq_args,
-                               &lrp->res.seq_res, 0, task))
+                               &lrp->res.seq_res, task))
                return;
        rpc_call_start(task);
 }
@@ -5821,6 +5897,7 @@ int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp)
        int status;
 
        dprintk("--> %s\n", __func__);
+       nfs41_init_sequence(&lrp->args.seq_args, &lrp->res.seq_res, 1);
        task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task))
                return PTR_ERR(task);
@@ -5921,7 +5998,7 @@ static void nfs4_layoutcommit_prepare(struct rpc_task *task, void *calldata)
        struct nfs_server *server = NFS_SERVER(data->args.inode);
 
        if (nfs4_setup_sequence(server, &data->args.seq_args,
-                               &data->res.seq_res, 1, task))
+                               &data->res.seq_res, task))
                return;
        rpc_call_start(task);
 }
@@ -6008,6 +6085,7 @@ nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, bool sync)
                data->args.lastbytewritten,
                data->args.inode->i_ino);
 
+       nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
        task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task))
                return PTR_ERR(task);
@@ -6101,11 +6179,12 @@ out_freepage:
 out:
        return err;
 }
-static int _nfs41_test_stateid(struct nfs_server *server, struct nfs4_state *state)
+
+static int _nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid)
 {
        int status;
        struct nfs41_test_stateid_args args = {
-               .stateid = &state->stateid,
+               .stateid = stateid,
        };
        struct nfs41_test_stateid_res res;
        struct rpc_message msg = {
@@ -6113,28 +6192,31 @@ static int _nfs41_test_stateid(struct nfs_server *server, struct nfs4_state *sta
                .rpc_argp = &args,
                .rpc_resp = &res,
        };
-       args.seq_args.sa_session = res.seq_res.sr_session = NULL;
-       status = nfs4_call_sync_sequence(server->client, server, &msg, &args.seq_args, &res.seq_res, 0, 1);
+
+       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);
+
+       if (status == NFS_OK)
+               return res.status;
        return status;
 }
 
-static int nfs41_test_stateid(struct nfs_server *server, struct nfs4_state *state)
+static int nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid)
 {
        struct nfs4_exception exception = { };
        int err;
        do {
                err = nfs4_handle_exception(server,
-                               _nfs41_test_stateid(server, state),
+                               _nfs41_test_stateid(server, stateid),
                                &exception);
        } while (exception.retry);
        return err;
 }
 
-static int _nfs4_free_stateid(struct nfs_server *server, struct nfs4_state *state)
+static int _nfs4_free_stateid(struct nfs_server *server, nfs4_stateid *stateid)
 {
-       int status;
        struct nfs41_free_stateid_args args = {
-               .stateid = &state->stateid,
+               .stateid = stateid,
        };
        struct nfs41_free_stateid_res res;
        struct rpc_message msg = {
@@ -6143,18 +6225,17 @@ static int _nfs4_free_stateid(struct nfs_server *server, struct nfs4_state *stat
                .rpc_resp = &res,
        };
 
-       args.seq_args.sa_session = res.seq_res.sr_session = NULL;
-       status = nfs4_call_sync_sequence(server->client, server, &msg, &args.seq_args, &res.seq_res, 0, 1);
-       return status;
+       nfs41_init_sequence(&args.seq_args, &res.seq_res, 0);
+       return nfs4_call_sync_sequence(server->client, server, &msg, &args.seq_args, &res.seq_res, 1);
 }
 
-static int nfs41_free_stateid(struct nfs_server *server, struct nfs4_state *state)
+static int nfs41_free_stateid(struct nfs_server *server, nfs4_stateid *stateid)
 {
        struct nfs4_exception exception = { };
        int err;
        do {
                err = nfs4_handle_exception(server,
-                               _nfs4_free_stateid(server, state),
+                               _nfs4_free_stateid(server, stateid),
                                &exception);
        } while (exception.retry);
        return err;