]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
Merge tag 'nfs-for-3.12-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 9 Sep 2013 16:19:15 +0000 (09:19 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 9 Sep 2013 16:19:15 +0000 (09:19 -0700)
Pull NFS client updates from Trond Myklebust:
 "Highlights include:

   - Fix NFSv4 recovery so that it doesn't recover lost locks in cases
     such as lease loss due to a network partition, where doing so may
     result in data corruption.  Add a kernel parameter to control
     choice of legacy behaviour or not.
   - Performance improvements when 2 processes are writing to the same
     file.
   - Flush data to disk when an RPCSEC_GSS session timeout is imminent.
   - Implement NFSv4.1 SP4_MACH_CRED state protection to prevent other
     NFS clients from being able to manipulate our lease and file
     locking state.
   - Allow sharing of RPCSEC_GSS caches between different rpc clients.
   - Fix the broken NFSv4 security auto-negotiation between client and
     server.
   - Fix rmdir() to wait for outstanding sillyrename unlinks to complete
   - Add a tracepoint framework for debugging NFSv4 state recovery
     issues.
   - Add tracing to the generic NFS layer.
   - Add tracing for the SUNRPC socket connection state.
   - Clean up the rpc_pipefs mount/umount event management.
   - Merge more patches from Chuck in preparation for NFSv4 migration
     support"

* tag 'nfs-for-3.12-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (107 commits)
  NFSv4: use mach cred for SECINFO_NO_NAME w/ integrity
  NFS: nfs_compare_super shouldn't check the auth flavour unless 'sec=' was set
  NFSv4: Allow security autonegotiation for submounts
  NFSv4: Disallow security negotiation for lookups when 'sec=' is specified
  NFSv4: Fix security auto-negotiation
  NFS: Clean up nfs_parse_security_flavors()
  NFS: Clean up the auth flavour array mess
  NFSv4.1 Use MDS auth flavor for data server connection
  NFS: Don't check lock owner compatability unless file is locked (part 2)
  NFS: Don't check lock owner compatibility in writes unless file is locked
  nfs4: Map NFS4ERR_WRONG_CRED to EPERM
  nfs4.1: Add SP4_MACH_CRED write and commit support
  nfs4.1: Add SP4_MACH_CRED stateid support
  nfs4.1: Add SP4_MACH_CRED secinfo support
  nfs4.1: Add SP4_MACH_CRED cleanup support
  nfs4.1: Add state protection handler
  nfs4.1: Minimal SP4_MACH_CRED implementation
  SUNRPC: Replace pointer values with task->tk_pid and rpc_clnt->cl_clid
  SUNRPC: Add an identifier for struct rpc_clnt
  SUNRPC: Ensure rpc_task->tk_pid is available for tracepoints
  ...

1  2 
Documentation/kernel-parameters.txt
fs/nfs/dir.c
fs/nfs/inode.c
fs/nfs/nfs4proc.c
fs/nfs/super.c
include/linux/sunrpc/sched.h
net/sunrpc/clnt.c
net/sunrpc/xprtsock.c

index 479eeaf440248b8d56dca90775be614b7cbc9e9e,30584b194984d12005e91b82d21204c5068e91aa..1a036cd972fb0c205109ed66b968c3d771f66418
@@@ -235,61 -235,10 +235,61 @@@ bytes respectively. Such letter suffixe
                        Format: To spoof as Windows 98: ="Microsoft Windows"
  
        acpi_osi=       [HW,ACPI] Modify list of supported OS interface strings
 -                      acpi_osi="string1"      # add string1 -- only one string
 -                      acpi_osi="!string2"     # remove built-in string2
 +                      acpi_osi="string1"      # add string1
 +                      acpi_osi="!string2"     # remove string2
 +                      acpi_osi=!*             # remove all strings
 +                      acpi_osi=!              # disable all built-in OS vendor
 +                                                strings
                        acpi_osi=               # disable all strings
  
 +                      'acpi_osi=!' can be used in combination with single or
 +                      multiple 'acpi_osi="string1"' to support specific OS
 +                      vendor string(s).  Note that such command can only
 +                      affect the default state of the OS vendor strings, thus
 +                      it cannot affect the default state of the feature group
 +                      strings and the current state of the OS vendor strings,
 +                      specifying it multiple times through kernel command line
 +                      is meaningless.  This command is useful when one do not
 +                      care about the state of the feature group strings which
 +                      should be controlled by the OSPM.
 +                      Examples:
 +                        1. 'acpi_osi=! acpi_osi="Windows 2000"' is equivalent
 +                           to 'acpi_osi="Windows 2000" acpi_osi=!', they all
 +                           can make '_OSI("Windows 2000")' TRUE.
 +
 +                      'acpi_osi=' cannot be used in combination with other
 +                      'acpi_osi=' command lines, the _OSI method will not
 +                      exist in the ACPI namespace.  NOTE that such command can
 +                      only affect the _OSI support state, thus specifying it
 +                      multiple times through kernel command line is also
 +                      meaningless.
 +                      Examples:
 +                        1. 'acpi_osi=' can make 'CondRefOf(_OSI, Local1)'
 +                           FALSE.
 +
 +                      'acpi_osi=!*' can be used in combination with single or
 +                      multiple 'acpi_osi="string1"' to support specific
 +                      string(s).  Note that such command can affect the
 +                      current state of both the OS vendor strings and the
 +                      feature group strings, thus specifying it multiple times
 +                      through kernel command line is meaningful.  But it may
 +                      still not able to affect the final state of a string if
 +                      there are quirks related to this string.  This command
 +                      is useful when one want to control the state of the
 +                      feature group strings to debug BIOS issues related to
 +                      the OSPM features.
 +                      Examples:
 +                        1. 'acpi_osi="Module Device" acpi_osi=!*' can make
 +                           '_OSI("Module Device")' FALSE.
 +                        2. 'acpi_osi=!* acpi_osi="Module Device"' can make
 +                           '_OSI("Module Device")' TRUE.
 +                        3. 'acpi_osi=! acpi_osi=!* acpi_osi="Windows 2000"' is
 +                           equivalent to
 +                           'acpi_osi=!* acpi_osi=! acpi_osi="Windows 2000"'
 +                           and
 +                           'acpi_osi=!* acpi_osi="Windows 2000" acpi_osi=!',
 +                           they all will make '_OSI("Windows 2000")' TRUE.
 +
        acpi_pm_good    [X86]
                        Override the pmtimer bug detection: force the kernel
                        to assume that this machine's pmtimer latches its value
                        will be sent.
                        The default is to send the implementation identification
                        information.
+       
+       nfs.recover_lost_locks =
+                       [NFSv4] Attempt to recover locks that were lost due
+                       to a lease timeout on the server. Please note that
+                       doing this risks data corruption, since there are
+                       no guarantees that the file will remain unchanged
+                       after the locks are lost.
+                       If you want to enable the kernel legacy behaviour of
+                       attempting to recover these locks, then set this
+                       parameter to '1'.
+                       The default parameter value of '0' causes the kernel
+                       not to attempt recovery of lost locks.
  
        nfsd.nfs4_disable_idmapping=
                        [NFSv4] When set to the default of '1', the NFSv4
                        improve throughput, but will also increase the
                        amount of memory reserved for use by the client.
  
 -      swapaccount[=0|1]
 +      swapaccount=[0|1]
                        [KNL] Enable accounting of swap in memory resource
                        controller if no parameter or 1 is given or disable
                        it if 0 is given (See Documentation/cgroups/memory.txt)
                                    them quite hard to use for exploits but
                                    might break your system.
  
 +      vt.color=       [VT] Default text color.
 +                      Format: 0xYX, X = foreground, Y = background.
 +                      Default: 0x07 = light gray on black.
 +
        vt.cur_default= [VT] Default cursor shape.
                        Format: 0xCCBBAA, where AA, BB, and CC are the same as
                        the parameters of the <Esc>[?A;B;Cc escape sequence;
                        overridden by individual drivers. 0 will hide
                        cursors, 1 will display them.
  
 +      vt.italic=      [VT] Default color for italic text; 0-15.
 +                      Default: 2 = green.
 +
 +      vt.underline=   [VT] Default color for underlined text; 0-15.
 +                      Default: 3 = cyan.
 +
        watchdog timers [HW,WDT] For information on watchdog timers,
                        see Documentation/watchdog/watchdog-parameters.txt
                        or other driver-specific files in the
diff --combined fs/nfs/dir.c
index 7468735d299ed1d4d027ee783b5eeb806f62944a,187caa47dad979ca8bd1a2c0013703284daab6f0..e79bc6ce828e79b8cd3f4f6795de20f2c3ceb675
@@@ -43,6 -43,8 +43,8 @@@
  #include "internal.h"
  #include "fscache.h"
  
+ #include "nfstrace.h"
  /* #define NFS_DEBUG_VERBOSE 1 */
  
  static int nfs_opendir(struct inode *, struct file *);
@@@ -1100,7 -1102,9 +1102,9 @@@ static int nfs_lookup_revalidate(struc
        if (IS_ERR(label))
                goto out_error;
  
+       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)
                goto out_bad;
        if (nfs_compare_fh(NFS_FH(inode), fhandle))
@@@ -1135,13 -1139,14 +1139,13 @@@ out_zap_parent
        if (inode && S_ISDIR(inode->i_mode)) {
                /* Purge readdir caches. */
                nfs_zap_caches(inode);
 -              /* If we have submounts, don't unhash ! */
 -              if (have_submounts(dentry))
 -                      goto out_valid;
                if (dentry->d_flags & DCACHE_DISCONNECTED)
                        goto out_valid;
 -              shrink_dcache_parent(dentry);
        }
 -      d_drop(dentry);
 +      /* If we have submounts, don't unhash ! */
 +      if (check_submounts_and_drop(dentry) != 0)
 +              goto out_valid;
 +
        dput(parent);
        dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is invalid\n",
                        __func__, dentry->d_parent->d_name.name,
@@@ -1312,6 -1317,7 +1316,7 @@@ struct dentry *nfs_lookup(struct inode 
  
        parent = dentry->d_parent;
        /* Protect against concurrent sillydeletes */
+       trace_nfs_lookup_enter(dir, dentry, flags);
        nfs_block_sillyrename(parent);
        error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label);
        if (error == -ENOENT)
@@@ -1338,6 -1344,7 +1343,7 @@@ no_entry
        nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
  out_unblock_sillyrename:
        nfs_unblock_sillyrename(parent);
+       trace_nfs_lookup_exit(dir, dentry, flags, error);
        nfs4_label_free(label);
  out:
        nfs_free_fattr(fattr);
@@@ -1392,7 -1399,6 +1398,6 @@@ static int nfs_finish_open(struct nfs_o
        nfs_file_set_open_context(file, ctx);
  
  out:
-       put_nfs_open_context(ctx);
        return err;
  }
  
@@@ -1404,6 -1410,7 +1409,7 @@@ int nfs_atomic_open(struct inode *dir, 
        struct dentry *res;
        struct iattr attr = { .ia_valid = ATTR_OPEN };
        struct inode *inode;
+       unsigned int lookup_flags = 0;
        int err;
  
        /* Expect a negative dentry */
        dfprintk(VFS, "NFS: atomic_open(%s/%ld), %s\n",
                        dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);
  
+       err = nfs_check_flags(open_flags);
+       if (err)
+               return err;
        /* NFS only supports OPEN on regular files */
        if ((open_flags & O_DIRECTORY)) {
                if (!d_unhashed(dentry)) {
                         */
                        return -ENOENT;
                }
+               lookup_flags = LOOKUP_OPEN|LOOKUP_DIRECTORY;
                goto no_open;
        }
  
        if (IS_ERR(ctx))
                goto out;
  
+       trace_nfs_atomic_open_enter(dir, ctx, open_flags);
        nfs_block_sillyrename(dentry->d_parent);
        inode = NFS_PROTO(dir)->open_context(dir, ctx, open_flags, &attr);
        nfs_unblock_sillyrename(dentry->d_parent);
        if (IS_ERR(inode)) {
-               put_nfs_open_context(ctx);
                err = PTR_ERR(inode);
+               trace_nfs_atomic_open_exit(dir, ctx, open_flags, err);
+               put_nfs_open_context(ctx);
                switch (err) {
                case -ENOENT:
                        d_drop(dentry);
        }
  
        err = nfs_finish_open(ctx, ctx->dentry, file, open_flags, opened);
+       trace_nfs_atomic_open_exit(dir, ctx, open_flags, err);
+       put_nfs_open_context(ctx);
  out:
        return err;
  
  no_open:
-       res = nfs_lookup(dir, dentry, 0);
+       res = nfs_lookup(dir, dentry, lookup_flags);
        err = PTR_ERR(res);
        if (IS_ERR(res))
                goto out;
@@@ -1596,7 -1612,9 +1611,9 @@@ int nfs_create(struct inode *dir, struc
        attr.ia_mode = mode;
        attr.ia_valid = ATTR_MODE;
  
+       trace_nfs_create_enter(dir, dentry, open_flags);
        error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags);
+       trace_nfs_create_exit(dir, dentry, open_flags, error);
        if (error != 0)
                goto out_err;
        return 0;
@@@ -1624,7 -1642,9 +1641,9 @@@ nfs_mknod(struct inode *dir, struct den
        attr.ia_mode = mode;
        attr.ia_valid = ATTR_MODE;
  
+       trace_nfs_mknod_enter(dir, dentry);
        status = NFS_PROTO(dir)->mknod(dir, dentry, &attr, rdev);
+       trace_nfs_mknod_exit(dir, dentry, status);
        if (status != 0)
                goto out_err;
        return 0;
@@@ -1648,7 -1668,9 +1667,9 @@@ int nfs_mkdir(struct inode *dir, struc
        attr.ia_valid = ATTR_MODE;
        attr.ia_mode = mode | S_IFDIR;
  
+       trace_nfs_mkdir_enter(dir, dentry);
        error = NFS_PROTO(dir)->mkdir(dir, dentry, &attr);
+       trace_nfs_mkdir_exit(dir, dentry, error);
        if (error != 0)
                goto out_err;
        return 0;
@@@ -1671,12 -1693,21 +1692,21 @@@ int nfs_rmdir(struct inode *dir, struc
        dfprintk(VFS, "NFS: rmdir(%s/%ld), %s\n",
                        dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);
  
-       error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name);
-       /* Ensure the VFS deletes this inode */
-       if (error == 0 && dentry->d_inode != NULL)
-               clear_nlink(dentry->d_inode);
-       else if (error == -ENOENT)
-               nfs_dentry_handle_enoent(dentry);
+       trace_nfs_rmdir_enter(dir, dentry);
+       if (dentry->d_inode) {
+               nfs_wait_on_sillyrename(dentry);
+               error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name);
+               /* Ensure the VFS deletes this inode */
+               switch (error) {
+               case 0:
+                       clear_nlink(dentry->d_inode);
+                       break;
+               case -ENOENT:
+                       nfs_dentry_handle_enoent(dentry);
+               }
+       } else
+               error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name);
+       trace_nfs_rmdir_exit(dir, dentry, error);
  
        return error;
  }
@@@ -1704,6 -1735,7 +1734,7 @@@ static int nfs_safe_remove(struct dentr
                goto out;
        }
  
+       trace_nfs_remove_enter(dir, dentry);
        if (inode != NULL) {
                NFS_PROTO(inode)->return_delegation(inode);
                error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
                error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
        if (error == -ENOENT)
                nfs_dentry_handle_enoent(dentry);
+       trace_nfs_remove_exit(dir, dentry, error);
  out:
        return error;
  }
@@@ -1730,13 -1763,14 +1762,14 @@@ int nfs_unlink(struct inode *dir, struc
        dfprintk(VFS, "NFS: unlink(%s/%ld, %s)\n", dir->i_sb->s_id,
                dir->i_ino, dentry->d_name.name);
  
+       trace_nfs_unlink_enter(dir, dentry);
        spin_lock(&dentry->d_lock);
        if (d_count(dentry) > 1) {
                spin_unlock(&dentry->d_lock);
                /* Start asynchronous writeout of the inode */
                write_inode_now(dentry->d_inode, 0);
                error = nfs_sillyrename(dir, dentry);
-               return error;
+               goto out;
        }
        if (!d_unhashed(dentry)) {
                __d_drop(dentry);
                nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
        } else if (need_rehash)
                d_rehash(dentry);
+ out:
+       trace_nfs_unlink_exit(dir, dentry, error);
        return error;
  }
  EXPORT_SYMBOL_GPL(nfs_unlink);
@@@ -1794,7 -1830,9 +1829,9 @@@ int nfs_symlink(struct inode *dir, stru
                memset(kaddr + pathlen, 0, PAGE_SIZE - pathlen);
        kunmap_atomic(kaddr);
  
+       trace_nfs_symlink_enter(dir, dentry);
        error = NFS_PROTO(dir)->symlink(dir, dentry, page, pathlen, &attr);
+       trace_nfs_symlink_exit(dir, dentry, error);
        if (error != 0) {
                dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s) error %d\n",
                        dir->i_sb->s_id, dir->i_ino,
@@@ -1829,6 -1867,7 +1866,7 @@@ nfs_link(struct dentry *old_dentry, str
                old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
                dentry->d_parent->d_name.name, dentry->d_name.name);
  
+       trace_nfs_link_enter(inode, dir, dentry);
        NFS_PROTO(inode)->return_delegation(inode);
  
        d_drop(dentry);
                ihold(inode);
                d_add(dentry, inode);
        }
+       trace_nfs_link_exit(inode, dir, dentry, error);
        return error;
  }
  EXPORT_SYMBOL_GPL(nfs_link);
@@@ -1878,6 -1918,7 +1917,7 @@@ int nfs_rename(struct inode *old_dir, s
                 new_dentry->d_parent->d_name.name, new_dentry->d_name.name,
                 d_count(new_dentry));
  
+       trace_nfs_rename_enter(old_dir, old_dentry, new_dir, new_dentry);
        /*
         * For non-directories, check whether the target is busy and if so,
         * make a copy of the dentry and then do a silly-rename. If the
  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);
@@@ -2173,9 -2216,11 +2215,11 @@@ static int nfs_do_access(struct inode *
        struct nfs_access_entry cache;
        int status;
  
+       trace_nfs_access_enter(inode);
        status = nfs_access_get_cached(inode, cred, &cache);
        if (status == 0)
-               goto out;
+               goto out_cached;
  
        /* Be clever: ask server to check for all possible rights */
        cache.mask = MAY_EXEC | MAY_WRITE | MAY_READ;
                        if (!S_ISDIR(inode->i_mode))
                                set_bit(NFS_INO_STALE, &NFS_I(inode)->flags);
                }
