Merge tag 'nfs-for-4.13-1' of git://git.linux-nfs.org/projects/anna/linux-nfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 13 Jul 2017 21:35:37 +0000 (14:35 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 13 Jul 2017 21:35:37 +0000 (14:35 -0700)
Pull NFS client updates from Anna Schumaker:
 "Stable bugfixes:
   - Fix -EACCESS on commit to DS handling
   - Fix initialization of nfs_page_array->npages
   - Only invalidate dentries that are actually invalid

  Features:
   - Enable NFSoRDMA transparent state migration
   - Add support for lookup-by-filehandle
   - Add support for nfs re-exporting

  Other bugfixes and cleanups:
   - Christoph cleaned up the way we declare NFS operations
   - Clean up various internal structures
   - Various cleanups to commits
   - Various improvements to error handling
   - Set the dt_type of . and .. entries in NFS v4
   - Make slot allocation more reliable
   - Fix fscache stat printing
   - Fix uninitialized variable warnings
   - Fix potential list overrun in nfs_atomic_open()
   - Fix a race in NFSoRDMA RPC reply handler
   - Fix return size for nfs42_proc_copy()
   - Fix against MAC forgery timing attacks"

* tag 'nfs-for-4.13-1' of git://git.linux-nfs.org/projects/anna/linux-nfs: (68 commits)
  NFS: Don't run wake_up_bit() when nobody is waiting...
  nfs: add export operations
  nfs4: add NFSv4 LOOKUPP handlers
  nfs: add a nfs_ilookup helper
  nfs: replace d_add with d_splice_alias in atomic_open
  sunrpc: use constant time memory comparison for mac
  NFSv4.2 fix size storage for nfs42_proc_copy
  xprtrdma: Fix documenting comments in frwr_ops.c
  xprtrdma: Replace PAGE_MASK with offset_in_page()
  xprtrdma: FMR does not need list_del_init()
  xprtrdma: Demote "connect" log messages
  NFSv4.1: Use seqid returned by EXCHANGE_ID after state migration
  NFSv4.1: Handle EXCHGID4_FLAG_CONFIRMED_R during NFSv4.1 migration
  xprtrdma: Don't defer MR recovery if ro_map fails
  xprtrdma: Fix FRWR invalidation error recovery
  xprtrdma: Fix client lock-up after application signal fires
  xprtrdma: Rename rpcrdma_req::rl_free
  xprtrdma: Pass only the list of registered MRs to ro_unmap_sync
  xprtrdma: Pre-mark remotely invalidated MRs
  xprtrdma: On invalidation failure, remove MWs from rl_registered
  ...

1  2 
fs/nfs/dir.c
fs/nfs/internal.h
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/super.c

diff --combined fs/nfs/dir.c
@@@ -151,7 -151,7 +151,7 @@@ struct nfs_cache_array 
        struct nfs_cache_array_entry array[0];
  };
  
