nfsd: Drop BUG_ON and ignore SECLABEL on absent filesystem
[firefly-linux-kernel-4.4.55.git] / fs / nfsd / nfs4xdr.c
index 158badf945df1da9b5f146933b525538cbf1211f..75e0563c09d1911d927501ee52b53a3bd988940e 100644 (file)
@@ -33,6 +33,7 @@
  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <linux/file.h>
 #include <linux/slab.h>
 #include <linux/namei.h>
 #include <linux/statfs.h>
@@ -2142,6 +2143,7 @@ nfsd4_encode_aclname(struct xdr_stream *xdr, struct svc_rqst *rqstp,
 #define WORD0_ABSENT_FS_ATTRS (FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_FSID | \
                              FATTR4_WORD0_RDATTR_ERROR)
 #define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID
+#define WORD2_ABSENT_FS_ATTRS 0
 
 #ifdef CONFIG_NFSD_V4_SECURITY_LABEL
 static inline __be32
@@ -2170,7 +2172,7 @@ nfsd4_encode_security_label(struct xdr_stream *xdr, struct svc_rqst *rqstp,
 { return 0; }
 #endif
 
-static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err)
+static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *bmval2, u32 *rdattr_err)
 {
        /* As per referral draft:  */
        if (*bmval0 & ~WORD0_ABSENT_FS_ATTRS ||
@@ -2183,6 +2185,7 @@ static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err)
        }
        *bmval0 &= WORD0_ABSENT_FS_ATTRS;
        *bmval1 &= WORD1_ABSENT_FS_ATTRS;
+       *bmval2 &= WORD2_ABSENT_FS_ATTRS;
        return 0;
 }
 
@@ -2227,7 +2230,6 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
        u32 rdattr_err = 0;
        __be32 status;
        int err;
-       int aclsupport = 0;
        struct nfs4_acl *acl = NULL;
        void *context = NULL;
        int contextlen;
@@ -2246,8 +2248,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
        BUG_ON(bmval2 & ~nfsd_suppattrs2(minorversion));
 
        if (exp->ex_fslocs.migrated) {
-               BUG_ON(bmval[2]);
-               status = fattr_handle_absent_fs(&bmval0, &bmval1, &rdattr_err);
+               status = fattr_handle_absent_fs(&bmval0, &bmval1, &bmval2, &rdattr_err);
                if (status)
                        goto out;
        }
@@ -2274,24 +2275,20 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
                        goto out;
                fhp = tempfh;
        }