-               return status;
+               goto out;
        }
        nfs_access_add_cache(inode, &cache);
+ out_cached:
+       if ((mask & ~cache.mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) != 0)
+               status = -EACCES;
  out:
-       if ((mask & ~cache.mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0)
-               return 0;
-       return -EACCES;
+       trace_nfs_access_exit(inode, status);
+       return status;
  }
  
  static int nfs_open_permission_mask(int openflags)
@@@ -2240,11 -2287,6 +2286,6 @@@ int nfs_permission(struct inode *inode
                case S_IFLNK:
                        goto out;
                case S_IFREG:
-                       /* NFSv4 has atomic_open... */
-                       if (nfs_server_capable(inode, NFS_CAP_ATOMIC_OPEN)
-                                       && (mask & MAY_OPEN)
-                                       && !(mask & MAY_EXEC))
-                               goto out;
                        break;
                case S_IFDIR:
                        /*
diff --combined fs/nfs/inode.c
index 941246f2b43d266827666dee7fec5051c2289586,4bcb00ae30ae9725d90243e04f21d9a82960e566..87e7976408281f93fe350d797960617de4f33c70
@@@ -38,7 -38,6 +38,6 @@@
  #include <linux/slab.h>
  #include <linux/compat.h>
  #include <linux/freezer.h>
- #include <linux/crc32.h>
  
  #include <asm/uaccess.h>
  
@@@ -52,6 -51,8 +51,8 @@@
  #include "nfs.h"
  #include "netns.h"
  
+ #include "nfstrace.h"
  #define NFSDBG_FACILITY               NFSDBG_VFS
  
  #define NFS_64_BIT_INODE_NUMBERS_ENABLED      1
@@@ -463,6 -464,7 +464,6 @@@ nfs_fhget(struct super_block *sb, struc
                unlock_new_inode(inode);
        } else
                nfs_refresh_inode(inode, fattr);
 -              nfs_setsecurity(inode, fattr, label);
        dprintk("NFS: nfs_fhget(%s/%Ld fh_crc=0x%08x ct=%d)\n",
                inode->i_sb->s_id,
                (long long)NFS_FILEID(inode),
@@@ -503,6 -505,8 +504,8 @@@ nfs_setattr(struct dentry *dentry, stru
        if ((attr->ia_valid & ~(ATTR_FILE|ATTR_OPEN)) == 0)
                return 0;
  
+       trace_nfs_setattr_enter(inode);
        /* Write all dirty data */
        if (S_ISREG(inode->i_mode)) {
                nfs_inode_dio_wait(inode);
                error = nfs_refresh_inode(inode, fattr);
        nfs_free_fattr(fattr);
  out:
+       trace_nfs_setattr_exit(inode, error);
        return error;
  }
  EXPORT_SYMBOL_GPL(nfs_setattr);
@@@ -591,6 -596,7 +595,7 @@@ int nfs_getattr(struct vfsmount *mnt, s
        int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME;
        int err;
  
+       trace_nfs_getattr_enter(inode);
        /* Flush out writes to the server in order to update c/mtime.  */
        if (S_ISREG(inode->i_mode)) {
                nfs_inode_dio_wait(inode);
                stat->ino = nfs_compat_user_ino64(NFS_FILEID(inode));
        }
  out:
+       trace_nfs_getattr_exit(inode, err);
        return err;
  }
  EXPORT_SYMBOL_GPL(nfs_getattr);
@@@ -875,6 -882,8 +881,8 @@@ __nfs_revalidate_inode(struct nfs_serve
        dfprintk(PAGECACHE, "NFS: revalidating (%s/%Ld)\n",
                inode->i_sb->s_id, (long long)NFS_FILEID(inode));
  
+       trace_nfs_revalidate_inode_enter(inode);
        if (is_bad_inode(inode))
                goto out;
        if (NFS_STALE(inode))
@@@ -925,6 -934,7 +933,7 @@@ err_out
        nfs4_label_free(label);
  out:
        nfs_free_fattr(fattr);
+       trace_nfs_revalidate_inode_exit(inode, status);
        return status;
  }
  
@@@ -962,15 -972,9 +971,15 @@@ EXPORT_SYMBOL_GPL(nfs_revalidate_inode)
  static int nfs_invalidate_mapping(struct inode *inode, struct address_space *mapping)
  {
        struct nfs_inode *nfsi = NFS_I(inode);
 -      
 +      int ret;
 +
        if (mapping->nrpages != 0) {
 -              int ret = invalidate_inode_pages2(mapping);
 +              if (S_ISREG(inode->i_mode)) {
 +                      ret = nfs_sync_mapping(mapping);
 +                      if (ret < 0)
 +                              return ret;
 +              }
 +              ret = invalidate_inode_pages2(mapping);
                if (ret < 0)
                        return ret;
        }
        spin_unlock(&inode->i_lock);
        nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE);
        nfs_fscache_wait_on_invalidate(inode);
        dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n",
                        inode->i_sb->s_id, (long long)NFS_FILEID(inode));
        return 0;
@@@ -1014,8 -1019,12 +1024,12 @@@ int nfs_revalidate_mapping(struct inod
                if (ret < 0)
                        goto out;
        }
-       if (nfsi->cache_validity & NFS_INO_INVALID_DATA)
+       if (nfsi->cache_validity & NFS_INO_INVALID_DATA) {
+               trace_nfs_invalidate_mapping_enter(inode);
                ret = nfs_invalidate_mapping(inode, mapping);
+               trace_nfs_invalidate_mapping_exit(inode, ret);
+       }
  out:
        return ret;
  }