- typedef int (*decode_dirent_t)(struct xdr_stream *, struct nfs_entry *, int);
+ typedef int (*decode_dirent_t)(struct xdr_stream *, struct nfs_entry *, bool);
  typedef struct {
        struct file     *file;
        struct page     *page;
        unsigned long   timestamp;
        unsigned long   gencount;
        unsigned int    cache_entry_index;
-       unsigned int    plus:1;
-       unsigned int    eof:1;
+       bool plus;
+       bool eof;
  } nfs_readdir_descriptor_t;
  
  /*
@@@ -355,7 -355,7 +355,7 @@@ int nfs_readdir_xdr_filler(struct page 
                if (error == -ENOTSUPP && desc->plus) {
                        NFS_SERVER(inode)->caps &= ~NFS_CAP_READDIRPLUS;
                        clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags);
-                       desc->plus = 0;
+                       desc->plus = false;
                        goto again;
                }
                goto error;
@@@ -557,7 -557,7 +557,7 @@@ int nfs_readdir_page_filler(nfs_readdir
  
                count++;
  
-               if (desc->plus != 0)
+               if (desc->plus)
                        nfs_prime_dcache(file_dentry(desc->file), entry);
  
                status = nfs_readdir_add_to_array(entry, page);
@@@ -860,7 -860,7 +860,7 @@@ static int nfs_readdir(struct file *fil
        desc->ctx = ctx;
        desc->dir_cookie = &dir_ctx->dir_cookie;
        desc->decode = NFS_PROTO(inode)->decode_dirent;
-       desc->plus = nfs_use_readdirplus(inode, ctx) ? 1 : 0;
+       desc->plus = nfs_use_readdirplus(inode, ctx);
  
        if (ctx->pos == 0 || nfs_attribute_cache_expired(inode))
                res = nfs_revalidate_mapping(inode, file->f_mapping);
                        clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags);
                        nfs_zap_caches(inode);
                        desc->page_index = 0;
-                       desc->plus = 0;
-                       desc->eof = 0;
+                       desc->plus = false;
+                       desc->eof = false;
                        continue;
                }
                if (res < 0)
@@@ -1115,11 -1115,13 +1115,13 @@@ static int nfs_lookup_revalidate(struc
        /* Force a full look up iff the parent directory has changed */
        if (!nfs_is_exclusive_create(dir, flags) &&
            nfs_check_verifier(dir, dentry, flags & LOOKUP_RCU)) {
-               if (nfs_lookup_verify_inode(inode, flags)) {
+               error = nfs_lookup_verify_inode(inode, flags);
+               if (error) {
                        if (flags & LOOKUP_RCU)
                                return -ECHILD;
-                       goto out_zap_parent;
+                       if (error == -ESTALE)
+                               goto out_zap_parent;
+                       goto out_error;
                }
                nfs_advise_use_readdirplus(dir);
                goto out_valid;
        trace_nfs_lookup_revalidate_enter(dir, dentry, flags);
        error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label);
        trace_nfs_lookup_revalidate_exit(dir, dentry, flags, error);
-       if (error)
+       if (error == -ESTALE || error == -ENOENT)
                goto out_bad;
+       if (error)
+               goto out_error;
        if (nfs_compare_fh(NFS_FH(inode), fhandle))
                goto out_bad;
        if ((error = nfs_refresh_inode(inode, fattr)) != 0)
@@@ -1427,8 -1431,10 +1431,10 @@@ static int nfs_finish_open(struct nfs_o
        err = finish_open(file, dentry, do_open, opened);
        if (err)
                goto out;
-       nfs_file_set_open_context(file, ctx);
+       if (S_ISREG(file->f_path.dentry->d_inode->i_mode))
+               nfs_file_set_open_context(file, ctx);
+       else
+               err = -ESTALE;
  out:
        return err;
  }
@@@ -1512,7 -1518,7 +1518,7 @@@ int nfs_atomic_open(struct inode *dir, 
                d_drop(dentry);
                switch (err) {
                case -ENOENT:
-                       d_add(dentry, NULL);
+                       d_splice_alias(NULL, dentry);
                        nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
                        break;
                case -EISDIR:
@@@ -1946,6 -1952,29 +1952,6 @@@ nfs_link(struct dentry *old_dentry, str
  }
  EXPORT_SYMBOL_GPL(nfs_link);
  
 -static void
 -nfs_complete_rename(struct rpc_task *task, struct nfs_renamedata *data)
 -{
 -      struct dentry *old_dentry = data->old_dentry;
 -      struct dentry *new_dentry = data->new_dentry;
 -      struct inode *old_inode = d_inode(old_dentry);
 -      struct inode *new_inode = d_inode(new_dentry);
 -
 -      nfs_mark_for_revalidate(old_inode);
 -
 -      switch (task->tk_status) {
 -      case 0:
 -              if (new_inode != NULL)
 -                      nfs_drop_nlink(new_inode);
 -              d_move(old_dentry, new_dentry);
 -              nfs_set_verifier(new_dentry,
 -                                      nfs_save_change_attribute(data->new_dir));
 -              break;
 -      case -ENOENT:
 -              nfs_dentry_handle_enoent(old_dentry);
 -      }
 -}
 -
  /*
   * RENAME
   * FIXME: Some nfsds, like the Linux user space nfsd, may generate a
@@@ -1976,7 -2005,7 +1982,7 @@@ int nfs_rename(struct inode *old_dir, s
  {
        struct inode *old_inode = d_inode(old_dentry);
        struct inode *new_inode = d_inode(new_dentry);
 -      struct dentry *dentry = NULL;
 +      struct dentry *dentry = NULL, *rehash = NULL;
        struct rpc_task *task;
        int error = -EBUSY;
  
                 * To prevent any new references to the target during the
                 * rename, we unhash the dentry in advance.
                 */
 -              if (!d_unhashed(new_dentry))
 +              if (!d_unhashed(new_dentry)) {
                        d_drop(new_dentry);
 +                      rehash = new_dentry;
 +              }
  
                if (d_count(new_dentry) > 2) {
                        int err;
                                goto out;
  
                        new_dentry = dentry;
 +                      rehash = NULL;
                        new_inode = NULL;
                }
        }
        if (new_inode != NULL)
                NFS_PROTO(new_inode)->return_delegation(new_inode);
  
 -      task = nfs_async_rename(old_dir, new_dir, old_dentry, new_dentry,
 -                                      nfs_complete_rename);
 +      task = nfs_async_rename(old_dir, new_dir, old_dentry, new_dentry, NULL);
        if (IS_ERR(task)) {
                error = PTR_ERR(task);
                goto out;
        }
  
        error = rpc_wait_for_completion_task(task);
-       if (error == 0)
+       if (error != 0) {
+               ((struct nfs_renamedata *)task->tk_calldata)->cancelled = 1;
+               /* Paired with the atomic_dec_and_test() barrier in rpc_do_put_task() */
+               smp_wmb();
+       } else
                error = task->tk_status;
        rpc_put_task(task);
 +      nfs_mark_for_revalidate(old_inode);
  out:
 +      if (rehash)
 +              d_rehash(rehash);
        trace_nfs_rename_exit(old_dir, old_dentry,
                        new_dir, new_dentry, error);
 +      if (!error) {
 +              if (new_inode != NULL)
 +                      nfs_drop_nlink(new_inode);
 +              /*
 +               * The d_move() should be here instead of in an async RPC completion
 +               * handler because we need the proper locks to move the dentry.  If
 +               * we're interrupted by a signal, the async RPC completion handler
 +               * should mark the directories for revalidation.
 +               */
 +              d_move(old_dentry, new_dentry);
 +              nfs_set_verifier(new_dentry,
 +                                      nfs_save_change_attribute(new_dir));
 +      } else if (error == -ENOENT)
 +              nfs_dentry_handle_enoent(old_dentry);
 +
        /* new dentry created? */
        if (dentry)
                dput(dentry);
diff --combined fs/nfs/internal.h
@@@ -7,10 -7,11 +7,12 @@@
  #include <linux/security.h>
  #include <linux/crc32.h>
  #include <linux/nfs_page.h>
 +#include <linux/wait_bit.h>
  
  #define NFS_MS_MASK (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_SYNCHRONOUS)
  
+ extern const struct export_operations nfs_export_ops;
  struct nfs_string;
  
  /* Maximum number of readahead requests
@@@ -273,17 -274,17 +275,17 @@@ static inline bool nfs_match_open_conte
  /* nfs2xdr.c */
  extern const struct rpc_procinfo nfs_procedures[];
  extern int nfs2_decode_dirent(struct xdr_stream *,
-                               struct nfs_entry *, int);
+                               struct nfs_entry *, bool);
  
  /* nfs3xdr.c */
  extern const struct rpc_procinfo nfs3_procedures[];
  extern int nfs3_decode_dirent(struct xdr_stream *,
-                               struct nfs_entry *, int);
+                               struct nfs_entry *, bool);
  
  /* nfs4xdr.c */
  #if IS_ENABLED(CONFIG_NFS_V4)
  extern int nfs4_decode_dirent(struct xdr_stream *,
-                               struct nfs_entry *, int);
+                               struct nfs_entry *, bool);
  #endif
  #ifdef CONFIG_NFS_V4_1
  extern const u32 nfs41_maxread_overhead;