-       if (bmval0 & (FATTR4_WORD0_ACL | FATTR4_WORD0_ACLSUPPORT
-                       | FATTR4_WORD0_SUPPORTED_ATTRS)) {
+       if (bmval0 & FATTR4_WORD0_ACL) {
                err = nfsd4_get_nfs4_acl(rqstp, dentry, &acl);
-               aclsupport = (err == 0);
-               if (bmval0 & FATTR4_WORD0_ACL) {
-                       if (err == -EOPNOTSUPP)
-                               bmval0 &= ~FATTR4_WORD0_ACL;
-                       else if (err == -EINVAL) {
-                               status = nfserr_attrnotsupp;
-                               goto out;
-                       } else if (err != 0)
-                               goto out_nfserr;
-               }
+               if (err == -EOPNOTSUPP)
+                       bmval0 &= ~FATTR4_WORD0_ACL;
+               else if (err == -EINVAL) {
+                       status = nfserr_attrnotsupp;
+                       goto out;
+               } else if (err != 0)
+                       goto out_nfserr;
        }
 
 #ifdef CONFIG_NFSD_V4_SECURITY_LABEL
-       if ((bmval[2] & FATTR4_WORD2_SECURITY_LABEL) ||
-                       bmval[0] & FATTR4_WORD0_SUPPORTED_ATTRS) {
+       if ((bmval2 & FATTR4_WORD2_SECURITY_LABEL) ||
+            bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) {
                err = security_inode_getsecctx(d_inode(dentry),
                                                &context, &contextlen);
                contextsupport = (err == 0);
@@ -2338,7 +2335,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
                u32 word1 = nfsd_suppattrs1(minorversion);
                u32 word2 = nfsd_suppattrs2(minorversion);
 
-               if (!aclsupport)
+               if (!IS_POSIXACL(dentry->d_inode))
                        word0 &= ~FATTR4_WORD0_ACL;
                if (!contextsupport)
                        word2 &= ~FATTR4_WORD2_SECURITY_LABEL;
@@ -2486,7 +2483,7 @@ out_acl:
                p = xdr_reserve_space(xdr, 4);
                if (!p)
                        goto out_resource;
-               *p++ = cpu_to_be32(aclsupport ?
+               *p++ = cpu_to_be32(IS_POSIXACL(dentry->d_inode) ?
                        ACL4_SUPPORT_ALLOW_ACL|ACL4_SUPPORT_DENY_ACL : 0);
        }
        if (bmval0 & FATTR4_WORD0_CANSETTIME) {
@@ -3422,52 +3419,51 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
        unsigned long maxcount;
        struct xdr_stream *xdr = &resp->xdr;
        struct file *file = read->rd_filp;
-       struct svc_fh *fhp = read->rd_fhp;
        int starting_len = xdr->buf->len;
-       struct raparms *ra;
+       struct raparms *ra = NULL;
        __be32 *p;
-       __be32 err;
 
        if (nfserr)
-               return nfserr;
+               goto out;
 
        p = xdr_reserve_space(xdr, 8); /* eof flag and byte count */
        if (!p) {
                WARN_ON_ONCE(test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags));
-               return nfserr_resource;
+               nfserr = nfserr_resource;
+               goto out;
        }
-       if (resp->xdr.buf->page_len && test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags)) {
+       if (resp->xdr.buf->page_len &&
+           test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags)) {
                WARN_ON_ONCE(1);
-               return nfserr_resource;
+               nfserr = nfserr_resource;
+               goto out;
        }
        xdr_commit_encode(xdr);
 
        maxcount = svc_max_payload(resp->rqstp);
-       maxcount = min_t(unsigned long, maxcount, (xdr->buf->buflen - xdr->buf->len));
+       maxcount = min_t(unsigned long, maxcount,
+                        (xdr->buf->buflen - xdr->buf->len));
        maxcount = min_t(unsigned long, maxcount, read->rd_length);
 
-       if (read->rd_filp)
-               err = nfsd_permission(resp->rqstp, fhp->fh_export,
-                               fhp->fh_dentry,
-                               NFSD_MAY_READ|NFSD_MAY_OWNER_OVERRIDE);
-       else
-               err = nfsd_get_tmp_read_open(resp->rqstp, read->rd_fhp,
-                                               &file, &ra);
-       if (err)
-               goto err_truncate;
+       if (read->rd_tmp_file)
+               ra = nfsd_init_raparms(file);
 
-       if (file->f_op->splice_read && test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags))
-               err = nfsd4_encode_splice_read(resp, read, file, maxcount);
+       if (file->f_op->splice_read &&
+           test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags))
+               nfserr = nfsd4_encode_splice_read(resp, read, file, maxcount);
        else
-               err = nfsd4_encode_readv(resp, read, file, maxcount);
+               nfserr = nfsd4_encode_readv(resp, read, file, maxcount);
 
-       if (!read->rd_filp)
-               nfsd_put_tmp_read_open(file, ra);
+       if (ra)
+               nfsd_put_raparams(file, ra);
 
-err_truncate:
-       if (err)
+       if (nfserr)
                xdr_truncate_encode(xdr, starting_len);
-       return err;
+
+out:
+       if (file)
+               fput(file);
+       return nfserr;
 }
 
 static __be32