@@@ -1195,7 -1204,7 +1209,7 @@@ u32 _nfs_display_fhandle_hash(const str
  {
        /* wireshark uses 32-bit AUTODIN crc and does a bitwise
         * not on the result */
-       return ~crc32(0xFFFFFFFF, &fh->data[0], fh->size);
+       return nfs_fhandle_hash(fh);
  }
  
  /*
@@@ -1274,9 -1283,17 +1288,17 @@@ static int nfs_inode_attrs_need_update(
  
  static int nfs_refresh_inode_locked(struct inode *inode, struct nfs_fattr *fattr)
  {
+       int ret;
+       trace_nfs_refresh_inode_enter(inode);
        if (nfs_inode_attrs_need_update(inode, fattr))
-               return nfs_update_inode(inode, fattr);
-       return nfs_check_inode_attributes(inode, fattr);
+               ret = nfs_update_inode(inode, fattr);
+       else
+               ret = nfs_check_inode_attributes(inode, fattr);
+       trace_nfs_refresh_inode_exit(inode, ret);
+       return ret;
  }
  
  /**
diff --combined fs/nfs/nfs4proc.c
index 108a774095f7ef6a53fc04366aec3caa3bfea717,e1212914bc039542298d990b4e4201daddfa8b7f..39b6cf2d1683fae228f71d1954383f53550e0439
@@@ -66,6 -66,8 +66,8 @@@
  #include "nfs4session.h"
  #include "fscache.h"
  
+ #include "nfs4trace.h"
  #define NFSDBG_FACILITY               NFSDBG_PROC
  
  #define NFS4_POLL_RETRY_MIN   (HZ/10)
@@@ -150,6 -152,7 +152,7 @@@ static int nfs4_map_errors(int err
        case -NFS4ERR_RECALLCONFLICT:
                return -EREMOTEIO;
        case -NFS4ERR_WRONGSEC:
+       case -NFS4ERR_WRONG_CRED:
                return -EPERM;
        case -NFS4ERR_BADOWNER:
        case -NFS4ERR_BADNAME:
@@@ -433,6 -436,20 +436,20 @@@ wait_on_recovery
        return ret;
  }
  
+ /*
+  * Return 'true' if 'clp' is using an rpc_client that is integrity protected
+  * or 'false' otherwise.
+  */
+ static bool _nfs4_is_integrity_protected(struct nfs_client *clp)
+ {
+       rpc_authflavor_t flavor = clp->cl_rpcclient->cl_auth->au_flavor;
+       if (flavor == RPC_AUTH_GSS_KRB5I ||
+           flavor == RPC_AUTH_GSS_KRB5P)
+               return true;
+       return false;
+ }
  
  static void do_renew_lease(struct nfs_client *clp, unsigned long timestamp)
  {
@@@ -447,6 -464,88 +464,88 @@@ static void renew_lease(const struct nf
        do_renew_lease(server->nfs_client, timestamp);
  }
  
+ struct nfs4_call_sync_data {
+       const struct nfs_server *seq_server;
+       struct nfs4_sequence_args *seq_args;
+       struct nfs4_sequence_res *seq_res;
+ };
+ static void nfs4_init_sequence(struct nfs4_sequence_args *args,
+                              struct nfs4_sequence_res *res, int cache_reply)
+ {
+       args->sa_slot = NULL;
+       args->sa_cache_this = cache_reply;
+       args->sa_privileged = 0;
+       res->sr_slot = NULL;
+ }
+ static void nfs4_set_sequence_privileged(struct nfs4_sequence_args *args)
+ {
+       args->sa_privileged = 1;
+ }
+ static int nfs40_setup_sequence(const struct nfs_server *server,
+                               struct nfs4_sequence_args *args,
+                               struct nfs4_sequence_res *res,
+                               struct rpc_task *task)
+ {
+       struct nfs4_slot_table *tbl = server->nfs_client->cl_slot_tbl;
+       struct nfs4_slot *slot;
+       /* slot already allocated? */
+       if (res->sr_slot != NULL)
+               goto out_start;
+       spin_lock(&tbl->slot_tbl_lock);
+       if (nfs4_slot_tbl_draining(tbl) && !args->sa_privileged)
+               goto out_sleep;
+       slot = nfs4_alloc_slot(tbl);
+       if (IS_ERR(slot)) {
+               if (slot == ERR_PTR(-ENOMEM))
+                       task->tk_timeout = HZ >> 2;
+               goto out_sleep;
+       }
+       spin_unlock(&tbl->slot_tbl_lock);
+       args->sa_slot = slot;
+       res->sr_slot = slot;
+ out_start:
+       rpc_call_start(task);
+       return 0;
+ out_sleep:
+       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;
+ }
+ static int nfs40_sequence_done(struct rpc_task *task,
+                              struct nfs4_sequence_res *res)
+ {
+       struct nfs4_slot *slot = res->sr_slot;
+       struct nfs4_slot_table *tbl;
+       if (!RPC_WAS_SENT(task))
+               goto out;
+       tbl = slot->table;
+       spin_lock(&tbl->slot_tbl_lock);
+       if (!nfs41_wake_and_assign_slot(tbl, slot))
+               nfs4_free_slot(tbl, slot);
+       spin_unlock(&tbl->slot_tbl_lock);
+       res->sr_slot = NULL;
+ out:
+       return 1;
+ }
  #if defined(CONFIG_NFS_V4_1)
  
  static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
@@@ -506,6 -605,7 +605,7 @@@ static int nfs41_sequence_done(struct r
                interrupted = true;
        }
  
+       trace_nfs4_sequence_done(session, res);
        /* Check the SEQUENCE operation status */
        switch (res->sr_status) {
        case 0:
@@@ -591,25 -691,11 +691,11 @@@ static int nfs4_sequence_done(struct rp
  {
        if (res->sr_slot == NULL)
                return 1;
+       if (!res->sr_slot->table->session)
+               return nfs40_sequence_done(task, res);
        return nfs41_sequence_done(task, res);
  }
  
- static void nfs41_init_sequence(struct nfs4_sequence_args *args,
-               struct nfs4_sequence_res *res, int cache_reply)
- {
-       args->sa_slot = NULL;
-       args->sa_cache_this = 0;
-       args->sa_privileged = 0;
-       if (cache_reply)
-               args->sa_cache_this = 1;
-       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,
  
        args->sa_slot = slot;
  
-       dprintk("<-- %s slotid=%d seqid=%d\n", __func__,
+       dprintk("<-- %s slotid=%u seqid=%u\n", __func__,
                        slot->slot_nr, slot->seq_nr);
  
        res->sr_slot = slot;
         * set to 1 if an rpc level failure occurs.
         */
        res->sr_status = 1;
+       trace_nfs4_setup_sequence(session, args);
  out_success:
        rpc_call_start(task);
        return 0;
@@@ -673,38 -760,30 +760,30 @@@ out_sleep
  }
  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,
-                       struct rpc_task *task)
static int nfs4_setup_sequence(const struct nfs_server *server,
+                              struct nfs4_sequence_args *args,
+                              struct nfs4_sequence_res *res,
+                              struct rpc_task *task)
  {
        struct nfs4_session *session = nfs4_get_session(server);
        int ret = 0;
  
-       if (session == NULL) {
-               rpc_call_start(task);
-               goto out;
-       }
+       if (!session)
+               return nfs40_setup_sequence(server, args, res, task);
  
-       dprintk("--> %s clp %p session %p sr_slot %d\n",
+       dprintk("--> %s clp %p session %p sr_slot %u\n",
                __func__, session->clp, session, res->sr_slot ?
-                       res->sr_slot->slot_nr : -1);
+                       res->sr_slot->slot_nr : NFS4_NO_SLOT);
  
        ret = nfs41_setup_sequence(session, args, res, task);
- out:
        dprintk("<-- %s status=%d\n", __func__, ret);
        return ret;
  }
  
- struct nfs41_call_sync_data {
-       const struct nfs_server *seq_server;
-       struct nfs4_sequence_args *seq_args;
-       struct nfs4_sequence_res *seq_res;
- };
  static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata)
  {
-       struct nfs41_call_sync_data *data = calldata;
+       struct nfs4_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);
  
  static void nfs41_call_sync_done(struct rpc_task *task, void *calldata)
  {
-       struct nfs41_call_sync_data *data = calldata;
+       struct nfs4_call_sync_data *data = calldata;
  
        nfs41_sequence_done(task, data->seq_res);
  }
@@@ -724,6 -803,42 +803,42 @@@ static const struct rpc_call_ops nfs41_
        .rpc_call_done = nfs41_call_sync_done,
  };
  
+ #else /* !CONFIG_NFS_V4_1 */
+ static int nfs4_setup_sequence(const struct nfs_server *server,
+                              struct nfs4_sequence_args *args,
+                              struct nfs4_sequence_res *res,
+                              struct rpc_task *task)
+ {
+       return nfs40_setup_sequence(server, args, res, task);
+ }
+ static int nfs4_sequence_done(struct rpc_task *task,
+                              struct nfs4_sequence_res *res)
+ {
+       return nfs40_sequence_done(task, res);
+ }
+ #endif        /* !CONFIG_NFS_V4_1 */
+ static void nfs40_call_sync_prepare(struct rpc_task *task, void *calldata)
+ {
+       struct nfs4_call_sync_data *data = calldata;
+       nfs4_setup_sequence(data->seq_server,
+                               data->seq_args, data->seq_res, task);
+ }
+ static void nfs40_call_sync_done(struct rpc_task *task, void *calldata)
+ {
+       struct nfs4_call_sync_data *data = calldata;
+       nfs4_sequence_done(task, data->seq_res);
+ }
+ static const struct rpc_call_ops nfs40_call_sync_ops = {
+       .rpc_call_prepare = nfs40_call_sync_prepare,
+       .rpc_call_done = nfs40_call_sync_done,
+ };
  static int nfs4_call_sync_sequence(struct rpc_clnt *clnt,
                                   struct nfs_server *server,
                                   struct rpc_message *msg,
  {
        int ret;
        struct rpc_task *task;
-       struct nfs41_call_sync_data data = {
+       struct nfs_client *clp = server->nfs_client;
+       struct nfs4_call_sync_data data = {
                .seq_server = server,
                .seq_args = args,
                .seq_res = res,
        struct rpc_task_setup task_setup = {
                .rpc_client = clnt,
                .rpc_message = msg,
-               .callback_ops = &nfs41_call_sync_ops,
+               .callback_ops = clp->cl_mvops->call_sync_ops,
                .callback_data = &data
        };
  
        return ret;
  }
  
- #else
- 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)
- {
-       return 1;
- }
- #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)
- {
-       return rpc_call_sync(clnt, msg, 0);
- }
  static
  int nfs4_call_sync(struct rpc_clnt *clnt,
                   struct nfs_server *server,
                   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);
+       nfs4_init_sequence(args, res, cache_reply);
+       return nfs4_call_sync_sequence(clnt, server, msg, args, res);
  }
  
  static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo)
@@@ -933,7 -1019,7 +1019,7 @@@ static struct nfs4_opendata *nfs4_opend
                p->o_arg.fh = NFS_FH(dentry->d_inode);
        }
        if (attrs != NULL && attrs->ia_valid != 0) {
-               __be32 verf[2];
+               __u32 verf[2];
  
                p->o_arg.u.attrs = &p->attrs;
                memcpy(&p->attrs, attrs, sizeof(p->attrs));
@@@ -1103,7 -1189,7 +1189,7 @@@ static int update_open_stateid(struct n
                goto no_delegation;
  
        spin_lock(&deleg_cur->lock);
-       if (nfsi->delegation != deleg_cur ||
+       if (rcu_dereference(nfsi->delegation) != deleg_cur ||
           test_bit(NFS_DELEGATION_RETURNING, &deleg_cur->flags) ||
            (deleg_cur->type & fmode) != fmode)
                goto no_delegation_unlock;
@@@ -1440,6 -1526,7 +1526,7 @@@ static int nfs4_do_open_reclaim(struct 
        int err;
        do {
                err = _nfs4_do_open_reclaim(ctx, state);
+               trace_nfs4_open_reclaim(ctx, 0, err);
                if (nfs4_clear_cap_atomic_open_v1(server, err, &exception))
                        continue;
                if (err != -NFS4ERR_DELAY)
@@@ -1524,10 -1611,20 +1611,20 @@@ int nfs4_open_delegation_recall(struct 
        return nfs4_handle_delegation_recall_error(server, state, stateid, err);
  }
  
+ static void nfs4_open_confirm_prepare(struct rpc_task *task, void *calldata)
+ {
+       struct nfs4_opendata *data = calldata;
+       nfs40_setup_sequence(data->o_arg.server, &data->o_arg.seq_args,
+                               &data->o_res.seq_res, task);
+ }
  static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata)
  {
        struct nfs4_opendata *data = calldata;
  
+       nfs40_sequence_done(task, &data->o_res.seq_res);
        data->rpc_status = task->tk_status;
        if (data->rpc_status == 0) {
                nfs4_stateid_copy(&data->o_res.stateid, &data->c_res.stateid);
@@@ -1556,6 -1653,7 +1653,7 @@@ out_free
  }
  
  static const struct rpc_call_ops nfs4_open_confirm_ops = {
+       .rpc_call_prepare = nfs4_open_confirm_prepare,
        .rpc_call_done = nfs4_open_confirm_done,
        .rpc_release = nfs4_open_confirm_release,
  };
@@@ -1583,6 -1681,7 +1681,7 @@@ static int _nfs4_proc_open_confirm(stru
        };
        int status;
  
+       nfs4_init_sequence(&data->o_arg.seq_args, &data->o_res.seq_res, 1);
        kref_get(&data->kref);
        data->rpc_done = 0;
        data->rpc_status = 0;
@@@ -1742,7 -1841,7 +1841,7 @@@ static int nfs4_run_open_task(struct nf
        };
        int status;
  
-       nfs41_init_sequence(&o_arg->seq_args, &o_res->seq_res, 1);
+       nfs4_init_sequence(&o_arg->seq_args, &o_res->seq_res, 1);
        kref_get(&data->kref);
        data->rpc_done = 0;
        data->rpc_status = 0;
@@@ -1895,6 -1994,7 +1994,7 @@@ static int nfs4_do_open_expired(struct 
  
        do {
                err = _nfs4_open_expired(ctx, state);
+               trace_nfs4_open_expired(ctx, 0, err);
                if (nfs4_clear_cap_atomic_open_v1(server, err, &exception))
                        continue;
                switch (err) {
@@@ -1944,6 -2044,7 +2044,7 @@@ static void nfs41_clear_delegation_stat
                cred = get_rpccred(delegation->cred);
                rcu_read_unlock();
                status = nfs41_test_stateid(server, stateid, cred);
+               trace_nfs4_test_delegation_stateid(state, NULL, status);
        } else
                rcu_read_unlock();
  
@@@ -1986,6 -2087,7 +2087,7 @@@ static int nfs41_check_open_stateid(str
                return -NFS4ERR_BAD_STATEID;
  
        status = nfs41_test_stateid(server, stateid, cred);
+       trace_nfs4_test_open_stateid(state, NULL, status);
        if (status != NFS_OK) {
                /* Free the stateid unless the server explicitly
                 * informs us the stateid is unrecognized. */
@@@ -2197,6 -2299,7 +2299,7 @@@ static struct nfs4_state *nfs4_do_open(
        do {
                status = _nfs4_do_open(dir, ctx, flags, sattr, label);
                res = ctx->state;
+               trace_nfs4_open_file(ctx, flags, status);
                if (status == 0)
                        break;
                /* NOTE: BAD_SEQID means the server and client disagree about the
@@@ -2310,6 -2413,7 +2413,7 @@@ static int nfs4_do_setattr(struct inod
        int err;
        do {
                err = _nfs4_do_setattr(inode, cred, fattr, sattr, state, ilabel, olabel);
+               trace_nfs4_setattr(inode, err);
                switch (err) {
                case -NFS4ERR_OPENMODE:
                        if (!(sattr->ia_valid & ATTR_SIZE)) {
@@@ -2387,6 -2491,7 +2491,7 @@@ static void nfs4_close_done(struct rpc_
        dprintk("%s: begin!\n", __func__);
        if (!nfs4_sequence_done(task, &calldata->res.seq_res))
                return;
+       trace_nfs4_close(state, &calldata->arg, &calldata->res, task->tk_status);
          /* hmm. we are done with the inode, and in the process of freeing
         * the state_owner. we keep this around to process errors
         */
@@@ -2511,10 -2616,13 +2616,13 @@@ int nfs4_do_close(struct nfs4_state *st
        };
        int status = -ENOMEM;
  
+       nfs4_state_protect(server->nfs_client, NFS_SP4_MACH_CRED_CLEANUP,
+               &task_setup_data.rpc_client, &msg);
        calldata = kzalloc(sizeof(*calldata), gfp_mask);
        if (calldata == NULL)
                goto out;
-       nfs41_init_sequence(&calldata->arg.seq_args, &calldata->res.seq_res, 1);
+       nfs4_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);
@@@ -2690,6 -2798,7 +2798,7 @@@ static int nfs4_lookup_root(struct nfs_
        int err;
        do {
                err = _nfs4_lookup_root(server, fhandle, info);
+               trace_nfs4_lookup_root(server, fhandle, info->fattr, err);
                switch (err) {
                case 0:
                case -NFS4ERR_WRONGSEC:
  static int nfs4_lookup_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
                                struct nfs_fsinfo *info, rpc_authflavor_t flavor)
  {
+       struct rpc_auth_create_args auth_args = {
+               .pseudoflavor = flavor,
+       };
        struct rpc_auth *auth;
        int ret;
  
-       auth = rpcauth_create(flavor, server->client);
+       auth = rpcauth_create(&auth_args, server->client);
        if (IS_ERR(auth)) {
                ret = -EACCES;
                goto out;
@@@ -2772,18 -2884,27 +2884,27 @@@ static int nfs4_do_find_root_sec(struc
   * @server: initialized nfs_server handle
   * @fhandle: we fill in the pseudo-fs root file handle
   * @info: we fill in an FSINFO struct
+  * @auth_probe: probe the auth flavours
   *
   * Returns zero on success, or a negative errno.
   */
  int nfs4_proc_get_rootfh(struct nfs_server *server, struct nfs_fh *fhandle,
-                        struct nfs_fsinfo *info)
+                        struct nfs_fsinfo *info,
+                        bool auth_probe)
  {
        int status;
  
-       status = nfs4_lookup_root(server, fhandle, info);
-       if ((status == -NFS4ERR_WRONGSEC) &&
-           !(server->flags & NFS_MOUNT_SECFLAVOUR))
+       switch (auth_probe) {
+       case false:
+               status = nfs4_lookup_root(server, fhandle, info);
+               if (status != -NFS4ERR_WRONGSEC)
+                       break;
+               /* Did user force a 'sec=' mount option? */
+               if (server->flags & NFS_MOUNT_SECFLAVOUR)
+                       break;
+       default:
                status = nfs4_do_find_root_sec(server, fhandle, info);
+       }
  
        if (status == 0)
                status = nfs4_server_capabilities(server, fhandle);
@@@ -2899,8 -3020,9 +3020,9 @@@ static int nfs4_proc_getattr(struct nfs
        struct nfs4_exception exception = { };
        int err;
        do {
-               err = nfs4_handle_exception(server,
-                               _nfs4_proc_getattr(server, fhandle, fattr, label),
+               err = _nfs4_proc_getattr(server, fhandle, fattr, label);
+               trace_nfs4_getattr(server, fhandle, fattr, err);
+               err = nfs4_handle_exception(server, err,
                                &exception);
        } while (exception.retry);
        return err;
@@@ -2940,10 -3062,10 +3062,10 @@@ nfs4_proc_setattr(struct dentry *dentry
        
        /* Deal with open(O_TRUNC) */
        if (sattr->ia_valid & ATTR_OPEN)
-               sattr->ia_valid &= ~(ATTR_MTIME|ATTR_CTIME|ATTR_OPEN);
+               sattr->ia_valid &= ~(ATTR_MTIME|ATTR_CTIME);
  
        /* Optimization: if the end result is no change, don't RPC */
-       if ((sattr->ia_valid & ~(ATTR_FILE)) == 0)
+       if ((sattr->ia_valid & ~(ATTR_FILE|ATTR_OPEN)) == 0)
                return 0;
  
        /* Search for an existing open(O_WRITE) file */
@@@ -3020,6 -3142,7 +3142,7 @@@ static int nfs4_proc_lookup_common(stru
        int err;
        do {
                err = _nfs4_proc_lookup(client, dir, name, fhandle, fattr, label);
+               trace_nfs4_lookup(dir, name, err);
                switch (err) {
                case -NFS4ERR_BADNAME:
                        err = -ENOENT;
                        err = -EPERM;
                        if (client != *clnt)
                                goto out;
+                       /* No security negotiation if the user specified 'sec=' */
+                       if (NFS_SERVER(dir)->flags & NFS_MOUNT_SECFLAVOUR)
+                               goto out;
                        client = nfs4_create_sec_client(client, dir, name);
                        if (IS_ERR(client))
                                return PTR_ERR(client);
@@@ -3071,13 -3196,15 +3196,13 @@@ struct rpc_clnt 
  nfs4_proc_lookup_mountpoint(struct inode *dir, struct qstr *name,
                            struct nfs_fh *fhandle, struct nfs_fattr *fattr)
  {
 +      struct rpc_clnt *client = NFS_CLIENT(dir);
        int status;
 -      struct rpc_clnt *client = rpc_clone_client(NFS_CLIENT(dir));
  
        status = nfs4_proc_lookup_common(&client, dir, name, fhandle, fattr, NULL);
 -      if (status < 0) {
 -              rpc_shutdown_client(client);
 +      if (status < 0)
                return ERR_PTR(status);
 -      }
 -      return client;
 +      return (client == NFS_CLIENT(dir)) ? rpc_clone_client(client) : client;
  }
  
  static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry)
@@@ -3134,8 -3261,9 +3259,9 @@@ static int nfs4_proc_access(struct inod
        struct nfs4_exception exception = { };
        int err;
        do {
-               err = nfs4_handle_exception(NFS_SERVER(inode),
-                               _nfs4_proc_access(inode, entry),
+               err = _nfs4_proc_access(inode, entry);
+               trace_nfs4_access(inode, err);
+               err = nfs4_handle_exception(NFS_SERVER(inode), err,
                                &exception);
        } while (exception.retry);
        return err;
@@@ -3188,8 -3316,9 +3314,9 @@@ static int nfs4_proc_readlink(struct in
        struct nfs4_exception exception = { };
        int err;
        do {
-               err = nfs4_handle_exception(NFS_SERVER(inode),
-                               _nfs4_proc_readlink(inode, page, pgbase, pglen),
+               err = _nfs4_proc_readlink(inode, page, pgbase, pglen);
+               trace_nfs4_readlink(inode, err);
+               err = nfs4_handle_exception(NFS_SERVER(inode), err,
                                &exception);
        } while (exception.retry);
        return err;
@@@ -3253,8 -3382,9 +3380,9 @@@ static int nfs4_proc_remove(struct inod
        struct nfs4_exception exception = { };
        int err;
        do {
-               err = nfs4_handle_exception(NFS_SERVER(dir),
-                               _nfs4_proc_remove(dir, name),
+               err = _nfs4_proc_remove(dir, name);
+               trace_nfs4_remove(dir, name, err);
+               err = nfs4_handle_exception(NFS_SERVER(dir), err,
                                &exception);
        } while (exception.retry);
        return err;
@@@ -3268,7 -3398,7 +3396,7 @@@ static void nfs4_proc_unlink_setup(stru
  
        res->server = server;
        msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE];
-       nfs41_init_sequence(&args->seq_args, &res->seq_res, 1);
+       nfs4_init_sequence(&args->seq_args, &res->seq_res, 1);
  
        nfs_fattr_init(res->dir_attr);
  }
@@@ -3283,7 -3413,8 +3411,8 @@@ static void nfs4_proc_unlink_rpc_prepar
  
  static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir)
  {
-       struct nfs_removeres *res = task->tk_msg.rpc_resp;
+       struct nfs_unlinkdata *data = task->tk_calldata;
+       struct nfs_removeres *res = &data->res;
  
        if (!nfs4_sequence_done(task, &res->seq_res))
                return 0;
@@@ -3301,7 -3432,7 +3430,7 @@@ static void nfs4_proc_rename_setup(stru
  
        msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME];
        res->server = server;
-       nfs41_init_sequence(&arg->seq_args, &res->seq_res, 1);
+       nfs4_init_sequence(&arg->seq_args, &res->seq_res, 1);
  }
  
  static void nfs4_proc_rename_rpc_prepare(struct rpc_task *task, struct nfs_renamedata *data)
  static int nfs4_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
                                 struct inode *new_dir)
  {
-       struct nfs_renameres *res = task->tk_msg.rpc_resp;
+       struct nfs_renamedata *data = task->tk_calldata;
+       struct nfs_renameres *res = &data->res;
  
        if (!nfs4_sequence_done(task, &res->seq_res))
                return 0;
@@@ -3361,9 -3493,10 +3491,10 @@@ static int nfs4_proc_rename(struct inod
        struct nfs4_exception exception = { };
        int err;
        do {
-               err = nfs4_handle_exception(NFS_SERVER(old_dir),
-                               _nfs4_proc_rename(old_dir, old_name,
-                                       new_dir, new_name),
+               err = _nfs4_proc_rename(old_dir, old_name,
+                                       new_dir, new_name);
+               trace_nfs4_rename(old_dir, old_name, new_dir, new_name, err);
+               err = nfs4_handle_exception(NFS_SERVER(old_dir), err,
                                &exception);
        } while (exception.retry);
        return err;
@@@ -3525,9 -3658,9 +3656,9 @@@ static int nfs4_proc_symlink(struct ino
        label = nfs4_label_init_security(dir, dentry, sattr, &l);
  
        do {
-               err = nfs4_handle_exception(NFS_SERVER(dir),
-                               _nfs4_proc_symlink(dir, dentry, page,
-                                                       len, sattr, label),
+               err = _nfs4_proc_symlink(dir, dentry, page, len, sattr, label);
+               trace_nfs4_symlink(dir, &dentry->d_name, err);
+               err = nfs4_handle_exception(NFS_SERVER(dir), err,
                                &exception);
        } while (exception.retry);
  
@@@ -3564,8 -3697,9 +3695,9 @@@ static int nfs4_proc_mkdir(struct inod
  
        sattr->ia_mode &= ~current_umask();
        do {
-               err = nfs4_handle_exception(NFS_SERVER(dir),
-                               _nfs4_proc_mkdir(dir, dentry, sattr, label),
+               err = _nfs4_proc_mkdir(dir, dentry, sattr, label);
+               trace_nfs4_mkdir(dir, &dentry->d_name, err);
+               err = nfs4_handle_exception(NFS_SERVER(dir), err,
                                &exception);
        } while (exception.retry);
        nfs4_label_release_security(label);
@@@ -3618,9 -3752,10 +3750,10 @@@ static int nfs4_proc_readdir(struct den
        struct nfs4_exception exception = { };
        int err;
        do {
-               err = nfs4_handle_exception(NFS_SERVER(dentry->d_inode),
-                               _nfs4_proc_readdir(dentry, cred, cookie,
-                                       pages, count, plus),
+               err = _nfs4_proc_readdir(dentry, cred, cookie,
+                               pages, count, plus);
+               trace_nfs4_readdir(dentry->d_inode, err);
+               err = nfs4_handle_exception(NFS_SERVER(dentry->d_inode), err,
                                &exception);
        } while (exception.retry);
        return err;
@@@ -3672,8 -3807,9 +3805,9 @@@ static int nfs4_proc_mknod(struct inod
  
        sattr->ia_mode &= ~current_umask();
        do {
-               err = nfs4_handle_exception(NFS_SERVER(dir),
-                               _nfs4_proc_mknod(dir, dentry, sattr, label, rdev),
+               err = _nfs4_proc_mknod(dir, dentry, sattr, label, rdev);
+               trace_nfs4_mknod(dir, &dentry->d_name, err);
+               err = nfs4_handle_exception(NFS_SERVER(dir), err,
                                &exception);
        } while (exception.retry);
  
@@@ -3741,6 -3877,7 +3875,7 @@@ static int nfs4_do_fsinfo(struct nfs_se
  
        do {
                err = _nfs4_do_fsinfo(server, fhandle, fsinfo);
+               trace_nfs4_fsinfo(server, fhandle, fsinfo->fattr, err);
                if (err == 0) {
                        struct nfs_client *clp = server->nfs_client;
  
@@@ -3859,6 -3996,7 +3994,7 @@@ static int nfs4_read_done_cb(struct rpc
  {
        struct nfs_server *server = NFS_SERVER(data->header->inode);
  
+       trace_nfs4_read(data, task->tk_status);
        if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) {
                rpc_restart_call_prepare(task);
                return -EAGAIN;
@@@ -3902,24 -4040,29 +4038,29 @@@ static void nfs4_proc_read_setup(struc
        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);
+       nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0);
  }
  
- static void nfs4_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_data *data)
+ static int 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;
-       nfs4_set_rw_stateid(&data->args.stateid, data->args.context,
-                       data->args.lock_context, FMODE_READ);
+               return 0;
+       if (nfs4_set_rw_stateid(&data->args.stateid, data->args.context,
+                               data->args.lock_context, FMODE_READ) == -EIO)
+               return -EIO;
+       if (unlikely(test_bit(NFS_CONTEXT_BAD, &data->args.context->flags)))
+               return -EIO;
+       return 0;
  }
  
  static int nfs4_write_done_cb(struct rpc_task *task, struct nfs_write_data *data)
  {
        struct inode *inode = data->header->inode;
        
+       trace_nfs4_write(data, task->tk_status);
        if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) {
                rpc_restart_call_prepare(task);
                return -EAGAIN;
@@@ -3985,18 -4128,22 +4126,22 @@@ static void nfs4_proc_write_setup(struc
        data->timestamp   = jiffies;
  
        msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE];
-       nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
+       nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
  }
  
- static void nfs4_proc_write_rpc_prepare(struct rpc_task *task, struct nfs_write_data *data)
+ static int 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;
-       nfs4_set_rw_stateid(&data->args.stateid, data->args.context,
-                       data->args.lock_context, FMODE_WRITE);
+               return 0;
+       if (nfs4_set_rw_stateid(&data->args.stateid, data->args.context,
+                               data->args.lock_context, FMODE_WRITE) == -EIO)
+               return -EIO;
+       if (unlikely(test_bit(NFS_CONTEXT_BAD, &data->args.context->flags)))
+               return -EIO;
+       return 0;
  }
  
  static void nfs4_proc_commit_rpc_prepare(struct rpc_task *task, struct nfs_commit_data *data)
@@@ -4011,6 -4158,7 +4156,7 @@@ static int nfs4_commit_done_cb(struct r
  {
        struct inode *inode = data->inode;
  
+       trace_nfs4_commit(data, task->tk_status);
        if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) {
                rpc_restart_call_prepare(task);
                return -EAGAIN;
@@@ -4033,7 -4181,7 +4179,7 @@@ static void nfs4_proc_commit_setup(stru
                data->commit_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);
+       nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
  }
  
  struct nfs4_renewdata {
@@@ -4062,6 -4210,7 +4208,7 @@@ static void nfs4_renew_done(struct rpc_
        struct nfs_client *clp = data->client;
        unsigned long timestamp = data->timestamp;
  
+       trace_nfs4_renew_async(clp, task->tk_status);
        if (task->tk_status < 0) {
                /* Unless we're shutting down, schedule state recovery! */
                if (test_bit(NFS_CS_RENEWD, &clp->cl_res_state) == 0)
@@@ -4319,6 -4468,7 +4466,7 @@@ static ssize_t nfs4_get_acl_uncached(st
        ssize_t ret;
        do {
                ret = __nfs4_get_acl_uncached(inode, buf, buflen);
+               trace_nfs4_get_acl(inode, ret);
                if (ret >= 0)
                        break;
                ret = nfs4_handle_exception(NFS_SERVER(inode), ret, &exception);
@@@ -4398,8 -4548,9 +4546,9 @@@ static int nfs4_proc_set_acl(struct ino
        struct nfs4_exception exception = { };
        int err;
        do {
-               err = nfs4_handle_exception(NFS_SERVER(inode),
-                               __nfs4_proc_set_acl(inode, buf, buflen),
+               err = __nfs4_proc_set_acl(inode, buf, buflen);
+               trace_nfs4_set_acl(inode, err);
+               err = nfs4_handle_exception(NFS_SERVER(inode), err,
                                &exception);
        } while (exception.retry);
        return err;
@@@ -4452,8 -4603,9 +4601,9 @@@ static int nfs4_get_security_label(stru
                return -EOPNOTSUPP;
  
        do {
-               err = nfs4_handle_exception(NFS_SERVER(inode),
-                               _nfs4_get_security_label(inode, buf, buflen),
+               err = _nfs4_get_security_label(inode, buf, buflen);
+               trace_nfs4_get_security_label(inode, err);
+               err = nfs4_handle_exception(NFS_SERVER(inode), err,
                                &exception);
        } while (exception.retry);
        return err;
@@@ -4505,9 -4657,10 +4655,10 @@@ static int nfs4_do_set_security_label(s
        int err;
  
        do {
-               err = nfs4_handle_exception(NFS_SERVER(inode),
-                               _nfs4_do_set_security_label(inode, ilabel,
-                               fattr, olabel),
+               err = _nfs4_do_set_security_label(inode, ilabel,
+                               fattr, olabel);
+               trace_nfs4_set_security_label(inode, err);
+               err = nfs4_handle_exception(NFS_SERVER(inode), err,
                                &exception);
        } while (exception.retry);
        return err;
@@@ -4630,11 -4783,11 +4781,11 @@@ static void nfs4_init_boot_verifier(con
                /* An impossible timestamp guarantees this value
                 * will never match a generated boot time. */
                verf[0] = 0;
-               verf[1] = (__be32)(NSEC_PER_SEC + 1);
+               verf[1] = cpu_to_be32(NSEC_PER_SEC + 1);
        } else {
                struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
-               verf[0] = (__be32)nn->boot_time.tv_sec;
-               verf[1] = (__be32)nn->boot_time.tv_nsec;
+               verf[0] = cpu_to_be32(nn->boot_time.tv_sec);
+               verf[1] = cpu_to_be32(nn->boot_time.tv_nsec);
        }
        memcpy(bootverf->data, verf, sizeof(bootverf->data));
  }
@@@ -4660,10 -4813,14 +4811,14 @@@ static unsigned in
  nfs4_init_uniform_client_string(const struct nfs_client *clp,
                                char *buf, size_t len)
  {
-       char *nodename = clp->cl_rpcclient->cl_nodename;
+       const char *nodename = clp->cl_rpcclient->cl_nodename;
  
        if (nfs4_client_id_uniquifier[0] != '\0')
-               nodename = nfs4_client_id_uniquifier;
+               return scnprintf(buf, len, "Linux NFSv%u.%u %s/%s",
+                               clp->rpc_ops->version,
+                               clp->cl_minorversion,
+                               nfs4_client_id_uniquifier,
+                               nodename);
        return scnprintf(buf, len, "Linux NFSv%u.%u %s",
                                clp->rpc_ops->version, clp->cl_minorversion,
                                nodename);
@@@ -4724,6 -4881,7 +4879,7 @@@ int nfs4_proc_setclientid(struct nfs_cl
                clp->cl_rpcclient->cl_auth->au_ops->au_name,
                setclientid.sc_name_len, setclientid.sc_name);
        status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
+       trace_nfs4_setclientid(clp, status);
        dprintk("NFS reply setclientid: %d\n", status);
        return status;
  }
@@@ -4751,6 -4909,7 +4907,7 @@@ int nfs4_proc_setclientid_confirm(struc
                clp->cl_rpcclient->cl_auth->au_ops->au_name,
                clp->cl_clientid);
        status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
+       trace_nfs4_setclientid_confirm(clp, status);
        dprintk("NFS reply setclientid_confirm: %d\n", status);
        return status;
  }
@@@ -4772,6 -4931,7 +4929,7 @@@ static void nfs4_delegreturn_done(struc
        if (!nfs4_sequence_done(task, &data->res.seq_res))
                return;
  
+       trace_nfs4_delegreturn_exit(&data->args, &data->res, task->tk_status);
        switch (task->tk_status) {
        case -NFS4ERR_STALE_STATEID:
        case -NFS4ERR_EXPIRED:
@@@ -4793,7 -4953,6 +4951,6 @@@ static void nfs4_delegreturn_release(vo
        kfree(calldata);
  }
  
- #if defined(CONFIG_NFS_V4_1)
  static void nfs4_delegreturn_prepare(struct rpc_task *task, void *data)
  {
        struct nfs4_delegreturndata *d_data;
                        &d_data->res.seq_res,
                        task);
  }
- #endif /* CONFIG_NFS_V4_1 */
  
  static const struct rpc_call_ops nfs4_delegreturn_ops = {
- #if defined(CONFIG_NFS_V4_1)
        .rpc_call_prepare = nfs4_delegreturn_prepare,
- #endif /* CONFIG_NFS_V4_1 */
        .rpc_call_done = nfs4_delegreturn_done,
        .rpc_release = nfs4_delegreturn_release,
  };
@@@ -4835,7 -4991,7 +4989,7 @@@ static int _nfs4_proc_delegreturn(struc
        data = kzalloc(sizeof(*data), GFP_NOFS);
        if (data == NULL)
                return -ENOMEM;
-       nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
+       nfs4_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->cache_consistency_bitmask;
@@@ -4875,6 -5031,7 +5029,7 @@@ int nfs4_proc_delegreturn(struct inode 
        int err;
        do {
                err = _nfs4_proc_delegreturn(inode, cred, stateid, issync);
+               trace_nfs4_delegreturn(inode, err);
                switch (err) {
                        case -NFS4ERR_STALE_STATEID:
                        case -NFS4ERR_EXPIRED:
@@@ -4949,8 -5106,9 +5104,9 @@@ static int nfs4_proc_getlk(struct nfs4_
        int err;
  
        do {
-               err = nfs4_handle_exception(NFS_SERVER(state->inode),
-                               _nfs4_proc_getlk(state, cmd, request),
+               err = _nfs4_proc_getlk(state, cmd, request);
+               trace_nfs4_get_lock(request, state, cmd, err);
+               err = nfs4_handle_exception(NFS_SERVER(state->inode), err,
                                &exception);
        } while (exception.retry);
        return err;
@@@ -5087,6 -5245,9 +5243,9 @@@ static struct rpc_task *nfs4_do_unlck(s
                .flags = RPC_TASK_ASYNC,
        };
  
+       nfs4_state_protect(NFS_SERVER(lsp->ls_state->inode)->nfs_client,
+               NFS_SP4_MACH_CRED_CLEANUP, &task_setup_data.rpc_client, &msg);
        /* Ensure this is an unlock - when canceling a lock, the
         * canceled lock is passed in, and it won't be an unlock.
         */
                return ERR_PTR(-ENOMEM);
        }
  
-       nfs41_init_sequence(&data->arg.seq_args, &data->res.seq_res, 1);
+       nfs4_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;
@@@ -5148,6 -5309,7 +5307,7 @@@ static int nfs4_proc_unlck(struct nfs4_
        rpc_put_task(task);
  out:
        request->fl_flags = fl_flags;
+       trace_nfs4_unlock(request, state, F_SETLK, status);
        return status;
  }
  
@@@ -5333,7 -5495,7 +5493,7 @@@ static int _nfs4_do_setlk(struct nfs4_s
                return -ENOMEM;
        if (IS_SETLKW(cmd))
                data->arg.block = 1;
-       nfs41_init_sequence(&data->arg.seq_args, &data->res.seq_res, 1);
+       nfs4_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;
@@@ -5371,6 -5533,7 +5531,7 @@@ static int nfs4_lock_reclaim(struct nfs
                if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
                        return 0;
                err = _nfs4_do_setlk(state, F_SETLK, request, NFS_LOCK_RECLAIM);
+               trace_nfs4_lock_reclaim(request, state, F_SETLK, err);
                if (err != -NFS4ERR_DELAY)
                        break;
                nfs4_handle_exception(server, err, &exception);
@@@ -5389,10 -5552,15 +5550,15 @@@ static int nfs4_lock_expired(struct nfs
        err = nfs4_set_lock_state(state, request);
        if (err != 0)
                return err;
+       if (!recover_lost_locks) {
+               set_bit(NFS_LOCK_LOST, &request->fl_u.nfs4_fl.owner->ls_flags);
+               return 0;
+       }
        do {
                if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
                        return 0;
                err = _nfs4_do_setlk(state, F_SETLK, request, NFS_LOCK_EXPIRED);
+               trace_nfs4_lock_expired(request, state, F_SETLK, err);
                switch (err) {
                default:
                        goto out;
@@@ -5428,6 -5596,7 +5594,7 @@@ static int nfs41_check_expired_locks(st
                        status = nfs41_test_stateid(server,
                                        &lsp->ls_stateid,
                                        cred);
+                       trace_nfs4_test_lock_stateid(state, lsp, status);
                        if (status != NFS_OK) {
                                /* Free the stateid unless the server
                                 * informs us the stateid is unrecognized. */
@@@ -5515,6 -5684,7 +5682,7 @@@ static int nfs4_proc_setlk(struct nfs4_
  
        do {
                err = _nfs4_proc_setlk(state, cmd, request);
+               trace_nfs4_set_lock(request, state, cmd, err);
                if (err == -NFS4ERR_DENIED)
                        err = -EAGAIN;
                err = nfs4_handle_exception(NFS_SERVER(state->inode),
@@@ -5597,8 -5767,23 +5765,23 @@@ struct nfs_release_lockowner_data 
        struct nfs4_lock_state *lsp;
        struct nfs_server *server;
        struct nfs_release_lockowner_args args;
+       struct nfs4_sequence_args seq_args;
+       struct nfs4_sequence_res seq_res;
  };
  
+ static void nfs4_release_lockowner_prepare(struct rpc_task *task, void *calldata)
+ {
+       struct nfs_release_lockowner_data *data = calldata;
+       nfs40_setup_sequence(data->server,
+                               &data->seq_args, &data->seq_res, task);
+ }
+ static void nfs4_release_lockowner_done(struct rpc_task *task, void *calldata)
+ {
+       struct nfs_release_lockowner_data *data = calldata;
+       nfs40_sequence_done(task, &data->seq_res);
+ }
  static void nfs4_release_lockowner_release(void *calldata)
  {
        struct nfs_release_lockowner_data *data = calldata;
  }
  
  static const struct rpc_call_ops nfs4_release_lockowner_ops = {
+       .rpc_call_prepare = nfs4_release_lockowner_prepare,
+       .rpc_call_done = nfs4_release_lockowner_done,
        .rpc_release = nfs4_release_lockowner_release,
  };
  
@@@ -5619,14 -5806,17 +5804,17 @@@ static int nfs4_release_lockowner(struc
  
        if (server->nfs_client->cl_mvops->minor_version != 0)
                return -EINVAL;
        data = kmalloc(sizeof(*data), GFP_NOFS);
        if (!data)
                return -ENOMEM;
+       nfs4_init_sequence(&data->seq_args, &data->seq_res, 0);
        data->lsp = lsp;
        data->server = server;
        data->args.lock_owner.clientid = server->nfs_client->cl_clientid;
        data->args.lock_owner.id = lsp->ls_seqid.owner_id;
        data->args.lock_owner.s_dev = server->s_dev;
        msg.rpc_argp = &data->args;
        rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, data);
        return 0;
@@@ -5781,14 -5971,23 +5969,23 @@@ int nfs4_proc_fs_locations(struct rpc_c
        struct nfs4_exception exception = { };
        int err;
        do {
-               err = nfs4_handle_exception(NFS_SERVER(dir),
-                               _nfs4_proc_fs_locations(client, dir, name, fs_locations, page),
+               err = _nfs4_proc_fs_locations(client, dir, name,
+                               fs_locations, page);
+               trace_nfs4_get_fs_locations(dir, name, err);
+               err = nfs4_handle_exception(NFS_SERVER(dir), err,
                                &exception);
        } while (exception.retry);
        return err;
  }
  
- static int _nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct nfs4_secinfo_flavors *flavors)
+ /**
+  * If 'use_integrity' is true and the state managment nfs_client
+  * cl_rpcclient is using krb5i/p, use the integrity protected cl_rpcclient
+  * and the machine credential as per RFC3530bis and RFC5661 Security
+  * Considerations sections. Otherwise, just use the user cred with the
+  * filesystem's rpc_client.
+  */
+ static int _nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct nfs4_secinfo_flavors *flavors, bool use_integrity)
  {
        int status;
        struct nfs4_secinfo_arg args = {
                .rpc_argp = &args,
                .rpc_resp = &res,
        };
+       struct rpc_clnt *clnt = NFS_SERVER(dir)->client;
+       if (use_integrity) {
+               clnt = NFS_SERVER(dir)->nfs_client->cl_rpcclient;
+               msg.rpc_cred = nfs4_get_clid_cred(NFS_SERVER(dir)->nfs_client);
+       }
  
        dprintk("NFS call  secinfo %s\n", name->name);
-       status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &msg, &args.seq_args, &res.seq_res, 0);
+       nfs4_state_protect(NFS_SERVER(dir)->nfs_client,
+               NFS_SP4_MACH_CRED_SECINFO, &clnt, &msg);
+       status = nfs4_call_sync(clnt, NFS_SERVER(dir), &msg, &args.seq_args,
+                               &res.seq_res, 0);
        dprintk("NFS reply  secinfo: %d\n", status);
+       if (msg.rpc_cred)
+               put_rpccred(msg.rpc_cred);
        return status;
  }
  
@@@ -5816,8 -6030,23 +6028,23 @@@ int nfs4_proc_secinfo(struct inode *dir
        struct nfs4_exception exception = { };
        int err;
        do {
-               err = nfs4_handle_exception(NFS_SERVER(dir),
-                               _nfs4_proc_secinfo(dir, name, flavors),
+               err = -NFS4ERR_WRONGSEC;
+               /* try to use integrity protection with machine cred */
+               if (_nfs4_is_integrity_protected(NFS_SERVER(dir)->nfs_client))
+                       err = _nfs4_proc_secinfo(dir, name, flavors, true);
+               /*
+                * if unable to use integrity protection, or SECINFO with
+                * integrity protection returns NFS4ERR_WRONGSEC (which is
+                * disallowed by spec, but exists in deployed servers) use
+                * the current filesystem's rpc_client and the user cred.
+                */
+               if (err == -NFS4ERR_WRONGSEC)
+                       err = _nfs4_proc_secinfo(dir, name, flavors, false);
+               trace_nfs4_secinfo(dir, name, err);
+               err = nfs4_handle_exception(NFS_SERVER(dir), err,
                                &exception);
        } while (exception.retry);
        return err;
@@@ -5881,6 -6110,7 +6108,7 @@@ int nfs4_proc_bind_conn_to_session(stru
        }
  
        status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
+       trace_nfs4_bind_conn_to_session(clp, status);
        if (status == 0) {
                if (memcmp(res.session->sess_id.data,
                    clp->cl_session->sess_id.data, NFS4_MAX_SESSIONID_LEN)) {
  }
  
  /*
-  * nfs4_proc_exchange_id()
+  * Minimum set of SP4_MACH_CRED operations from RFC 5661 in the enforce map
+  * and operations we'd like to see to enable certain features in the allow map
+  */
+ static const struct nfs41_state_protection nfs4_sp4_mach_cred_request = {
+       .how = SP4_MACH_CRED,
+       .enforce.u.words = {
+               [1] = 1 << (OP_BIND_CONN_TO_SESSION - 32) |
+                     1 << (OP_EXCHANGE_ID - 32) |
+                     1 << (OP_CREATE_SESSION - 32) |
+                     1 << (OP_DESTROY_SESSION - 32) |
+                     1 << (OP_DESTROY_CLIENTID - 32)
+       },
+       .allow.u.words = {
+               [0] = 1 << (OP_CLOSE) |
+                     1 << (OP_LOCKU),
+               [1] = 1 << (OP_SECINFO - 32) |
+                     1 << (OP_SECINFO_NO_NAME - 32) |
+                     1 << (OP_TEST_STATEID - 32) |
+                     1 << (OP_FREE_STATEID - 32)
+       }
+ };
+ /*
+  * Select the state protection mode for client `clp' given the server results
+  * from exchange_id in `sp'.
   *
-  * Returns zero, a negative errno, or a negative NFS4ERR status code.
+  * Returns 0 on success, negative errno otherwise.
+  */
+ static int nfs4_sp4_select_mode(struct nfs_client *clp,
+                                struct nfs41_state_protection *sp)
+ {
+       static const u32 supported_enforce[NFS4_OP_MAP_NUM_WORDS] = {
+               [1] = 1 << (OP_BIND_CONN_TO_SESSION - 32) |
+                     1 << (OP_EXCHANGE_ID - 32) |
+                     1 << (OP_CREATE_SESSION - 32) |
+                     1 << (OP_DESTROY_SESSION - 32) |
+                     1 << (OP_DESTROY_CLIENTID - 32)
+       };
+       unsigned int i;
+       if (sp->how == SP4_MACH_CRED) {
+               /* Print state protect result */
+               dfprintk(MOUNT, "Server SP4_MACH_CRED support:\n");
+               for (i = 0; i <= LAST_NFS4_OP; i++) {
+                       if (test_bit(i, sp->enforce.u.longs))
+                               dfprintk(MOUNT, "  enforce op %d\n", i);
+                       if (test_bit(i, sp->allow.u.longs))
+                               dfprintk(MOUNT, "  allow op %d\n", i);
+               }
+               /* make sure nothing is on enforce list that isn't supported */
+               for (i = 0; i < NFS4_OP_MAP_NUM_WORDS; i++) {
+                       if (sp->enforce.u.words[i] & ~supported_enforce[i]) {
+                               dfprintk(MOUNT, "sp4_mach_cred: disabled\n");
+                               return -EINVAL;
+                       }
+               }
+               /*
+                * Minimal mode - state operations are allowed to use machine
+                * credential.  Note this already happens by default, so the
+                * client doesn't have to do anything more than the negotiation.
+                *
+                * NOTE: we don't care if EXCHANGE_ID is in the list -
+                *       we're already using the machine cred for exchange_id
+                *       and will never use a different cred.
+                */
+               if (test_bit(OP_BIND_CONN_TO_SESSION, sp->enforce.u.longs) &&
+                   test_bit(OP_CREATE_SESSION, sp->enforce.u.longs) &&
+                   test_bit(OP_DESTROY_SESSION, sp->enforce.u.longs) &&
+                   test_bit(OP_DESTROY_CLIENTID, sp->enforce.u.longs)) {
+                       dfprintk(MOUNT, "sp4_mach_cred:\n");
+                       dfprintk(MOUNT, "  minimal mode enabled\n");
+                       set_bit(NFS_SP4_MACH_CRED_MINIMAL, &clp->cl_sp4_flags);
+               } else {
+                       dfprintk(MOUNT, "sp4_mach_cred: disabled\n");
+                       return -EINVAL;
+               }
+               if (test_bit(OP_CLOSE, sp->allow.u.longs) &&
+                   test_bit(OP_LOCKU, sp->allow.u.longs)) {
+                       dfprintk(MOUNT, "  cleanup mode enabled\n");
+                       set_bit(NFS_SP4_MACH_CRED_CLEANUP, &clp->cl_sp4_flags);
+               }
+               if (test_bit(OP_SECINFO, sp->allow.u.longs) &&
+                   test_bit(OP_SECINFO_NO_NAME, sp->allow.u.longs)) {
+                       dfprintk(MOUNT, "  secinfo mode enabled\n");
+                       set_bit(NFS_SP4_MACH_CRED_SECINFO, &clp->cl_sp4_flags);
+               }
+               if (test_bit(OP_TEST_STATEID, sp->allow.u.longs) &&
+                   test_bit(OP_FREE_STATEID, sp->allow.u.longs)) {
+                       dfprintk(MOUNT, "  stateid mode enabled\n");
+                       set_bit(NFS_SP4_MACH_CRED_STATEID, &clp->cl_sp4_flags);
+               }
+               if (test_bit(OP_WRITE, sp->allow.u.longs)) {
+                       dfprintk(MOUNT, "  write mode enabled\n");
+                       set_bit(NFS_SP4_MACH_CRED_WRITE, &clp->cl_sp4_flags);
+               }
+               if (test_bit(OP_COMMIT, sp->allow.u.longs)) {
+                       dfprintk(MOUNT, "  commit mode enabled\n");
+                       set_bit(NFS_SP4_MACH_CRED_COMMIT, &clp->cl_sp4_flags);
+               }
+       }
+       return 0;
+ }
+ /*
+  * _nfs4_proc_exchange_id()
   *
-  * Since the clientid has expired, all compounds using sessions
-  * associated with the stale clientid will be returning
-  * NFS4ERR_BADSESSION in the sequence operation, and will therefore
-  * be in some phase of session reset.
+  * Wrapper for EXCHANGE_ID operation.
   */
- int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
+ static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred,
+       u32 sp4_how)
  {
        nfs4_verifier verifier;
        struct nfs41_exchange_id_args args = {
                goto out_server_scope;
        }
  
+       switch (sp4_how) {
+       case SP4_NONE:
+               args.state_protect.how = SP4_NONE;
+               break;
+       case SP4_MACH_CRED:
+               args.state_protect = nfs4_sp4_mach_cred_request;
+               break;
+       default:
+               /* unsupported! */
+               WARN_ON_ONCE(1);
+               status = -EINVAL;
+               goto out_server_scope;
+       }
        status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
+       trace_nfs4_exchange_id(clp, status);
        if (status == 0)
                status = nfs4_check_cl_exchange_flags(res.flags);
  
+       if (status == 0)
+               status = nfs4_sp4_select_mode(clp, &res.state_protect);
        if (status == 0) {
                clp->cl_clientid = res.clientid;
                clp->cl_exchange_flags = (res.flags & ~EXCHGID4_FLAG_CONFIRMED_R);
        return status;
  }
  
+ /*
+  * nfs4_proc_exchange_id()
+  *
+  * Returns zero, a negative errno, or a negative NFS4ERR status code.
+  *
+  * Since the clientid has expired, all compounds using sessions
+  * associated with the stale clientid will be returning
+  * NFS4ERR_BADSESSION in the sequence operation, and will therefore
+  * be in some phase of session reset.
+  *
+  * Will attempt to negotiate SP4_MACH_CRED if krb5i / krb5p auth is used.
+  */
+ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
+ {
+       rpc_authflavor_t authflavor = clp->cl_rpcclient->cl_auth->au_flavor;
+       int status;
+       /* try SP4_MACH_CRED if krb5i/p */
+       if (authflavor == RPC_AUTH_GSS_KRB5I ||
+           authflavor == RPC_AUTH_GSS_KRB5P) {
+               status = _nfs4_proc_exchange_id(clp, cred, SP4_MACH_CRED);
+               if (!status)
+                       return 0;
+       }
+       /* try SP4_NONE */
+       return _nfs4_proc_exchange_id(clp, cred, SP4_NONE);
+ }
  static int _nfs4_proc_destroy_clientid(struct nfs_client *clp,
                struct rpc_cred *cred)
  {
        int status;
  
        status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
+       trace_nfs4_destroy_clientid(clp, status);
        if (status)
                dprintk("NFS: Got error %d from the server %s on "
                        "DESTROY_CLIENTID.", status, clp->cl_hostname);
@@@ -6063,7 -6451,7 +6449,7 @@@ int nfs4_destroy_clientid(struct nfs_cl
                goto out;
        if (clp->cl_preserve_clid)
                goto out;
-       cred = nfs4_get_exchange_id_cred(clp);
+       cred = nfs4_get_clid_cred(clp);
        ret = nfs4_proc_destroy_clientid(clp, cred);
        if (cred)
                put_rpccred(cred);
@@@ -6155,7 -6543,7 +6541,7 @@@ int nfs4_proc_get_lease_time(struct nfs
        };
        int status;
  
-       nfs41_init_sequence(&args.la_seq_args, &res.lr_seq_res, 0);
+       nfs4_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);
@@@ -6289,6 -6677,7 +6675,7 @@@ static int _nfs4_proc_create_session(st
        args.flags = (SESSION4_PERSIST | SESSION4_BACK_CHAN);
  
        status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
+       trace_nfs4_create_session(clp, status);
  
        if (!status) {
                /* Verify the session's negotiated channel_attrs values */
@@@ -6352,6 -6741,7 +6739,7 @@@ int nfs4_proc_destroy_session(struct nf
                return status;
  
        status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
+       trace_nfs4_destroy_session(session->clp, status);
  
        if (status)
                dprintk("NFS: Got error %d from the server on DESTROY_SESSION. "
@@@ -6401,6 -6791,7 +6789,7 @@@ static void nfs41_sequence_call_done(st
        if (!nfs41_sequence_done(task, task->tk_msg.rpc_resp))
                return;
  
+       trace_nfs4_sequence(clp, task->tk_status);
        if (task->tk_status < 0) {
                dprintk("%s ERROR %d\n", __func__, task->tk_status);
                if (atomic_read(&clp->cl_count) == 1)
@@@ -6458,7 -6849,7 +6847,7 @@@ static struct rpc_task *_nfs41_proc_seq
                nfs_put_client(clp);
                return ERR_PTR(-ENOMEM);
        }
-       nfs41_init_sequence(&calldata->args, &calldata->res, 0);
+       nfs4_init_sequence(&calldata->args, &calldata->res, 0);
        if (is_privileged)
                nfs4_set_sequence_privileged(&calldata->args);
        msg.rpc_argp = &calldata->args;
@@@ -6553,6 -6944,7 +6942,7 @@@ static void nfs4_reclaim_complete_done(
        if (!nfs41_sequence_done(task, res))
                return;
  
+       trace_nfs4_reclaim_complete(clp, task->tk_status);
        if (nfs41_reclaim_complete_handle_errors(task, clp) == -EAGAIN) {
                rpc_restart_call_prepare(task);
                return;
@@@ -6600,7 -6992,7 +6990,7 @@@ static int nfs41_proc_reclaim_complete(
        calldata->clp = clp;
        calldata->arg.one_fs = 0;
  
-       nfs41_init_sequence(&calldata->arg.seq_args, &calldata->res.seq_res, 0);
+       nfs4_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;
@@@ -6791,7 -7183,7 +7181,7 @@@ nfs4_proc_layoutget(struct nfs4_layoutg
  
        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);
+       nfs4_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0);
  
        /* nfs4_layoutget_release calls pnfs_put_layout_hdr */
        pnfs_get_layout_hdr(NFS_I(inode)->layout);
        status = nfs4_wait_for_completion_rpc_task(task);
        if (status == 0)
                status = task->tk_status;
+       trace_nfs4_layoutget(lgp->args.ctx,
+                       &lgp->args.range,
+                       &lgp->res.range,
+                       status);
        /* if layoutp->len is 0, nfs4_layoutget_prepare called rpc_exit */
        if (status == 0 && lgp->res.layoutp->len)
                lseg = pnfs_layout_process(lgp);
@@@ -6874,7 -7270,7 +7268,7 @@@ int nfs4_proc_layoutreturn(struct nfs4_
                .rpc_cred = lrp->cred,
        };
        struct rpc_task_setup task_setup_data = {
-               .rpc_client = lrp->clp->cl_rpcclient,
+               .rpc_client = NFS_SERVER(lrp->args.inode)->client,
                .rpc_message = &msg,
                .callback_ops = &nfs4_layoutreturn_call_ops,
                .callback_data = lrp,
        int status;
  
        dprintk("--> %s\n", __func__);
-       nfs41_init_sequence(&lrp->args.seq_args, &lrp->res.seq_res, 1);
+       nfs4_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);
        status = task->tk_status;
+       trace_nfs4_layoutreturn(lrp->args.inode, status);
        dprintk("<-- %s status=%d\n", __func__, status);
        rpc_put_task(task);
        return status;
@@@ -7063,7 -7460,7 +7458,7 @@@ nfs4_proc_layoutcommit(struct nfs4_layo
                data->args.lastbytewritten,
                data->args.inode->i_ino);
  
-       nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
+       nfs4_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);
        if (status != 0)
                goto out;
        status = task->tk_status;
+       trace_nfs4_layoutcommit(data->args.inode, status);
  out:
        dprintk("%s: status %d\n", __func__, status);
        rpc_put_task(task);
        return status;
  }
  
+ /**
+  * Use the state managment nfs_client cl_rpcclient, which uses krb5i (if
+  * possible) as per RFC3530bis and RFC5661 Security Considerations sections
+  */
  static int
  _nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
-                   struct nfs_fsinfo *info, struct nfs4_secinfo_flavors *flavors)
+                   struct nfs_fsinfo *info,
+                   struct nfs4_secinfo_flavors *flavors, bool use_integrity)
  {
        struct nfs41_secinfo_no_name_args args = {
                .style = SECINFO_STYLE_CURRENT_FH,
                .rpc_argp = &args,
                .rpc_resp = &res,
        };
-       return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
+       struct rpc_clnt *clnt = server->client;
+       int status;
+       if (use_integrity) {
+               clnt = server->nfs_client->cl_rpcclient;
+               msg.rpc_cred = nfs4_get_clid_cred(server->nfs_client);
+       }
+       dprintk("--> %s\n", __func__);
+       status = nfs4_call_sync(clnt, server, &msg, &args.seq_args,
+                               &res.seq_res, 0);
+       dprintk("<-- %s status=%d\n", __func__, status);
+       if (msg.rpc_cred)
+               put_rpccred(msg.rpc_cred);
+       return status;
  }
  
  static int
@@@ -7104,7 -7523,24 +7521,24 @@@ nfs41_proc_secinfo_no_name(struct nfs_s
        struct nfs4_exception exception = { };
        int err;
        do {
-               err = _nfs41_proc_secinfo_no_name(server, fhandle, info, flavors);
+               /* first try using integrity protection */
+               err = -NFS4ERR_WRONGSEC;
+               /* try to use integrity protection with machine cred */
+               if (_nfs4_is_integrity_protected(server->nfs_client))
+                       err = _nfs41_proc_secinfo_no_name(server, fhandle, info,
+                                                         flavors, true);
+               /*
+                * if unable to use integrity protection, or SECINFO with
+                * integrity protection returns NFS4ERR_WRONGSEC (which is
+                * disallowed by spec, but exists in deployed servers) use
+                * the current filesystem's rpc_client and the user cred.
+                */
+               if (err == -NFS4ERR_WRONGSEC)
+                       err = _nfs41_proc_secinfo_no_name(server, fhandle, info,
+                                                         flavors, false);
                switch (err) {
                case 0:
                case -NFS4ERR_WRONGSEC:
@@@ -7174,11 -7610,15 +7608,15 @@@ static int _nfs41_test_stateid(struct n
                .rpc_resp = &res,
                .rpc_cred = cred,
        };
+       struct rpc_clnt *rpc_client = server->client;
+       nfs4_state_protect(server->nfs_client, NFS_SP4_MACH_CRED_STATEID,
+               &rpc_client, &msg);
  
        dprintk("NFS call  test_stateid %p\n", stateid);
-       nfs41_init_sequence(&args.seq_args, &res.seq_res, 0);
+       nfs4_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,
+       status = nfs4_call_sync_sequence(rpc_client, server, &msg,
                        &args.seq_args, &res.seq_res);
        if (status != NFS_OK) {
                dprintk("NFS reply test_stateid: failed, %d\n", status);
@@@ -7247,7 -7687,7 +7685,7 @@@ static void nfs41_free_stateid_release(
        kfree(calldata);
  }
  
- const struct rpc_call_ops nfs41_free_stateid_ops = {
static const struct rpc_call_ops nfs41_free_stateid_ops = {
        .rpc_call_prepare = nfs41_free_stateid_prepare,
        .rpc_call_done = nfs41_free_stateid_done,
        .rpc_release = nfs41_free_stateid_release,
@@@ -7270,6 -7710,9 +7708,9 @@@ static struct rpc_task *_nfs41_free_sta
        };
        struct nfs_free_stateid_data *data;
  
+       nfs4_state_protect(server->nfs_client, NFS_SP4_MACH_CRED_STATEID,
+               &task_setup.rpc_client, &msg);
        dprintk("NFS call  free_stateid %p\n", stateid);
        data = kmalloc(sizeof(*data), GFP_NOFS);
        if (!data)
  
        msg.rpc_argp = &data->args;
        msg.rpc_resp = &data->res;
-       nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 0);
+       nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0);
        if (privileged)
                nfs4_set_sequence_privileged(&data->args.seq_args);
  
@@@ -7357,7 -7800,6 +7798,6 @@@ static const struct nfs4_state_recovery
        .recover_open   = nfs4_open_reclaim,
        .recover_lock   = nfs4_lock_reclaim,
        .establish_clid = nfs4_init_clientid,
-       .get_clid_cred  = nfs4_get_setclientid_cred,
        .detect_trunking = nfs40_discover_server_trunking,
  };
  
@@@ -7368,7 -7810,6 +7808,6 @@@ static const struct nfs4_state_recovery
        .recover_open   = nfs4_open_reclaim,
        .recover_lock   = nfs4_lock_reclaim,
        .establish_clid = nfs41_init_clientid,
-       .get_clid_cred  = nfs4_get_exchange_id_cred,
        .reclaim_complete = nfs41_proc_reclaim_complete,
        .detect_trunking = nfs41_discover_server_trunking,
  };
@@@ -7380,7 -7821,6 +7819,6 @@@ static const struct nfs4_state_recovery
        .recover_open   = nfs4_open_expired,
        .recover_lock   = nfs4_lock_expired,
        .establish_clid = nfs4_init_clientid,
-       .get_clid_cred  = nfs4_get_setclientid_cred,
  };
  
  #if defined(CONFIG_NFS_V4_1)
@@@ -7390,7 -7830,6 +7828,6 @@@ static const struct nfs4_state_recovery
        .recover_open   = nfs41_open_expired,
        .recover_lock   = nfs41_lock_expired,
        .establish_clid = nfs41_init_clientid,
-       .get_clid_cred  = nfs4_get_exchange_id_cred,
  };
  #endif /* CONFIG_NFS_V4_1 */
  
@@@ -7414,10 -7853,12 +7851,12 @@@ static const struct nfs4_minor_version_
                | NFS_CAP_ATOMIC_OPEN
                | NFS_CAP_CHANGE_ATTR
                | NFS_CAP_POSIX_LOCK,
-       .call_sync = _nfs4_call_sync,
+       .init_client = nfs40_init_client,
+       .shutdown_client = nfs40_shutdown_client,
        .match_stateid = nfs4_match_stateid,
        .find_root_sec = nfs4_find_root_sec,
        .free_lock_state = nfs4_release_lockowner,
+       .call_sync_ops = &nfs40_call_sync_ops,
        .reboot_recovery_ops = &nfs40_reboot_recovery_ops,
        .nograce_recovery_ops = &nfs40_nograce_recovery_ops,
        .state_renewal_ops = &nfs40_state_renewal_ops,
@@@ -7432,10 -7873,12 +7871,12 @@@ static const struct nfs4_minor_version_
                | NFS_CAP_POSIX_LOCK
                | NFS_CAP_STATEID_NFSV41
                | NFS_CAP_ATOMIC_OPEN_V1,
-       .call_sync = nfs4_call_sync_sequence,
+       .init_client = nfs41_init_client,
+       .shutdown_client = nfs41_shutdown_client,
        .match_stateid = nfs41_match_stateid,
        .find_root_sec = nfs41_find_root_sec,
        .free_lock_state = nfs41_free_lock_state,
+       .call_sync_ops = &nfs41_call_sync_ops,
        .reboot_recovery_ops = &nfs41_reboot_recovery_ops,
        .nograce_recovery_ops = &nfs41_nograce_recovery_ops,
        .state_renewal_ops = &nfs41_state_renewal_ops,
@@@ -7451,10 -7894,12 +7892,12 @@@ static const struct nfs4_minor_version_
                | NFS_CAP_POSIX_LOCK
                | NFS_CAP_STATEID_NFSV41
                | NFS_CAP_ATOMIC_OPEN_V1,
-       .call_sync = nfs4_call_sync_sequence,
+       .init_client = nfs41_init_client,
+       .shutdown_client = nfs41_shutdown_client,
        .match_stateid = nfs41_match_stateid,
        .find_root_sec = nfs41_find_root_sec,
        .free_lock_state = nfs41_free_lock_state,
+       .call_sync_ops = &nfs41_call_sync_ops,
        .reboot_recovery_ops = &nfs41_reboot_recovery_ops,
        .nograce_recovery_ops = &nfs41_nograce_recovery_ops,
        .state_renewal_ops = &nfs41_state_renewal_ops,
@@@ -7471,7 -7916,7 +7914,7 @@@ const struct nfs4_minor_version_ops *nf
  #endif
  };
  
- const struct inode_operations nfs4_dir_inode_operations = {
static const struct inode_operations nfs4_dir_inode_operations = {
        .create         = nfs_create,
        .lookup         = nfs_lookup,
        .atomic_open    = nfs_atomic_open,
diff --combined fs/nfs/super.c
index f6db66d8f647069a4cffde4e609bc7f23e3a2da0,50bc31d8e7f0bbdc3525b36b8c1ecb8c7d2f73fd..5793f24613c8e3d176ecf9c07b520c740d1424f3
@@@ -923,7 -923,7 +923,7 @@@ static struct nfs_parsed_mount_data *nf
                data->nfs_server.port   = NFS_UNSPEC_PORT;
                data->nfs_server.protocol = XPRT_TRANSPORT_TCP;
                data->auth_flavors[0]   = RPC_AUTH_MAXFLAVOR;
-               data->auth_flavor_len   = 1;
+               data->auth_flavor_len   = 0;
                data->minorversion      = 0;
                data->need_mount        = true;
                data->net               = current->nsproxy->net_ns;
@@@ -1018,6 -1018,13 +1018,13 @@@ static void nfs_set_mount_transport_pro
        }
  }
  
+ static void nfs_set_auth_parsed_mount_data(struct nfs_parsed_mount_data *data,
+               rpc_authflavor_t pseudoflavor)
+ {
+       data->auth_flavors[0] = pseudoflavor;
+       data->auth_flavor_len = 1;
+ }
  /*
   * Parse the value of the 'sec=' option.
   */
@@@ -1025,49 -1032,50 +1032,50 @@@ static int nfs_parse_security_flavors(c
                                      struct nfs_parsed_mount_data *mnt)
  {
        substring_t args[MAX_OPT_ARGS];
+       rpc_authflavor_t pseudoflavor;
  
        dfprintk(MOUNT, "NFS: parsing sec=%s option\n", value);
  
        switch (match_token(value, nfs_secflavor_tokens, args)) {
        case Opt_sec_none:
-               mnt->auth_flavors[0] = RPC_AUTH_NULL;
+               pseudoflavor = RPC_AUTH_NULL;
                break;
        case Opt_sec_sys:
-               mnt->auth_flavors[0] = RPC_AUTH_UNIX;
+               pseudoflavor = RPC_AUTH_UNIX;
                break;
        case Opt_sec_krb5:
-               mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5;
+               pseudoflavor = RPC_AUTH_GSS_KRB5;
                break;
        case Opt_sec_krb5i:
-               mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5I;
+               pseudoflavor = RPC_AUTH_GSS_KRB5I;
                break;
        case Opt_sec_krb5p:
-               mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5P;
+               pseudoflavor = RPC_AUTH_GSS_KRB5P;
                break;
        case Opt_sec_lkey:
-               mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEY;
+               pseudoflavor = RPC_AUTH_GSS_LKEY;
                break;
        case Opt_sec_lkeyi:
-               mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYI;
+               pseudoflavor = RPC_AUTH_GSS_LKEYI;
                break;
        case Opt_sec_lkeyp:
-               mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYP;
+               pseudoflavor = RPC_AUTH_GSS_LKEYP;
                break;
        case Opt_sec_spkm:
-               mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKM;
+               pseudoflavor = RPC_AUTH_GSS_SPKM;
                break;
        case Opt_sec_spkmi:
-               mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMI;
+               pseudoflavor = RPC_AUTH_GSS_SPKMI;
                break;
        case Opt_sec_spkmp:
-               mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMP;
+               pseudoflavor = RPC_AUTH_GSS_SPKMP;
                break;
        default:
                return 0;
        }
  
        mnt->flags |= NFS_MOUNT_SECFLAVOUR;
-       mnt->auth_flavor_len = 1;
+       nfs_set_auth_parsed_mount_data(mnt, pseudoflavor);
        return 1;
  }
  
@@@ -1729,7 -1737,7 +1737,7 @@@ static struct nfs_server *nfs_try_mount
         * Was a sec= authflavor specified in the options? First, verify
         * whether the server supports it, and then just try to use it if so.
         */
-       if (args->auth_flavors[0] != RPC_AUTH_MAXFLAVOR) {
+       if (args->auth_flavor_len > 0) {
                status = nfs_verify_authflavor(args, authlist, authlist_len);
                dfprintk(MOUNT, "NFS: using auth flavor %u\n", args->auth_flavors[0]);
                if (status)
                        /* Fallthrough */
                }
                dfprintk(MOUNT, "NFS: attempting to use auth flavor %u\n", flavor);
-               args->auth_flavors[0] = flavor;
+               nfs_set_auth_parsed_mount_data(args, flavor);
                server = nfs_mod->rpc_ops->create_server(mount_info, nfs_mod);
                if (!IS_ERR(server))
                        return server;
  
        /* Last chance! Try AUTH_UNIX */
        dfprintk(MOUNT, "NFS: attempting to use auth flavor %u\n", RPC_AUTH_UNIX);
-       args->auth_flavors[0] = RPC_AUTH_UNIX;
+       nfs_set_auth_parsed_mount_data(args, RPC_AUTH_UNIX);
        return nfs_mod->rpc_ops->create_server(mount_info, nfs_mod);
  }
  
@@@ -1893,6 -1901,7 +1901,7 @@@ static int nfs23_validate_mount_data(vo
  {
        struct nfs_mount_data *data = (struct nfs_mount_data *)options;
        struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address;
+       int extra_flags = NFS_MOUNT_LEGACY_INTERFACE;
  
        if (data == NULL)
                goto out_no_data;
                        goto out_no_v3;
                data->root.size = NFS2_FHSIZE;
                memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE);
+               /* Turn off security negotiation */
+               extra_flags |= NFS_MOUNT_SECFLAVOUR;
        case 4:
                if (data->flags & NFS_MOUNT_SECFLAVOUR)
                        goto out_no_sec;
                 * can deal with.
                 */
                args->flags             = data->flags & NFS_MOUNT_FLAGMASK;
-               args->flags             |= NFS_MOUNT_LEGACY_INTERFACE;
+               args->flags             |= extra_flags;
                args->rsize             = data->rsize;
                args->wsize             = data->wsize;
                args->timeo             = data->timeo;
                args->namlen            = data->namlen;
                args->bsize             = data->bsize;
  
-               args->auth_flavors[0] = RPC_AUTH_UNIX;
                if (data->flags & NFS_MOUNT_SECFLAVOUR)
-                       args->auth_flavors[0] = data->pseudoflavor;
+                       nfs_set_auth_parsed_mount_data(args, data->pseudoflavor);
+               else
+                       nfs_set_auth_parsed_mount_data(args, RPC_AUTH_UNIX);
                if (!args->nfs_server.hostname)
                        goto out_nomem;
  
@@@ -2084,6 -2096,8 +2096,8 @@@ static int nfs_validate_text_mount_data
                max_namelen = NFS4_MAXNAMLEN;
                max_pathlen = NFS4_MAXPATHLEN;
                nfs_validate_transport_protocol(args);
+               if (args->nfs_server.protocol == XPRT_TRANSPORT_UDP)
+                       goto out_invalid_transport_udp;
                nfs4_validate_mount_flags(args);
  #else
                goto out_v4_not_compiled;
  out_v4_not_compiled:
        dfprintk(MOUNT, "NFS: NFSv4 is not compiled into kernel\n");
        return -EPROTONOSUPPORT;
+ #else
+ out_invalid_transport_udp:
+       dfprintk(MOUNT, "NFSv4: Unsupported transport protocol udp\n");
+       return -EINVAL;
  #endif /* !CONFIG_NFS_V4 */
  
  out_no_address:
@@@ -2170,7 -2188,7 +2188,7 @@@ nfs_remount(struct super_block *sb, in
        data->rsize = nfss->rsize;
        data->wsize = nfss->wsize;
        data->retrans = nfss->client->cl_timeout->to_retries;
-       data->auth_flavors[0] = nfss->client->cl_auth->au_flavor;
+       nfs_set_auth_parsed_mount_data(data, nfss->client->cl_auth->au_flavor);
        data->acregmin = nfss->acregmin / HZ;
        data->acregmax = nfss->acregmax / HZ;
        data->acdirmin = nfss->acdirmin / HZ;
@@@ -2277,6 -2295,18 +2295,18 @@@ void nfs_clone_super(struct super_bloc
        nfs_initialise_sb(sb);
  }
  
+ #define NFS_MOUNT_CMP_FLAGMASK ~(NFS_MOUNT_INTR \
+               | NFS_MOUNT_SECURE \
+               | NFS_MOUNT_TCP \
+               | NFS_MOUNT_VER3 \
+               | NFS_MOUNT_KERBEROS \
+               | NFS_MOUNT_NONLM \
+               | NFS_MOUNT_BROKEN_SUID \
+               | NFS_MOUNT_STRICTLOCK \
+               | NFS_MOUNT_UNSHARED \
+               | NFS_MOUNT_NORESVPORT \
+               | NFS_MOUNT_LEGACY_INTERFACE)
  static int nfs_compare_mount_options(const struct super_block *s, const struct nfs_server *b, int flags)
  {
        const struct nfs_server *a = s->s_fs_info;
                goto Ebusy;
        if (a->nfs_client != b->nfs_client)
                goto Ebusy;
-       if (a->flags != b->flags)
+       if ((a->flags ^ b->flags) & NFS_MOUNT_CMP_FLAGMASK)
                goto Ebusy;
        if (a->wsize != b->wsize)
                goto Ebusy;
                goto Ebusy;
        if (a->acdirmax != b->acdirmax)
                goto Ebusy;
-       if (clnt_a->cl_auth->au_flavor != clnt_b->cl_auth->au_flavor)
+       if (b->flags & NFS_MOUNT_SECFLAVOUR &&
+          clnt_a->cl_auth->au_flavor != clnt_b->cl_auth->au_flavor)
                goto Ebusy;
        return 1;
  Ebusy:
@@@ -2478,10 -2509,6 +2509,10 @@@ struct dentry *nfs_fs_mount_common(stru
        if (server->flags & NFS_MOUNT_NOAC)
                sb_mntdata.mntflags |= MS_SYNCHRONOUS;
  
 +      if (mount_info->cloned != NULL && mount_info->cloned->sb != NULL)
 +              if (mount_info->cloned->sb->s_flags & MS_SYNCHRONOUS)
 +                      sb_mntdata.mntflags |= MS_SYNCHRONOUS;
 +
        /* Get a superblock - note that we may end up sharing one that already exists */
        s = sget(nfs_mod->nfs_fs, compare_super, nfs_set_super, flags, &sb_mntdata);
        if (IS_ERR(s)) {
@@@ -2673,15 -2700,17 +2704,17 @@@ static int nfs4_validate_mount_data(voi
                        goto out_no_address;
                args->nfs_server.port = ntohs(((struct sockaddr_in *)sap)->sin_port);
  
-               args->auth_flavors[0] = RPC_AUTH_UNIX;
                if (data->auth_flavourlen) {
+                       rpc_authflavor_t pseudoflavor;
                        if (data->auth_flavourlen > 1)
                                goto out_inval_auth;
-                       if (copy_from_user(&args->auth_flavors[0],
+                       if (copy_from_user(&pseudoflavor,
                                           data->auth_flavours,
-                                          sizeof(args->auth_flavors[0])))
+                                          sizeof(pseudoflavor)))
                                return -EFAULT;
-               }
+                       nfs_set_auth_parsed_mount_data(args, pseudoflavor);
+               } else
+                       nfs_set_auth_parsed_mount_data(args, RPC_AUTH_UNIX);
  
                c = strndup_user(data->hostname.data, NFS4_MAXNAMLEN);
                if (IS_ERR(c))
                args->acdirmax  = data->acdirmax;
                args->nfs_server.protocol = data->proto;
                nfs_validate_transport_protocol(args);
+               if (args->nfs_server.protocol == XPRT_TRANSPORT_UDP)
+                       goto out_invalid_transport_udp;
  
                break;
        default:
@@@ -2735,6 -2766,10 +2770,10 @@@ out_inval_auth
  out_no_address:
        dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n");
        return -EINVAL;
+ out_invalid_transport_udp:
+       dfprintk(MOUNT, "NFSv4: Unsupported transport protocol udp\n");
+       return -EINVAL;
  }
  
  /*
@@@ -2750,6 -2785,7 +2789,7 @@@ bool nfs4_disable_idmapping = true
  unsigned short max_session_slots = NFS4_DEF_SLOT_TABLE_SIZE;
  unsigned short send_implementation_id = 1;
  char nfs4_client_id_uniquifier[NFS4_CLIENT_ID_UNIQ_LEN] = "";
+ bool recover_lost_locks = false;
  
  EXPORT_SYMBOL_GPL(nfs_callback_set_tcpport);
  EXPORT_SYMBOL_GPL(nfs_callback_tcpport);
@@@ -2758,6 -2794,7 +2798,7 @@@ EXPORT_SYMBOL_GPL(nfs4_disable_idmappin
  EXPORT_SYMBOL_GPL(max_session_slots);
  EXPORT_SYMBOL_GPL(send_implementation_id);
  EXPORT_SYMBOL_GPL(nfs4_client_id_uniquifier);
+ EXPORT_SYMBOL_GPL(recover_lost_locks);
  
  #define NFS_CALLBACK_MAXPORTNR (65535U)
  
@@@ -2795,4 -2832,10 +2836,10 @@@ MODULE_PARM_DESC(send_implementation_id
                "Send implementation ID with NFSv4.1 exchange_id");
  MODULE_PARM_DESC(nfs4_unique_id, "nfs_client_id4 uniquifier string");
  
+ module_param(recover_lost_locks, bool, 0644);
+ MODULE_PARM_DESC(recover_lost_locks,
+                "If the server reports that a lock might be lost, "
+                "try to recover it risking data corruption.");
  #endif /* CONFIG_NFS_V4 */
index 1821445708d62d81bb1176ecb20f8480fa4799fa,8ebb7c043f0512c4d4778e9813a925c71555f2c0..096ee58be11a83f2fc05107639a2273cc0c677e6
@@@ -79,7 -79,7 +79,7 @@@ struct rpc_task 
        unsigned short          tk_flags;       /* misc flags */
        unsigned short          tk_timeouts;    /* maj timeouts */
  
- #ifdef RPC_DEBUG
+ #if defined(RPC_DEBUG) || defined(RPC_TRACEPOINTS)
        unsigned short          tk_pid;         /* debugging aid */
  #endif
        unsigned char           tk_priority : 2,/* Task priority */
@@@ -121,7 -121,6 +121,7 @@@ struct rpc_task_setup 
  #define RPC_TASK_SOFTCONN     0x0400          /* Fail if can't connect */
  #define RPC_TASK_SENT         0x0800          /* message was sent */
  #define RPC_TASK_TIMEOUT      0x1000          /* fail with ETIMEDOUT on timeout */
 +#define RPC_TASK_NOCONNECT    0x2000          /* return ENOTCONN if not connected */
  
  #define RPC_IS_ASYNC(t)               ((t)->tk_flags & RPC_TASK_ASYNC)
  #define RPC_IS_SWAPPER(t)     ((t)->tk_flags & RPC_TASK_SWAPPER)
diff --combined net/sunrpc/clnt.c
index ecbc4e3d83ad3f816caa51b6ec942461dac9f090,0a790690d1426b7de8b5103ec475a15b54466c6b..77479606a9716e9526019ba5e5a0dfa4b7d010a2
@@@ -102,12 -102,7 +102,7 @@@ static void rpc_unregister_client(struc
  
  static void __rpc_clnt_remove_pipedir(struct rpc_clnt *clnt)
  {
-       if (clnt->cl_dentry) {
-               if (clnt->cl_auth && clnt->cl_auth->au_ops->pipes_destroy)
-                       clnt->cl_auth->au_ops->pipes_destroy(clnt->cl_auth);
-               rpc_remove_client_dir(clnt->cl_dentry);
-       }
-       clnt->cl_dentry = NULL;
+       rpc_remove_client_dir(clnt);
  }
  
  static void rpc_clnt_remove_pipedir(struct rpc_clnt *clnt)
  }
  
  static struct dentry *rpc_setup_pipedir_sb(struct super_block *sb,
-                                   struct rpc_clnt *clnt,
-                                   const char *dir_name)
+                                   struct rpc_clnt *clnt)
  {
        static uint32_t clntid;
+       const char *dir_name = clnt->cl_program->pipe_dir_name;
        char name[15];
        struct dentry *dir, *dentry;
  
  }
  
  static int
- rpc_setup_pipedir(struct rpc_clnt *clnt, const char *dir_name,
-                 struct super_block *pipefs_sb)
+ rpc_setup_pipedir(struct super_block *pipefs_sb, struct rpc_clnt *clnt)
  {
        struct dentry *dentry;
  
-       clnt->cl_dentry = NULL;
-       if (dir_name == NULL)
-               return 0;
-       dentry = rpc_setup_pipedir_sb(pipefs_sb, clnt, dir_name);
-       if (IS_ERR(dentry))
-               return PTR_ERR(dentry);
-       clnt->cl_dentry = dentry;
+       if (clnt->cl_program->pipe_dir_name != NULL) {
+               dentry = rpc_setup_pipedir_sb(pipefs_sb, clnt);
+               if (IS_ERR(dentry))
+                       return PTR_ERR(dentry);
+       }
        return 0;
  }
  
- static inline int rpc_clnt_skip_event(struct rpc_clnt *clnt, unsigned long event)
+ static int rpc_clnt_skip_event(struct rpc_clnt *clnt, unsigned long event)
  {
-       if (((event == RPC_PIPEFS_MOUNT) && clnt->cl_dentry) ||
-           ((event == RPC_PIPEFS_UMOUNT) && !clnt->cl_dentry))
-               return 1;
-       if ((event == RPC_PIPEFS_MOUNT) && atomic_read(&clnt->cl_count) == 0)
+       if (clnt->cl_program->pipe_dir_name == NULL)
                return 1;
+       switch (event) {
+       case RPC_PIPEFS_MOUNT:
+               if (clnt->cl_pipedir_objects.pdh_dentry != NULL)
+                       return 1;
+               if (atomic_read(&clnt->cl_count) == 0)
+                       return 1;
+               break;
+       case RPC_PIPEFS_UMOUNT:
+               if (clnt->cl_pipedir_objects.pdh_dentry == NULL)
+                       return 1;
+               break;
+       }
        return 0;
  }
  
@@@ -186,18 -188,11 +188,11 @@@ static int __rpc_clnt_handle_event(stru
  
        switch (event) {
        case RPC_PIPEFS_MOUNT:
-               dentry = rpc_setup_pipedir_sb(sb, clnt,
-                                             clnt->cl_program->pipe_dir_name);
+               dentry = rpc_setup_pipedir_sb(sb, clnt);
                if (!dentry)
                        return -ENOENT;
                if (IS_ERR(dentry))
                        return PTR_ERR(dentry);
-               clnt->cl_dentry = dentry;
-               if (clnt->cl_auth->au_ops->pipes_create) {
-                       err = clnt->cl_auth->au_ops->pipes_create(clnt->cl_auth);
-                       if (err)
-                               __rpc_clnt_remove_pipedir(clnt);
-               }
                break;
        case RPC_PIPEFS_UMOUNT:
                __rpc_clnt_remove_pipedir(clnt);
@@@ -230,8 -225,6 +225,6 @@@ static struct rpc_clnt *rpc_get_client_
  
        spin_lock(&sn->rpc_client_lock);
        list_for_each_entry(clnt, &sn->all_clients, cl_clients) {
-               if (clnt->cl_program->pipe_dir_name == NULL)
-                       continue;
                if (rpc_clnt_skip_event(clnt, event))
                        continue;
                spin_unlock(&sn->rpc_client_lock);
@@@ -282,7 -275,10 +275,10 @@@ static void rpc_clnt_set_nodename(struc
  static int rpc_client_register(const struct rpc_create_args *args,
                               struct rpc_clnt *clnt)
  {
-       const struct rpc_program *program = args->program;
+       struct rpc_auth_create_args auth_args = {
+               .pseudoflavor = args->authflavor,
+               .target_name = args->client_name,
+       };
        struct rpc_auth *auth;
        struct net *net = rpc_net_ns(clnt);
        struct super_block *pipefs_sb;
  
        pipefs_sb = rpc_get_sb_net(net);
        if (pipefs_sb) {
-               err = rpc_setup_pipedir(clnt, program->pipe_dir_name, pipefs_sb);
+               err = rpc_setup_pipedir(pipefs_sb, clnt);
                if (err)
                        goto out;
        }
        if (pipefs_sb)
                rpc_put_sb_net(net);
  
-       auth = rpcauth_create(args->authflavor, clnt);
+       auth = rpcauth_create(&auth_args, clnt);
        if (IS_ERR(auth)) {
                dprintk("RPC:       Couldn't create auth handle (flavor %u)\n",
                                args->authflavor);
@@@ -317,7 -313,27 +313,27 @@@ out
        return err;
  }
  
- static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, struct rpc_xprt *xprt)
+ static DEFINE_IDA(rpc_clids);
+ static int rpc_alloc_clid(struct rpc_clnt *clnt)
+ {
+       int clid;
+       clid = ida_simple_get(&rpc_clids, 0, 0, GFP_KERNEL);
+       if (clid < 0)
+               return clid;
+       clnt->cl_clid = clid;
+       return 0;
+ }
+ static void rpc_free_clid(struct rpc_clnt *clnt)
+ {
+       ida_simple_remove(&rpc_clids, clnt->cl_clid);
+ }
+ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args,
+               struct rpc_xprt *xprt,
+               struct rpc_clnt *parent)
  {
        const struct rpc_program *program = args->program;
        const struct rpc_version *version;
        clnt = kzalloc(sizeof(*clnt), GFP_KERNEL);
        if (!clnt)
                goto out_err;
-       clnt->cl_parent = clnt;
+       clnt->cl_parent = parent ? : clnt;
+       err = rpc_alloc_clid(clnt);
+       if (err)
+               goto out_no_clid;
  
        rcu_assign_pointer(clnt->cl_xprt, xprt);
        clnt->cl_procinfo = version->procs;
        clnt->cl_maxproc  = version->nrprocs;
-       clnt->cl_protname = program->name;
        clnt->cl_prog     = args->prognumber ? : program->number;
        clnt->cl_vers     = version->number;
        clnt->cl_stats    = program->stats;
        clnt->cl_metrics  = rpc_alloc_iostats(clnt);
+       rpc_init_pipe_dir_head(&clnt->cl_pipedir_objects);
        err = -ENOMEM;
        if (clnt->cl_metrics == NULL)
                goto out_no_stats;
  
        clnt->cl_rtt = &clnt->cl_rtt_default;
        rpc_init_rtt(&clnt->cl_rtt_default, clnt->cl_timeout->to_initval);
-       clnt->cl_principal = NULL;
-       if (args->client_name) {
-               clnt->cl_principal = kstrdup(args->client_name, GFP_KERNEL);
-               if (!clnt->cl_principal)
-                       goto out_no_principal;
-       }
  
        atomic_set(&clnt->cl_count, 1);
  
        err = rpc_client_register(args, clnt);
        if (err)
                goto out_no_path;
+       if (parent)
+               atomic_inc(&parent->cl_count);
        return clnt;
  
  out_no_path:
-       kfree(clnt->cl_principal);
- out_no_principal:
        rpc_free_iostats(clnt->cl_metrics);
  out_no_stats:
+       rpc_free_clid(clnt);
+ out_no_clid:
        kfree(clnt);
  out_err:
        rpciod_down();
@@@ -479,7 -495,7 +495,7 @@@ struct rpc_clnt *rpc_create(struct rpc_
        if (args->flags & RPC_CLNT_CREATE_NONPRIVPORT)
                xprt->resvport = 0;
  
-       clnt = rpc_new_client(args, xprt);
+       clnt = rpc_new_client(args, xprt, NULL);
        if (IS_ERR(clnt))
                return clnt;
  
@@@ -526,15 -542,12 +542,12 @@@ static struct rpc_clnt *__rpc_clone_cli
                goto out_err;
        args->servername = xprt->servername;
  
-       new = rpc_new_client(args, xprt);
+       new = rpc_new_client(args, xprt, clnt);
        if (IS_ERR(new)) {
                err = PTR_ERR(new);
                goto out_err;
        }
  
-       atomic_inc(&clnt->cl_count);
-       new->cl_parent = clnt;
        /* Turn off autobind on clones */
        new->cl_autobind = 0;
        new->cl_softrtry = clnt->cl_softrtry;
@@@ -561,7 -574,6 +574,6 @@@ struct rpc_clnt *rpc_clone_client(struc
                .prognumber     = clnt->cl_prog,
                .version        = clnt->cl_vers,
                .authflavor     = clnt->cl_auth->au_flavor,
-               .client_name    = clnt->cl_principal,
        };
        return __rpc_clone_client(&args, clnt);
  }
@@@ -583,7 -595,6 +595,6 @@@ rpc_clone_client_set_auth(struct rpc_cl
                .prognumber     = clnt->cl_prog,
                .version        = clnt->cl_vers,
                .authflavor     = flavor,
-               .client_name    = clnt->cl_principal,
        };
        return __rpc_clone_client(&args, clnt);
  }
@@@ -629,7 -640,7 +640,7 @@@ void rpc_shutdown_client(struct rpc_cln
        might_sleep();
  
        dprintk_rcu("RPC:       shutting down %s client for %s\n",
-                       clnt->cl_protname,
+                       clnt->cl_program->name,
                        rcu_dereference(clnt->cl_xprt)->servername);
  
        while (!list_empty(&clnt->cl_tasks)) {
@@@ -649,17 -660,17 +660,17 @@@ static voi
  rpc_free_client(struct rpc_clnt *clnt)
  {
        dprintk_rcu("RPC:       destroying %s client for %s\n",
-                       clnt->cl_protname,
+                       clnt->cl_program->name,
                        rcu_dereference(clnt->cl_xprt)->servername);
        if (clnt->cl_parent != clnt)
                rpc_release_client(clnt->cl_parent);
        rpc_clnt_remove_pipedir(clnt);
        rpc_unregister_client(clnt);
        rpc_free_iostats(clnt->cl_metrics);
-       kfree(clnt->cl_principal);
        clnt->cl_metrics = NULL;
        xprt_put(rcu_dereference_raw(clnt->cl_xprt));
        rpciod_down();
+       rpc_free_clid(clnt);
        kfree(clnt);
  }
  
@@@ -720,7 -731,6 +731,6 @@@ struct rpc_clnt *rpc_bind_new_program(s
                .prognumber     = program->number,
                .version        = vers,
                .authflavor     = old->cl_auth->au_flavor,
-               .client_name    = old->cl_principal,
        };
        struct rpc_clnt *clnt;
        int err;
@@@ -1299,7 -1309,7 +1309,7 @@@ call_start(struct rpc_task *task
        struct rpc_clnt *clnt = task->tk_client;
  
        dprintk("RPC: %5u call_start %s%d proc %s (%s)\n", task->tk_pid,
-                       clnt->cl_protname, clnt->cl_vers,
+                       clnt->cl_program->name, clnt->cl_vers,
                        rpc_proc_name(task),
                        (RPC_IS_ASYNC(task) ? "async" : "sync"));
  
@@@ -1423,9 -1433,9 +1433,9 @@@ call_refreshresult(struct rpc_task *tas
                return;
        case -ETIMEDOUT:
                rpc_delay(task, 3*HZ);
-       case -EKEYEXPIRED:
        case -EAGAIN:
                status = -EACCES;
+       case -EKEYEXPIRED:
                if (!task->tk_cred_retry)
                        break;
                task->tk_cred_retry--;
@@@ -1660,10 -1670,6 +1670,10 @@@ call_connect(struct rpc_task *task
                task->tk_action = call_connect_status;
                if (task->tk_status < 0)
                        return;
 +              if (task->tk_flags & RPC_TASK_NOCONNECT) {
 +                      rpc_exit(task, -ENOTCONN);
 +                      return;
 +              }
                xprt_connect(task);
        }
  }
@@@ -1912,7 -1918,7 +1922,7 @@@ call_status(struct rpc_task *task
        default:
                if (clnt->cl_chatty)
                        printk("%s: RPC call returned error %d\n",
-                              clnt->cl_protname, -status);
+                              clnt->cl_program->name, -status);
                rpc_exit(task, status);
        }
  }
@@@ -1943,7 -1949,7 +1953,7 @@@ call_timeout(struct rpc_task *task
                if (clnt->cl_chatty) {
                        rcu_read_lock();
                        printk(KERN_NOTICE "%s: server %s not responding, timed out\n",
-                               clnt->cl_protname,
+                               clnt->cl_program->name,
                                rcu_dereference(clnt->cl_xprt)->servername);
                        rcu_read_unlock();
                }
                if (clnt->cl_chatty) {
                        rcu_read_lock();
                        printk(KERN_NOTICE "%s: server %s not responding, still trying\n",
-                       clnt->cl_protname,
+                       clnt->cl_program->name,
                        rcu_dereference(clnt->cl_xprt)->servername);
                        rcu_read_unlock();
                }
@@@ -1994,7 -2000,7 +2004,7 @@@ call_decode(struct rpc_task *task
                if (clnt->cl_chatty) {
                        rcu_read_lock();
                        printk(KERN_NOTICE "%s: server %s OK\n",
-                               clnt->cl_protname,
+                               clnt->cl_program->name,
                                rcu_dereference(clnt->cl_xprt)->servername);
                        rcu_read_unlock();
                }
                        goto out_retry;
                }
                dprintk("RPC:       %s: too small RPC reply size (%d bytes)\n",
-                               clnt->cl_protname, task->tk_status);
+                               clnt->cl_program->name, task->tk_status);
                task->tk_action = call_timeout;
                goto out_retry;
        }
@@@ -2091,7 -2097,8 +2101,8 @@@ rpc_verify_header(struct rpc_task *task
                dprintk("RPC: %5u %s: XDR representation not a multiple of"
                       " 4 bytes: 0x%x\n", task->tk_pid, __func__,
                       task->tk_rqstp->rq_rcv_buf.len);
-               goto out_eio;
+               error = -EIO;
+               goto out_err;
        }
        if ((len -= 3) < 0)
                goto out_overflow;
        if ((n = ntohl(*p++)) != RPC_REPLY) {
                dprintk("RPC: %5u %s: not an RPC reply: %x\n",
                        task->tk_pid, __func__, n);
+               error = -EIO;
                goto out_garbage;
        }
  
                        dprintk("RPC: %5u %s: RPC call rejected, "
                                "unknown error: %x\n",
                                task->tk_pid, __func__, n);
-                       goto out_eio;
+                       error = -EIO;
+                       goto out_err;
                }
                if (--len < 0)
                        goto out_overflow;
                                task->tk_pid, __func__, n);
                goto out_err;
        }
-       if (!(p = rpcauth_checkverf(task, p))) {
-               dprintk("RPC: %5u %s: auth check failed\n",
-                               task->tk_pid, __func__);
+       p = rpcauth_checkverf(task, p);
+       if (IS_ERR(p)) {
+               error = PTR_ERR(p);
+               dprintk("RPC: %5u %s: auth check failed with %d\n",
+                               task->tk_pid, __func__, error);
                goto out_garbage;               /* bad verifier, retry */
        }
        len = p - (__be32 *)iov->iov_base - 1;
@@@ -2218,8 -2229,6 +2233,6 @@@ out_garbage
  out_retry:
                return ERR_PTR(-EAGAIN);
        }
- out_eio:
-       error = -EIO;
  out_err:
        rpc_exit(task, error);
        dprintk("RPC: %5u %s: call failed with error %d\n", task->tk_pid,
@@@ -2291,7 -2300,7 +2304,7 @@@ static void rpc_show_task(const struct 
        printk(KERN_INFO "%5u %04x %6d %8p %8p %8ld %8p %sv%u %s a:%ps q:%s\n",
                task->tk_pid, task->tk_flags, task->tk_status,
                clnt, task->tk_rqstp, task->tk_timeout, task->tk_ops,
-               clnt->cl_protname, clnt->cl_vers, rpc_proc_name(task),
+               clnt->cl_program->name, clnt->cl_vers, rpc_proc_name(task),
                task->tk_action, rpc_waitq);
  }
  
diff --combined net/sunrpc/xprtsock.c
index d6656d7768f4e689e94aca67189a0634bd950fad,b98bce5461b59e9d4a62aa5459249fa6b2d463bf..ee03d35677d962a3385d8d01a31968b70fa77b56
@@@ -47,6 -47,8 +47,8 @@@
  #include <net/udp.h>
  #include <net/tcp.h>
  
+ #include <trace/events/sunrpc.h>
  #include "sunrpc.h"
  
  static void xs_close(struct rpc_xprt *xprt);
@@@ -665,8 -667,10 +667,10 @@@ static void xs_tcp_shutdown(struct rpc_
        struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
        struct socket *sock = transport->sock;
  
-       if (sock != NULL)
+       if (sock != NULL) {
                kernel_sock_shutdown(sock, SHUT_WR);
+               trace_rpc_socket_shutdown(xprt, sock);
+       }
  }
  
  /**
@@@ -811,6 -815,7 +815,7 @@@ static void xs_reset_transport(struct s
  
        sk->sk_no_check = 0;
  
+       trace_rpc_socket_close(&transport->xprt, sock);
        sock_release(sock);
  }
  
@@@ -1492,6 -1497,7 +1497,7 @@@ static void xs_tcp_state_change(struct 
                        sock_flag(sk, SOCK_ZAPPED),
                        sk->sk_shutdown);
  
+       trace_rpc_socket_state_change(xprt, sk->sk_socket);
        switch (sk->sk_state) {
        case TCP_ESTABLISHED:
                spin_lock(&xprt->transport_lock);
@@@ -1602,7 -1608,7 +1608,7 @@@ static void xs_tcp_write_space(struct s
        read_lock_bh(&sk->sk_callback_lock);
  
        /* from net/core/stream.c:sk_stream_write_space */
 -      if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk))
 +      if (sk_stream_is_writeable(sk))
                xs_write_space(sk);
  
        read_unlock_bh(&sk->sk_callback_lock);
@@@ -1896,6 -1902,7 +1902,7 @@@ static int xs_local_setup_socket(struc
                        xprt, xprt->address_strings[RPC_DISPLAY_ADDR]);
  
        status = xs_local_finish_connecting(xprt, sock);
+       trace_rpc_socket_connect(xprt, sock, status);
        switch (status) {
        case 0:
                dprintk("RPC:       xprt %p connected to %s\n",
@@@ -2039,6 -2046,7 +2046,7 @@@ static void xs_udp_setup_socket(struct 
                        xprt->address_strings[RPC_DISPLAY_PORT]);
  
        xs_udp_finish_connecting(xprt, sock);
+       trace_rpc_socket_connect(xprt, sock, 0);
        status = 0;
  out:
        xprt_clear_connecting(xprt);
@@@ -2064,6 -2072,8 +2072,8 @@@ static void xs_abort_connection(struct 
        memset(&any, 0, sizeof(any));
        any.sa_family = AF_UNSPEC;
        result = kernel_connect(transport->sock, &any, sizeof(any), 0);
+       trace_rpc_socket_reset_connection(&transport->xprt,
+                       transport->sock, result);
        if (!result)
                xs_sock_reset_connection_flags(&transport->xprt);
        dprintk("RPC:       AF_UNSPEC connect return code %d\n", result);
@@@ -2194,6 -2204,7 +2204,7 @@@ static void xs_tcp_setup_socket(struct 
                        xprt->address_strings[RPC_DISPLAY_PORT]);
  
        status = xs_tcp_finish_connecting(xprt, sock);
+       trace_rpc_socket_connect(xprt, sock, status);
        dprintk("RPC:       %p connect status %d connected %d sock state %d\n",
                        xprt, -status, xprt_connected(xprt),
                        sock->sk->sk_state);