diff --combined fs/nfs/nfs4proc.c
@@@ -275,6 -275,7 +275,7 @@@ const u32 nfs4_fs_locations_bitmap[3] 
  static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dentry,
                struct nfs4_readdir_arg *readdir)
  {
+       unsigned int attrs = FATTR4_WORD0_FILEID | FATTR4_WORD0_TYPE;
        __be32 *start, *p;
  
        if (cookie > 2) {
                memcpy(p, ".\0\0\0", 4);                        /* entry */
                p++;
                *p++ = xdr_one;                         /* bitmap length */
-               *p++ = htonl(FATTR4_WORD0_FILEID);             /* bitmap */
-               *p++ = htonl(8);              /* attribute buffer length */
+               *p++ = htonl(attrs);                           /* bitmap */
+               *p++ = htonl(12);             /* attribute buffer length */
+               *p++ = htonl(NF4DIR);
                p = xdr_encode_hyper(p, NFS_FILEID(d_inode(dentry)));
        }
        
        memcpy(p, "..\0\0", 4);                         /* entry */
        p++;
        *p++ = xdr_one;                         /* bitmap length */
-       *p++ = htonl(FATTR4_WORD0_FILEID);             /* bitmap */
-       *p++ = htonl(8);              /* attribute buffer length */
+       *p++ = htonl(attrs);                           /* bitmap */
+       *p++ = htonl(12);             /* attribute buffer length */
+       *p++ = htonl(NF4DIR);
        p = xdr_encode_hyper(p, NFS_FILEID(d_inode(dentry->d_parent)));
  
        readdir->pgbase = (char *)p - (char *)start;
@@@ -1034,11 -1037,11 +1037,11 @@@ struct nfs4_opendata 
        struct nfs4_state *state;
        struct iattr attrs;
        unsigned long timestamp;
-       unsigned int rpc_done : 1;
-       unsigned int file_created : 1;
-       unsigned int is_recover : 1;
+       bool rpc_done;
+       bool file_created;
+       bool is_recover;
+       bool cancelled;
        int rpc_status;
-       int cancelled;
  };
  
  static bool nfs4_clear_cap_atomic_open_v1(struct nfs_server *server,
@@@ -1962,7 -1965,7 +1965,7 @@@ static void nfs4_open_confirm_done(stru
                nfs4_stateid_copy(&data->o_res.stateid, &data->c_res.stateid);
                nfs_confirm_seqid(&data->owner->so_seqid, 0);
                renew_lease(data->o_res.server, data->timestamp);
-               data->rpc_done = 1;
+               data->rpc_done = true;
        }
  }
  
