--- /dev/null
+From 987da4791052fa298b7cfcde4dea9f6f2bbc786b Mon Sep 17 00:00:00 2001
+From: Christoph Hellwig <hch@infradead.org>
+Date: Mon, 18 Nov 2013 05:07:47 -0800
+Subject: nfsd: make sure to balance get/put_write_access
+
+From: Christoph Hellwig <hch@infradead.org>
+
+commit 987da4791052fa298b7cfcde4dea9f6f2bbc786b upstream.
+
+Use a straight goto error label style in nfsd_setattr to make sure
+we always do the put_write_access call after we got it earlier.
+
+Note that the we have been failing to do that in the case
+nfsd_break_lease() returns an error, a bug introduced into 2.6.38 with
+6a76bebefe15d9a08864f824d7f8d5beaf37c997 "nfsd4: break lease on nfsd
+setattr".
+
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: J. Bruce Fields <bfields@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/nfsd/vfs.c | 29 +++++++++++++++--------------
+ 1 file changed, 15 insertions(+), 14 deletions(-)
+
+--- a/fs/nfsd/vfs.c
++++ b/fs/nfsd/vfs.c
+@@ -443,27 +443,28 @@ nfsd_setattr(struct svc_rqst *rqstp, str
+
+ iap->ia_valid |= ATTR_CTIME;
+
+- err = nfserr_notsync;
+- if (!check_guard || guardtime == inode->i_ctime.tv_sec) {
+- host_err = nfsd_break_lease(inode);
+- if (host_err)
+- goto out_nfserr;
+- fh_lock(fhp);
+-
+- host_err = notify_change(dentry, iap);
+- err = nfserrno(host_err);
+- fh_unlock(fhp);
++ if (check_guard && guardtime != inode->i_ctime.tv_sec) {
++ err = nfserr_notsync;
++ goto out_put_write_access;
+ }
++
++ host_err = nfsd_break_lease(inode);
++ if (host_err)
++ goto out_put_write_access_nfserror;
++
++ fh_lock(fhp);
++ host_err = notify_change(dentry, iap);
++ fh_unlock(fhp);
++
++out_put_write_access_nfserror:
++ err = nfserrno(host_err);
++out_put_write_access:
+ if (size_change)
+ put_write_access(inode);
+ if (!err)
+ commit_metadata(fhp);
+ out:
+ return err;
+-
+-out_nfserr:
+- err = nfserrno(host_err);
+- goto out;
+ }
+
+ #if defined(CONFIG_NFSD_V2_ACL) || \
--- /dev/null
+From 818e5a22e907fbae75e9c1fd78233baec9fa64b6 Mon Sep 17 00:00:00 2001
+From: Christoph Hellwig <hch@infradead.org>
+Date: Mon, 18 Nov 2013 05:07:30 -0800
+Subject: nfsd: split up nfsd_setattr
+
+From: Christoph Hellwig <hch@infradead.org>
+
+commit 818e5a22e907fbae75e9c1fd78233baec9fa64b6 upstream.
+
+Split out two helpers to make the code more readable and easier to verify
+for correctness.
+
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: J. Bruce Fields <bfields@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/nfsd/vfs.c | 144 +++++++++++++++++++++++++++++++++-------------------------
+ 1 file changed, 84 insertions(+), 60 deletions(-)
+
+--- a/fs/nfsd/vfs.c
++++ b/fs/nfsd/vfs.c
+@@ -297,41 +297,12 @@ commit_metadata(struct svc_fh *fhp)
+ }
+
+ /*
+- * Set various file attributes.
+- * N.B. After this call fhp needs an fh_put
++ * Go over the attributes and take care of the small differences between
++ * NFS semantics and what Linux expects.
+ */
+-__be32
+-nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
+- int check_guard, time_t guardtime)
++static void
++nfsd_sanitize_attrs(struct inode *inode, struct iattr *iap)
+ {
+- struct dentry *dentry;
+- struct inode *inode;
+- int accmode = NFSD_MAY_SATTR;
+- umode_t ftype = 0;
+- __be32 err;
+- int host_err;
+- int size_change = 0;
+-
+- if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE))
+- accmode |= NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE;
+- if (iap->ia_valid & ATTR_SIZE)
+- ftype = S_IFREG;
+-
+- /* Get inode */
+- err = fh_verify(rqstp, fhp, ftype, accmode);
+- if (err)
+- goto out;
+-
+- dentry = fhp->fh_dentry;
+- inode = dentry->d_inode;
+-
+- /* Ignore any mode updates on symlinks */
+- if (S_ISLNK(inode->i_mode))
+- iap->ia_valid &= ~ATTR_MODE;
+-
+- if (!iap->ia_valid)
+- goto out;
+-
+ /*
+ * NFSv2 does not differentiate between "set-[ac]time-to-now"
+ * which only requires access, and "set-[ac]time-to-X" which
+@@ -341,8 +312,7 @@ nfsd_setattr(struct svc_rqst *rqstp, str
+ * convert to "set to now" instead of "set to explicit time"
+ *
+ * We only call inode_change_ok as the last test as technically
+- * it is not an interface that we should be using. It is only
+- * valid if the filesystem does not define it's own i_op->setattr.
++ * it is not an interface that we should be using.
+ */
+ #define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET)
+ #define MAX_TOUCH_TIME_ERROR (30*60)
+@@ -368,30 +338,6 @@ nfsd_setattr(struct svc_rqst *rqstp, str
+ iap->ia_valid &= ~BOTH_TIME_SET;
+ }
+ }
+-
+- /*
+- * The size case is special.
+- * It changes the file as well as the attributes.
+- */
+- if (iap->ia_valid & ATTR_SIZE) {
+- if (iap->ia_size < inode->i_size) {
+- err = nfsd_permission(rqstp, fhp->fh_export, dentry,
+- NFSD_MAY_TRUNC|NFSD_MAY_OWNER_OVERRIDE);
+- if (err)
+- goto out;
+- }
+-
+- host_err = get_write_access(inode);
+- if (host_err)
+- goto out_nfserr;
+-
+- size_change = 1;
+- host_err = locks_verify_truncate(inode, NULL, iap->ia_size);
+- if (host_err) {
+- put_write_access(inode);
+- goto out_nfserr;
+- }
+- }
+
+ /* sanitize the mode change */
+ if (iap->ia_valid & ATTR_MODE) {
+@@ -414,8 +360,86 @@ nfsd_setattr(struct svc_rqst *rqstp, str
+ iap->ia_valid |= (ATTR_KILL_SUID | ATTR_KILL_SGID);
+ }
+ }
++}
++
++static __be32
++nfsd_get_write_access(struct svc_rqst *rqstp, struct svc_fh *fhp,
++ struct iattr *iap)
++{
++ struct inode *inode = fhp->fh_dentry->d_inode;
++ int host_err;
++
++ if (iap->ia_size < inode->i_size) {
++ __be32 err;
++
++ err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry,
++ NFSD_MAY_TRUNC | NFSD_MAY_OWNER_OVERRIDE);
++ if (err)
++ return err;
++ }
++
++ host_err = get_write_access(inode);
++ if (host_err)
++ goto out_nfserrno;
++
++ host_err = locks_verify_truncate(inode, NULL, iap->ia_size);
++ if (host_err)
++ goto out_put_write_access;
++ return 0;
++
++out_put_write_access:
++ put_write_access(inode);
++out_nfserrno:
++ return nfserrno(host_err);
++}
++
++/*
++ * Set various file attributes. After this call fhp needs an fh_put.
++ */
++__be32
++nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
++ int check_guard, time_t guardtime)
++{
++ struct dentry *dentry;
++ struct inode *inode;
++ int accmode = NFSD_MAY_SATTR;
++ umode_t ftype = 0;
++ __be32 err;
++ int host_err;
++ int size_change = 0;
++
++ if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE))
++ accmode |= NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE;
++ if (iap->ia_valid & ATTR_SIZE)
++ ftype = S_IFREG;
++
++ /* Get inode */
++ err = fh_verify(rqstp, fhp, ftype, accmode);
++ if (err)
++ goto out;
++
++ dentry = fhp->fh_dentry;
++ inode = dentry->d_inode;
++
++ /* Ignore any mode updates on symlinks */
++ if (S_ISLNK(inode->i_mode))
++ iap->ia_valid &= ~ATTR_MODE;
++
++ if (!iap->ia_valid)
++ goto out;
++
++ nfsd_sanitize_attrs(inode, iap);
+
+- /* Change the attributes. */
++ /*
++ * The size case is special, it changes the file in addition to the
++ * attributes.
++ */
++ if (iap->ia_valid & ATTR_SIZE) {
++ err = nfsd_get_write_access(rqstp, fhp, iap);
++ if (err)
++ goto out;
++ size_change = 1;
++ }
+
+ iap->ia_valid |= ATTR_CTIME;
+
--- /dev/null
+From a6f951ddbdfb7bd87d31a44f61abe202ed6ce57f Mon Sep 17 00:00:00 2001
+From: Trond Myklebust <Trond.Myklebust@netapp.com>
+Date: Tue, 1 Oct 2013 14:24:58 -0400
+Subject: NFSv4: Fix a use-after-free situation in _nfs4_proc_getlk()
+
+From: Trond Myklebust <Trond.Myklebust@netapp.com>
+
+commit a6f951ddbdfb7bd87d31a44f61abe202ed6ce57f upstream.
+
+In nfs4_proc_getlk(), when some error causes a retry of the call to
+_nfs4_proc_getlk(), we can end up with Oopses of the form
+
+ BUG: unable to handle kernel NULL pointer dereference at 0000000000000134
+ IP: [<ffffffff8165270e>] _raw_spin_lock+0xe/0x30
+<snip>
+ Call Trace:
+ [<ffffffff812f287d>] _atomic_dec_and_lock+0x4d/0x70
+ [<ffffffffa053c4f2>] nfs4_put_lock_state+0x32/0xb0 [nfsv4]
+ [<ffffffffa053c585>] nfs4_fl_release_lock+0x15/0x20 [nfsv4]
+ [<ffffffffa0522c06>] _nfs4_proc_getlk.isra.40+0x146/0x170 [nfsv4]
+ [<ffffffffa052ad99>] nfs4_proc_lock+0x399/0x5a0 [nfsv4]
+
+The problem is that we don't clear the request->fl_ops after the first
+try and so when we retry, nfs4_set_lock_state() exits early without
+setting the lock stateid.
+Regression introduced by commit 70cc6487a4e08b8698c0e2ec935fb48d10490162
+(locks: make ->lock release private data before returning in GETLK case)
+
+Reported-by: Weston Andros Adamson <dros@netapp.com>
+Reported-by: Jorge Mora <mora@netapp.com>
+Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/nfs/nfs4proc.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/fs/nfs/nfs4proc.c
++++ b/fs/nfs/nfs4proc.c
+@@ -4207,6 +4207,7 @@ static int _nfs4_proc_getlk(struct nfs4_
+ status = 0;
+ }
+ request->fl_ops->fl_release_private(request);
++ request->fl_ops = NULL;
+ out:
+ return status;
+ }