These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / fs / nfsd / nfs4xdr.c
index 3dd1b61..51c9e9c 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>
@@ -2225,6 +2226,39 @@ static int get_parent_attributes(struct svc_export *exp, struct kstat *stat)
        return err;
 }
 
+static __be32
+nfsd4_encode_bitmap(struct xdr_stream *xdr, u32 bmval0, u32 bmval1, u32 bmval2)
+{
+       __be32 *p;
+
+       if (bmval2) {
+               p = xdr_reserve_space(xdr, 16);
+               if (!p)
+                       goto out_resource;
+               *p++ = cpu_to_be32(3);
+               *p++ = cpu_to_be32(bmval0);
+               *p++ = cpu_to_be32(bmval1);
+               *p++ = cpu_to_be32(bmval2);
+       } else if (bmval1) {
+               p = xdr_reserve_space(xdr, 12);
+               if (!p)
+                       goto out_resource;
+               *p++ = cpu_to_be32(2);
+               *p++ = cpu_to_be32(bmval0);
+               *p++ = cpu_to_be32(bmval1);
+       } else {
+               p = xdr_reserve_space(xdr, 8);
+               if (!p)
+                       goto out_resource;
+               *p++ = cpu_to_be32(1);
+               *p++ = cpu_to_be32(bmval0);
+       }
+
+       return 0;
+out_resource:
+       return nfserr_resource;
+}
+
 /*
  * Note: @fhp can be NULL; in this case, we might have to compose the filehandle
  * ourselves.
@@ -2250,7 +2284,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;
@@ -2296,19 +2329,15 @@ 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
@@ -2326,28 +2355,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
        }
 #endif /* CONFIG_NFSD_V4_SECURITY_LABEL */
 
-       if (bmval2) {
-               p = xdr_reserve_space(xdr, 16);
-               if (!p)
-                       goto out_resource;
-               *p++ = cpu_to_be32(3);
-               *p++ = cpu_to_be32(bmval0);
-               *p++ = cpu_to_be32(bmval1);
-               *p++ = cpu_to_be32(bmval2);
-       } else if (bmval1) {
-               p = xdr_reserve_space(xdr, 12);
-               if (!p)
-                       goto out_resource;
-               *p++ = cpu_to_be32(2);
-               *p++ = cpu_to_be32(bmval0);
-               *p++ = cpu_to_be32(bmval1);
-       } else {
-               p = xdr_reserve_space(xdr, 8);
-               if (!p)
-                       goto out_resource;
-               *p++ = cpu_to_be32(1);
-               *p++ = cpu_to_be32(bmval0);
-       }
+       status = nfsd4_encode_bitmap(xdr, bmval0, bmval1, bmval2);
+       if (status)
+               goto out;
 
        attrlen_offset = xdr->buf->len;
        p = xdr_reserve_space(xdr, 4);
@@ -2360,7 +2370,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;
@@ -2508,7 +2518,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) {
@@ -2700,6 +2710,9 @@ out_acl:
                *p++ = cpu_to_be32(stat.mtime.tv_nsec);
        }
        if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) {
+               struct kstat parent_stat;
+               u64 ino = stat.ino;
+
                p = xdr_reserve_space(xdr, 8);
                if (!p)
                        goto out_resource;
@@ -2708,9 +2721,13 @@ out_acl:
                 * and this is the root of a cross-mounted filesystem.
                 */
                if (ignore_crossmnt == 0 &&
-                   dentry == exp->ex_path.mnt->mnt_root)
-                       get_parent_attributes(exp, &stat);
-               p = xdr_encode_hyper(p, stat.ino);
+                   dentry == exp->ex_path.mnt->mnt_root) {
+                       err = get_parent_attributes(exp, &parent_stat);
+                       if (err)
+                               goto out_nfserr;
+                       ino = parent_stat.ino;
+               }
+               p = xdr_encode_hyper(p, ino);
        }
 #ifdef CONFIG_NFSD_PNFS
        if (bmval1 & FATTR4_WORD1_FS_LAYOUT_TYPES) {
@@ -2732,21 +2749,20 @@ out_acl:
                *p++ = cpu_to_be32(stat.blksize);
        }
 #endif /* CONFIG_NFSD_PNFS */
+       if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) {
+               status = nfsd4_encode_bitmap(xdr, NFSD_SUPPATTR_EXCLCREAT_WORD0,
+                                                 NFSD_SUPPATTR_EXCLCREAT_WORD1,
+                                                 NFSD_SUPPATTR_EXCLCREAT_WORD2);
+               if (status)
+                       goto out;
+       }
+
        if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) {
                status = nfsd4_encode_security_label(xdr, rqstp, context,
                                                                contextlen);
                if (status)
                        goto out;
        }
-       if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) {
-               p = xdr_reserve_space(xdr, 16);
-               if (!p)
-                       goto out_resource;
-               *p++ = cpu_to_be32(3);
-               *p++ = cpu_to_be32(NFSD_SUPPATTR_EXCLCREAT_WORD0);
-               *p++ = cpu_to_be32(NFSD_SUPPATTR_EXCLCREAT_WORD1);
-               *p++ = cpu_to_be32(NFSD_SUPPATTR_EXCLCREAT_WORD2);
-       }
 
        attrlen = htonl(xdr->buf->len - attrlen_offset - 4);
        write_bytes_to_xdr_buf(xdr->buf, attrlen_offset, &attrlen, 4);
@@ -3065,13 +3081,12 @@ nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
        __be32 *p;
 
        if (!nfserr) {
-               p = xdr_reserve_space(xdr, 32);
+               p = xdr_reserve_space(xdr, 20);
                if (!p)
                        return nfserr_resource;
-               p = encode_cinfo(p, &create->cr_cinfo);
-               *p++ = cpu_to_be32(2);
-               *p++ = cpu_to_be32(create->cr_bmval[0]);
-               *p++ = cpu_to_be32(create->cr_bmval[1]);
+               encode_cinfo(p, &create->cr_cinfo);
+               nfserr = nfsd4_encode_bitmap(xdr, create->cr_bmval[0],
+                               create->cr_bmval[1], create->cr_bmval[2]);
        }
        return nfserr;
 }
@@ -3211,16 +3226,22 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op
        nfserr = nfsd4_encode_stateid(xdr, &open->op_stateid);
        if (nfserr)
                goto out;
-       p = xdr_reserve_space(xdr, 40);
+       p = xdr_reserve_space(xdr, 24);
        if (!p)
                return nfserr_resource;
        p = encode_cinfo(p, &open->op_cinfo);
        *p++ = cpu_to_be32(open->op_rflags);
-       *p++ = cpu_to_be32(2);
-       *p++ = cpu_to_be32(open->op_bmval[0]);
-       *p++ = cpu_to_be32(open->op_bmval[1]);
-       *p++ = cpu_to_be32(open->op_delegate_type);
 
+       nfserr = nfsd4_encode_bitmap(xdr, open->op_bmval[0], open->op_bmval[1],
+                                       open->op_bmval[2]);
+       if (nfserr)
+               goto out;
+
+       p = xdr_reserve_space(xdr, 4);
+       if (!p)
+               return nfserr_resource;
+
+       *p++ = cpu_to_be32(open->op_delegate_type);
        switch (open->op_delegate_type) {
        case NFS4_OPEN_DELEGATE_NONE:
                break;
@@ -3440,52 +3461,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