@@@ -1972,7 -1975,7 +1975,7 @@@ static void nfs4_open_confirm_release(v
        struct nfs4_state *state = NULL;
  
        /* If this request hasn't been cancelled, do nothing */
-       if (data->cancelled == 0)
+       if (!data->cancelled)
                goto out_free;
        /* In case of error, no cleanup! */
        if (!data->rpc_done)
@@@ -2015,7 -2018,7 +2018,7 @@@ static int _nfs4_proc_open_confirm(stru
  
        nfs4_init_sequence(&data->c_arg.seq_args, &data->c_res.seq_res, 1);
        kref_get(&data->kref);
-       data->rpc_done = 0;
+       data->rpc_done = false;
        data->rpc_status = 0;
        data->timestamp = jiffies;
        if (data->is_recover)
                return PTR_ERR(task);
        status = rpc_wait_for_completion_task(task);
        if (status != 0) {
-               data->cancelled = 1;
+               data->cancelled = true;
                smp_wmb();
        } else
                status = data->rpc_status;
@@@ -2124,7 -2127,7 +2127,7 @@@ static void nfs4_open_done(struct rpc_t
                if (!(data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM))
                        nfs_confirm_seqid(&data->owner->so_seqid, 0);
        }
-       data->rpc_done = 1;
+       data->rpc_done = true;
  }
  
  static void nfs4_open_release(void *calldata)
        struct nfs4_state *state = NULL;
  
        /* If this request hasn't been cancelled, do nothing */
-       if (data->cancelled == 0)
+       if (!data->cancelled)
                goto out_free;
        /* In case of error, no cleanup! */
        if (data->rpc_status != 0 || !data->rpc_done)
@@@ -2179,20 -2182,20 +2182,20 @@@ static int nfs4_run_open_task(struct nf
  
        nfs4_init_sequence(&o_arg->seq_args, &o_res->seq_res, 1);
        kref_get(&data->kref);
-       data->rpc_done = 0;
+       data->rpc_done = false;
        data->rpc_status = 0;
-       data->cancelled = 0;
-       data->is_recover = 0;
+       data->cancelled = false;
+       data->is_recover = false;
        if (isrecover) {
                nfs4_set_sequence_privileged(&o_arg->seq_args);
-               data->is_recover = 1;
+               data->is_recover = true;
        }
        task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task))
                return PTR_ERR(task);
        status = rpc_wait_for_completion_task(task);
        if (status != 0) {
-               data->cancelled = 1;
+               data->cancelled = true;
                smp_wmb();
        } else
                status = data->rpc_status;
