diff options
Diffstat (limited to 'kernel/fs/nfsd/nfs4xdr.c')
-rw-r--r-- | kernel/fs/nfsd/nfs4xdr.c | 188 |
1 files changed, 104 insertions, 84 deletions
diff --git a/kernel/fs/nfsd/nfs4xdr.c b/kernel/fs/nfsd/nfs4xdr.c index 3dd1b616b..51c9e9ca3 100644 --- a/kernel/fs/nfsd/nfs4xdr.c +++ b/kernel/fs/nfsd/nfs4xdr.c @@ -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 |