@@@ -2287,9 -2290,9 +2290,9 @@@ static int _nfs4_proc_open(struct nfs4_
  
        if (o_arg->open_flags & O_CREAT) {
                if (o_arg->open_flags & O_EXCL)
-                       data->file_created = 1;
+                       data->file_created = true;
                else if (o_res->cinfo.before != o_res->cinfo.after)
-                       data->file_created = 1;
+                       data->file_created = true;
                if (data->file_created || dir->i_version != o_res->cinfo.after)
                        update_changeattr(dir, &o_res->cinfo,
                                        o_res->f_attr->time_start);
@@@ -2589,8 -2592,7 +2592,8 @@@ static inline void nfs4_exclusive_attrs
  
        /* Except MODE, it seems harmless of setting twice. */
        if (opendata->o_arg.createmode != NFS4_CREATE_EXCLUSIVE &&
 -              attrset[1] & FATTR4_WORD1_MODE)
 +              (attrset[1] & FATTR4_WORD1_MODE ||
 +               attrset[2] & FATTR4_WORD2_MODE_UMASK))
                sattr->ia_valid &= ~ATTR_MODE;
  
        if (attrset[2] & FATTR4_WORD2_SECURITY_LABEL)
@@@ -3803,6 -3805,54 +3806,54 @@@ nfs4_proc_lookup_mountpoint(struct inod
        return (client == NFS_CLIENT(dir)) ? rpc_clone_client(client) : client;
  }
  
+ static int _nfs4_proc_lookupp(struct inode *inode,
+               struct nfs_fh *fhandle, struct nfs_fattr *fattr,
+               struct nfs4_label *label)
+ {
+       struct rpc_clnt *clnt = NFS_CLIENT(inode);
+       struct nfs_server *server = NFS_SERVER(inode);
+       int                    status;
+       struct nfs4_lookupp_arg args = {
+               .bitmask = server->attr_bitmask,
+               .fh = NFS_FH(inode),
+       };
+       struct nfs4_lookupp_res res = {
+               .server = server,
+               .fattr = fattr,
+               .label = label,
+               .fh = fhandle,
+       };
+       struct rpc_message msg = {
+               .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUPP],
+               .rpc_argp = &args,
+               .rpc_resp = &res,
+       };
+       args.bitmask = nfs4_bitmask(server, label);
+       nfs_fattr_init(fattr);
+       dprintk("NFS call  lookupp ino=0x%lx\n", inode->i_ino);
+       status = nfs4_call_sync(clnt, server, &msg, &args.seq_args,
+                               &res.seq_res, 0);
+       dprintk("NFS reply lookupp: %d\n", status);
+       return status;
+ }
+ static int nfs4_proc_lookupp(struct inode *inode, struct nfs_fh *fhandle,
+                            struct nfs_fattr *fattr, struct nfs4_label *label)
+ {
+       struct nfs4_exception exception = { };
+       int err;
+       do {
+               err = _nfs4_proc_lookupp(inode, fhandle, fattr, label);
+               trace_nfs4_lookupp(inode, err);
+               err = nfs4_handle_exception(NFS_SERVER(inode), err,
+                               &exception);
+       } while (exception.retry);
+       return err;
+ }
  static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry)
  {
        struct nfs_server *server = NFS_SERVER(inode);
@@@ -4273,7 -4323,7 +4324,7 @@@ static int nfs4_proc_mkdir(struct inod
  }
  
  static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
-               u64 cookie, struct page **pages, unsigned int count, int plus)
+               u64 cookie, struct page **pages, unsigned int count, bool plus)
  {
        struct inode            *dir = d_inode(dentry);
        struct nfs4_readdir_arg args = {
  }
  
  static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
-               u64 cookie, struct page **pages, unsigned int count, int plus)
+               u64 cookie, struct page **pages, unsigned int count, bool plus)
  {
        struct nfs4_exception exception = { };
        int err;
@@@ -6135,7 -6185,7 +6186,7 @@@ static void nfs4_lock_release(void *cal
  
        dprintk("%s: begin!\n", __func__);
        nfs_free_seqid(data->arg.open_seqid);
-       if (data->cancelled != 0) {
+       if (data->cancelled) {
                struct rpc_task *task;
                task = nfs4_do_unlck(&data->fl, data->ctx, data->lsp,
                                data->arg.lock_seqid);
@@@ -6218,7 -6268,7 +6269,7 @@@ static int _nfs4_do_setlk(struct nfs4_s
                        nfs4_handle_setlk_error(data->server, data->lsp,
                                        data->arg.new_lock_owner, ret);
        } else
-               data->cancelled = 1;
+               data->cancelled = true;
        rpc_put_task(task);
        dprintk("%s: done, ret = %d!\n", __func__, ret);
        trace_nfs4_set_lock(fl, state, &data->res.stateid, cmd, ret);
@@@ -6373,7 -6423,7 +6424,7 @@@ struct nfs4_lock_waiter 
  };
  
  static int
 -nfs4_wake_lock_waiter(wait_queue_t *wait, unsigned int mode, int flags, void *key)
 +nfs4_wake_lock_waiter(wait_queue_entry_t *wait, unsigned int mode, int flags, void *key)
  {
        int ret;
        struct cb_notify_lock_args *cbnl = key;
@@@ -6416,7 -6466,7 +6467,7 @@@ nfs4_retry_setlk(struct nfs4_state *sta
                                           .inode = state->inode,
                                           .owner = &owner,
                                           .notified = false };
 -      wait_queue_t wait;
 +      wait_queue_entry_t wait;
  
        /* Don't bother with waitqueue if we don't expect a callback */
        if (!test_bit(NFS_STATE_MAY_NOTIFY_LOCK, &state->flags))
@@@ -7376,12 -7426,11 +7427,11 @@@ static void nfs4_exchange_id_done(struc
        if (status == 0) {
                clp->cl_clientid = cdata->res.clientid;
                clp->cl_exchange_flags = cdata->res.flags;
+               clp->cl_seqid = cdata->res.seqid;
                /* Client ID is not confirmed */
-               if (!(cdata->res.flags & EXCHGID4_FLAG_CONFIRMED_R)) {
+               if (!(cdata->res.flags & EXCHGID4_FLAG_CONFIRMED_R))
                        clear_bit(NFS4_SESSION_ESTABLISHED,
-                       &clp->cl_session->session_state);
-                       clp->cl_seqid = cdata->res.seqid;
-               }
+                                 &clp->cl_session->session_state);
  
                kfree(clp->cl_serverowner);
                clp->cl_serverowner = cdata->res.server_owner;
@@@ -8417,7 -8466,6 +8467,7 @@@ static void nfs4_layoutget_release(voi
        size_t max_pages = max_response_pages(server);
  
        dprintk("--> %s\n", __func__);
 +      nfs4_sequence_free_slot(&lgp->res.seq_res);
        nfs4_free_pages(lgp->args.layout.pages, max_pages);
        pnfs_put_layout_hdr(NFS_I(inode)->layout);
        put_nfs_open_context(lgp->args.ctx);
@@@ -8492,6 -8540,7 +8542,6 @@@ nfs4_proc_layoutget(struct nfs4_layoutg
        /* if layoutp->len is 0, nfs4_layoutget_prepare called rpc_exit */
        if (status == 0 && lgp->res.layoutp->len)
                lseg = pnfs_layout_process(lgp);
 -      nfs4_sequence_free_slot(&lgp->res.seq_res);
        rpc_put_task(task);
        dprintk("<-- %s status=%d\n", __func__, status);
        if (status)
@@@ -9313,6 -9362,7 +9363,7 @@@ const struct nfs_rpc_ops nfs_v4_cliento
        .getattr        = nfs4_proc_getattr,
        .setattr        = nfs4_proc_setattr,
        .lookup         = nfs4_proc_lookup,
+       .lookupp        = nfs4_proc_lookupp,
        .access         = nfs4_proc_access,
        .readlink       = nfs4_proc_readlink,
        .create         = nfs4_proc_create,
diff --combined fs/nfs/nfs4state.c
@@@ -352,11 -352,17 +352,17 @@@ int nfs41_discover_server_trunking(stru
        if (clp != *result)
                return 0;
  
-       /* Purge state if the client id was established in a prior instance */
-       if (clp->cl_exchange_flags & EXCHGID4_FLAG_CONFIRMED_R)
-               set_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state);
-       else
-               set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
+       /*
+        * Purge state if the client id was established in a prior
+        * instance and the client id could not have arrived on the
+        * server via Transparent State Migration.
+        */
+       if (clp->cl_exchange_flags & EXCHGID4_FLAG_CONFIRMED_R) {
+               if (!test_bit(NFS_CS_TSM_POSSIBLE, &clp->cl_flags))
+                       set_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state);
+               else
+                       set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
+       }
        nfs4_schedule_state_manager(clp);
        status = nfs_wait_client_init_complete(clp);
        if (status < 0)
@@@ -2134,8 -2140,6 +2140,8 @@@ again
        put_rpccred(cred);
        switch (status) {
        case 0:
 +      case -EINTR:
 +      case -ERESTARTSYS:
                break;
        case -ETIMEDOUT:
                if (clnt->cl_softrtry)
diff --combined fs/nfs/super.c
@@@ -879,7 -879,7 +879,7 @@@ int nfs_show_stats(struct seq_file *m, 
        if (nfss->options & NFS_OPTION_FSCACHE) {
                seq_printf(m, "\n\tfsc:\t");
                for (i = 0; i < __NFSIOS_FSCACHEMAX; i++)
-                       seq_printf(m, "%Lu ", totals.bytes[i]);
+                       seq_printf(m, "%Lu ", totals.fscache[i]);
        }
  #endif
        seq_printf(m, "\n");
@@@ -2339,6 -2339,7 +2339,7 @@@ void nfs_fill_super(struct super_block 
                 */
                sb->s_flags |= MS_POSIXACL;
                sb->s_time_gran = 1;
+               sb->s_export_op = &nfs_export_ops;
        }
  
        nfs_initialise_sb(sb);
@@@ -2360,6 -2361,7 +2361,7 @@@ static void nfs_clone_super(struct supe
        sb->s_xattr = old_sb->s_xattr;
        sb->s_op = old_sb->s_op;
        sb->s_time_gran = 1;
+       sb->s_export_op = old_sb->s_export_op;
  
        if (server->nfs_client->rpc_ops->version != 2) {
                /* The VFS shouldn't apply the umask to mode bits. We will do
@@@ -2545,25 -2547,10 +2547,25 @@@ EXPORT_SYMBOL_GPL(nfs_set_sb_security)
  int nfs_clone_sb_security(struct super_block *s, struct dentry *mntroot,
                          struct nfs_mount_info *mount_info)
  {
 +      int error;
 +      unsigned long kflags = 0, kflags_out = 0;
 +
        /* clone any lsm security options from the parent to the new sb */
        if (d_inode(mntroot)->i_op != NFS_SB(s)->nfs_client->rpc_ops->dir_inode_ops)
                return -ESTALE;
 -      return security_sb_clone_mnt_opts(mount_info->cloned->sb, s);
 +
 +      if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL)
 +              kflags |= SECURITY_LSM_NATIVE_LABELS;
 +
 +      error = security_sb_clone_mnt_opts(mount_info->cloned->sb, s, kflags,
 +                      &kflags_out);
 +      if (error)
 +              return error;
 +
 +      if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL &&
 +              !(kflags_out & SECURITY_LSM_NATIVE_LABELS))
 +              NFS_SB(s)->caps &= ~NFS_CAP_SECURITY_LABEL;
 +      return 0;
  }
  EXPORT_SYMBOL_GPL(nfs_clone_sb_security);