X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fnfsd%2Fnfs4xdr.c;h=091114daf8164e3aaca3c33ab2d6c955a9103e9d;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=b98b5fe49efce355a135b525d7dd6fee1bf4148c;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index b98b5fe49..091114daf 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -55,6 +55,9 @@ #include #include #include +#include +#include +#include #define NFSDDBG_FACILITY NFSDDBG_XDR @@ -287,27 +290,40 @@ u32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes) return p; } -char *savemem(struct nfsd4_compoundargs *argp, u32 *p, int nbytes) +static int +defer_free(struct nfsd4_compoundargs *argp, + void (*release)(const void *), void *p) { struct tmpbuf *tb; + + tb = kmalloc(sizeof(*tb), GFP_KERNEL); + if (!tb) + return -ENOMEM; + tb->buf = p; + tb->release = release; + tb->next = argp->to_free; + argp->to_free = tb; + return 0; +} + +char *savemem(struct nfsd4_compoundargs *argp, u32 *p, int nbytes) +{ + void *new = NULL; if (p == argp->tmp) { - p = kmalloc(nbytes, GFP_KERNEL); - if (!p) return NULL; + new = kmalloc(nbytes, GFP_KERNEL); + if (!new) return NULL; + p = new; memcpy(p, argp->tmp, nbytes); } else { if (p != argp->tmpp) BUG(); argp->tmpp = NULL; } - tb = kmalloc(sizeof(*tb), GFP_KERNEL); - if (!tb) { - kfree(p); + if (defer_free(argp, kfree, p)) { + kfree(new); return NULL; - } - tb->buf = p; - tb->next = argp->to_free; - argp->to_free = tb; - return (char*)p; + } else + return (char *)p; } @@ -335,7 +351,8 @@ nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval) } static int -nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *iattr) +nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *iattr, + struct nfs4_acl **acl) { int expected_len, len = 0; u32 dummy32; @@ -364,6 +381,51 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *ia READ64(iattr->ia_size); iattr->ia_valid |= ATTR_SIZE; } + if (bmval[0] & FATTR4_WORD0_ACL) { + int nace, i; + struct nfs4_ace ace; + + READ_BUF(4); len += 4; + READ32(nace); + + *acl = nfs4_acl_new(); + if (*acl == NULL) { + status = -ENOMEM; + goto out_nfserr; + } + defer_free(argp, (void (*)(const void *))nfs4_acl_free, *acl); + + for (i = 0; i < nace; i++) { + READ_BUF(16); len += 16; + READ32(ace.type); + READ32(ace.flag); + READ32(ace.access_mask); + READ32(dummy32); + READ_BUF(dummy32); + len += XDR_QUADLEN(dummy32) << 2; + READMEM(buf, dummy32); + if (check_utf8(buf, dummy32)) + return nfserr_inval; + ace.whotype = nfs4_acl_get_whotype(buf, dummy32); + status = 0; + if (ace.whotype != NFS4_ACL_WHO_NAMED) + ace.who = 0; + else if (ace.flag & NFS4_ACE_IDENTIFIER_GROUP) + status = nfsd_map_name_to_gid(argp->rqstp, + buf, dummy32, &ace.who); + else + status = nfsd_map_name_to_uid(argp->rqstp, + buf, dummy32, &ace.who); + if (status) + goto out_nfserr; + if (nfs4_acl_add_ace(*acl, ace.type, ace.flag, + ace.access_mask, ace.whotype, ace.who) != 0) { + status = -ENOMEM; + goto out_nfserr; + } + } + } else + *acl = NULL; if (bmval[1] & FATTR4_WORD1_MODE) { READ_BUF(4); len += 4; @@ -484,14 +546,12 @@ nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access DECODE_TAIL; } -#define NFS4_STATE_NOT_LOCKED ((void *)-1) - static int nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close) { DECODE_HEAD; - close->cl_stateowner = NFS4_STATE_NOT_LOCKED; + close->cl_stateowner = NULL; READ_BUF(4 + sizeof(stateid_t)); READ32(close->cl_seqid); READ32(close->cl_stateid.si_generation); @@ -538,9 +598,8 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create case NF4SOCK: case NF4FIFO: case NF4DIR: - break; default: - goto xdr_error; + break; } READ_BUF(4); @@ -550,12 +609,24 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create if ((status = check_filename(create->cr_name, create->cr_namelen, nfserr_inval))) return status; - if ((status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr))) + if ((status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr, &create->cr_acl))) goto out; DECODE_TAIL; } +static inline int +nfsd4_decode_delegreturn(struct nfsd4_compoundargs *argp, struct nfsd4_delegreturn *dr) +{ + DECODE_HEAD; + + READ_BUF(sizeof(stateid_t)); + READ32(dr->dr_stateid.si_generation); + COPYMEM(&dr->dr_stateid.si_opaque, sizeof(stateid_opaque_t)); + + DECODE_TAIL; +} + static inline int nfsd4_decode_getattr(struct nfsd4_compoundargs *argp, struct nfsd4_getattr *getattr) { @@ -582,7 +653,7 @@ nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock) { DECODE_HEAD; - lock->lk_stateowner = NFS4_STATE_NOT_LOCKED; + lock->lk_stateowner = NULL; /* * type, reclaim(boolean), offset, length, new_lock_owner(boolean) */ @@ -640,7 +711,7 @@ nfsd4_decode_locku(struct nfsd4_compoundargs *argp, struct nfsd4_locku *locku) { DECODE_HEAD; - locku->lu_stateowner = NFS4_STATE_NOT_LOCKED; + locku->lu_stateowner = NULL; READ_BUF(24 + sizeof(stateid_t)); READ32(locku->lu_type); if ((locku->lu_type < NFS4_READ_LT) || (locku->lu_type > NFS4_WRITEW_LT)) @@ -676,7 +747,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) memset(open->op_bmval, 0, sizeof(open->op_bmval)); open->op_iattr.ia_valid = 0; - open->op_stateowner = NFS4_STATE_NOT_LOCKED; + open->op_stateowner = NULL; /* seqid, share_access, share_deny, clientid, ownerlen */ READ_BUF(16 + sizeof(clientid_t)); @@ -699,7 +770,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) switch (open->op_createmode) { case NFS4_CREATE_UNCHECKED: case NFS4_CREATE_GUARDED: - if ((status = nfsd4_decode_fattr(argp, open->op_bmval, &open->op_iattr))) + if ((status = nfsd4_decode_fattr(argp, open->op_bmval, &open->op_iattr, &open->op_acl))) goto out; break; case NFS4_CREATE_EXCLUSIVE: @@ -732,8 +803,8 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) READ32(open->op_delegate_type); break; case NFS4_OPEN_CLAIM_DELEGATE_CUR: - READ_BUF(sizeof(delegation_stateid_t) + 4); - COPYMEM(&open->op_delegate_stateid, sizeof(delegation_stateid_t)); + READ_BUF(sizeof(stateid_t) + 4); + COPYMEM(&open->op_delegate_stateid, sizeof(stateid_t)); READ32(open->op_fname.len); READ_BUF(open->op_fname.len); SAVEMEM(open->op_fname.data, open->op_fname.len); @@ -752,7 +823,7 @@ nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_con { DECODE_HEAD; - open_conf->oc_stateowner = NFS4_STATE_NOT_LOCKED; + open_conf->oc_stateowner = NULL; READ_BUF(4 + sizeof(stateid_t)); READ32(open_conf->oc_req_stateid.si_generation); COPYMEM(&open_conf->oc_req_stateid.si_opaque, sizeof(stateid_opaque_t)); @@ -766,8 +837,8 @@ nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp, struct nfsd4_open_d { DECODE_HEAD; - open_down->od_stateowner = NFS4_STATE_NOT_LOCKED; - READ_BUF(4 + sizeof(stateid_t)); + open_down->od_stateowner = NULL; + READ_BUF(12 + sizeof(stateid_t)); READ32(open_down->od_stateid.si_generation); COPYMEM(&open_down->od_stateid.si_opaque, sizeof(stateid_opaque_t)); READ32(open_down->od_seqid); @@ -876,7 +947,7 @@ nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *seta READ_BUF(sizeof(stateid_t)); READ32(setattr->sa_stateid.si_generation); COPYMEM(&setattr->sa_stateid.si_opaque, sizeof(stateid_opaque_t)); - if ((status = nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr))) + if ((status = nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr, &setattr->sa_acl))) goto out; DECODE_TAIL; @@ -1112,6 +1183,9 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) case OP_CREATE: op->status = nfsd4_decode_create(argp, &op->u.create); break; + case OP_DELEGRETURN: + op->status = nfsd4_decode_delegreturn(argp, &op->u.delegreturn); + break; case OP_GETATTR: op->status = nfsd4_decode_getattr(argp, &op->u.getattr); break; @@ -1267,8 +1341,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) */ #define ENCODE_SEQID_OP_TAIL(stateowner) do { \ - if (seqid_mutating_err(nfserr) && stateowner \ - && (stateowner != NFS4_STATE_NOT_LOCKED)) { \ + if (seqid_mutating_err(nfserr) && stateowner) { \ if (stateowner->so_confirmed) \ stateowner->so_seqid++; \ stateowner->so_replay.rp_status = nfserr; \ @@ -1276,10 +1349,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) (((char *)(resp)->p - (char *)save)); \ memcpy(stateowner->so_replay.rp_buf, save, \ stateowner->so_replay.rp_buflen); \ - } \ - if (stateowner != NFS4_STATE_NOT_LOCKED) \ - nfs4_unlock_state(); \ - } while (0); + } } while (0); static u32 nfs4_ftypes[16] = { @@ -1289,6 +1359,48 @@ static u32 nfs4_ftypes[16] = { NF4SOCK, NF4BAD, NF4LNK, NF4BAD, }; +static int +nfsd4_encode_name(struct svc_rqst *rqstp, int whotype, uid_t id, int group, + u32 **p, int *buflen) +{ + int status; + + if (*buflen < (XDR_QUADLEN(IDMAP_NAMESZ) << 2) + 4) + return nfserr_resource; + if (whotype != NFS4_ACL_WHO_NAMED) + status = nfs4_acl_write_who(whotype, (u8 *)(*p + 1)); + else if (group) + status = nfsd_map_gid_to_name(rqstp, id, (u8 *)(*p + 1)); + else + status = nfsd_map_uid_to_name(rqstp, id, (u8 *)(*p + 1)); + if (status < 0) + return nfserrno(status); + *p = xdr_encode_opaque(*p, NULL, status); + *buflen -= (XDR_QUADLEN(status) << 2) + 4; + BUG_ON(*buflen < 0); + return 0; +} + +static inline int +nfsd4_encode_user(struct svc_rqst *rqstp, uid_t uid, u32 **p, int *buflen) +{ + return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, uid, 0, p, buflen); +} + +static inline int +nfsd4_encode_group(struct svc_rqst *rqstp, uid_t gid, u32 **p, int *buflen) +{ + return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, gid, 1, p, buflen); +} + +static inline int +nfsd4_encode_aclname(struct svc_rqst *rqstp, int whotype, uid_t id, int group, + u32 **p, int *buflen) +{ + return nfsd4_encode_name(rqstp, whotype, id, group, p, buflen); +} + + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -1304,10 +1416,6 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, u32 bmval0 = bmval[0]; u32 bmval1 = bmval[1]; struct kstat stat; - char owner[IDMAP_NAMESZ]; - u32 ownerlen = 0; - char group[IDMAP_NAMESZ]; - u32 grouplen = 0; struct svc_fh tempfh; struct kstatfs statfs; int buflen = *countp << 2; @@ -1316,6 +1424,8 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, u64 dummy64; u32 *p = buffer; int status; + int aclsupport = 0; + struct nfs4_acl *acl = NULL; BUG_ON(bmval1 & NFSD_WRITEONLY_ATTRS_WORD1); BUG_ON(bmval0 & ~NFSD_SUPPORTED_ATTRS_WORD0); @@ -1331,30 +1441,24 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, if (status) goto out_nfserr; } - if ((bmval0 & FATTR4_WORD0_FILEHANDLE) && !fhp) { + if ((bmval0 & (FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FSID)) && !fhp) { fh_init(&tempfh, NFS4_FHSIZE); status = fh_compose(&tempfh, exp, dentry, NULL); if (status) goto out; fhp = &tempfh; } - if (bmval1 & FATTR4_WORD1_OWNER) { - int temp = nfsd_map_uid_to_name(rqstp, stat.uid, owner); - if (temp < 0) { - status = temp; - goto out_nfserr; - } - ownerlen = (unsigned) temp; - } - if (bmval1 & FATTR4_WORD1_OWNER_GROUP) { - int temp = nfsd_map_gid_to_name(rqstp, stat.gid, group); - if (temp < 0) { - status = temp; - goto out_nfserr; + if (bmval0 & (FATTR4_WORD0_ACL | FATTR4_WORD0_ACLSUPPORT + | FATTR4_WORD0_SUPPORTED_ATTRS)) { + status = nfsd4_get_nfs4_acl(rqstp, dentry, &acl); + aclsupport = (status == 0); + if (bmval0 & FATTR4_WORD0_ACL) { + if (status == -EOPNOTSUPP) + bmval0 &= ~FATTR4_WORD0_ACL; + else if (status != 0) + goto out_nfserr; } - grouplen = (unsigned) temp; } - if ((buflen -= 16) < 0) goto out_resource; @@ -1367,7 +1471,9 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, if ((buflen -= 12) < 0) goto out_resource; WRITE32(2); - WRITE32(NFSD_SUPPORTED_ATTRS_WORD0); + WRITE32(aclsupport ? + NFSD_SUPPORTED_ATTRS_WORD0 : + NFSD_SUPPORTED_ATTRS_WORD0 & ~FATTR4_WORD0_ACL); WRITE32(NFSD_SUPPORTED_ATTRS_WORD1); } if (bmval0 & FATTR4_WORD0_TYPE) { @@ -1418,10 +1524,15 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, if (bmval0 & FATTR4_WORD0_FSID) { if ((buflen -= 16) < 0) goto out_resource; - WRITE32(0); - WRITE32(MAJOR(stat.dev)); - WRITE32(0); - WRITE32(MINOR(stat.dev)); + if (is_fsid(fhp, rqstp->rq_reffh)) { + WRITE64((u64)exp->ex_fsid); + WRITE64((u64)0); + } else { + WRITE32(0); + WRITE32(MAJOR(stat.dev)); + WRITE32(0); + WRITE32(MINOR(stat.dev)); + } } if (bmval0 & FATTR4_WORD0_UNIQUE_HANDLES) { if ((buflen -= 4) < 0) @@ -1438,10 +1549,44 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, goto out_resource; WRITE32(0); } + if (bmval0 & FATTR4_WORD0_ACL) { + struct nfs4_ace *ace; + struct list_head *h; + + if (acl == NULL) { + if ((buflen -= 4) < 0) + goto out_resource; + + WRITE32(0); + goto out_acl; + } + if ((buflen -= 4) < 0) + goto out_resource; + WRITE32(acl->naces); + + list_for_each(h, &acl->ace_head) { + ace = list_entry(h, struct nfs4_ace, l_ace); + + if ((buflen -= 4*3) < 0) + goto out_resource; + WRITE32(ace->type); + WRITE32(ace->flag); + WRITE32(ace->access_mask & NFS4_ACE_MASK_ALL); + status = nfsd4_encode_aclname(rqstp, ace->whotype, + ace->who, ace->flag & NFS4_ACE_IDENTIFIER_GROUP, + &p, &buflen); + if (status == nfserr_resource) + goto out_resource; + if (status) + goto out; + } + } +out_acl: if (bmval0 & FATTR4_WORD0_ACLSUPPORT) { if ((buflen -= 4) < 0) goto out_resource; - WRITE32(0); + WRITE32(aclsupport ? + ACL4_SUPPORT_ALLOW_ACL|ACL4_SUPPORT_DENY_ACL : 0); } if (bmval0 & FATTR4_WORD0_CANSETTIME) { if ((buflen -= 4) < 0) @@ -1536,18 +1681,22 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, WRITE32(stat.nlink); } if (bmval1 & FATTR4_WORD1_OWNER) { - buflen -= (XDR_QUADLEN(ownerlen) << 2) + 4; - if (buflen < 0) + status = nfsd4_encode_user(rqstp, + XIDINO_UID(XID_TAG(dentry->d_inode), + stat.uid, stat.xid), &p, &buflen); + if (status == nfserr_resource) goto out_resource; - WRITE32(ownerlen); - WRITEMEM(owner, ownerlen); + if (status) + goto out; } if (bmval1 & FATTR4_WORD1_OWNER_GROUP) { - buflen -= (XDR_QUADLEN(grouplen) << 2) + 4; - if (buflen < 0) + status = nfsd4_encode_group(rqstp, + XIDINO_GID(XID_TAG(dentry->d_inode), + stat.gid, stat.xid), &p, &buflen); + if (status == nfserr_resource) goto out_resource; - WRITE32(grouplen); - WRITEMEM(group, grouplen); + if (status) + goto out; } if (bmval1 & FATTR4_WORD1_RAWDEV) { if ((buflen -= 8) < 0) @@ -1624,6 +1773,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, status = nfs_ok; out: + nfs4_acl_free(acl); if (fhp == &tempfh) fh_put(&tempfh); return status; @@ -1639,6 +1789,58 @@ out_serverfault: goto out; } +static int +nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd, + const char *name, int namlen, u32 *p, int *buflen) +{ + struct svc_export *exp = cd->rd_fhp->fh_export; + struct dentry *dentry; + int nfserr; + + dentry = lookup_one_len(name, cd->rd_fhp->fh_dentry, namlen); + if (IS_ERR(dentry)) + return nfserrno(PTR_ERR(dentry)); + + exp_get(exp); + if (d_mountpoint(dentry)) { + if (nfsd_cross_mnt(cd->rd_rqstp, &dentry, &exp)) { + /* + * -EAGAIN is the only error returned from + * nfsd_cross_mnt() and it indicates that an + * up-call has been initiated to fill in the export + * options on exp. When the answer comes back, + * this call will be retried. + */ + nfserr = nfserr_dropit; + goto out_put; + } + + } + nfserr = nfsd4_encode_fattr(NULL, exp, dentry, p, buflen, cd->rd_bmval, + cd->rd_rqstp); +out_put: + dput(dentry); + exp_put(exp); + return nfserr; +} + +static u32 * +nfsd4_encode_rdattr_error(u32 *p, int buflen, int nfserr) +{ + u32 *attrlenp; + + if (buflen < 6) + return NULL; + *p++ = htonl(2); + *p++ = htonl(FATTR4_WORD0_RDATTR_ERROR); /* bmval0 */ + *p++ = htonl(0); /* bmval1 */ + + attrlenp = p++; + *p++ = nfserr; /* no htonl */ + *attrlenp = htonl((char *)p - (char *)attrlenp - 4); + return p; +} + static int nfsd4_encode_dirent(struct readdir_cd *ccd, const char *name, int namlen, loff_t offset, ino_t ino, unsigned int d_type) @@ -1646,11 +1848,7 @@ nfsd4_encode_dirent(struct readdir_cd *ccd, const char *name, int namlen, struct nfsd4_readdir *cd = container_of(ccd, struct nfsd4_readdir, common); int buflen; u32 *p = cd->buffer; - u32 *attrlenp; - struct dentry *dentry; - struct svc_export *exp = cd->rd_fhp->fh_export; - u32 bmval0, bmval1; - int nfserr = 0; + int nfserr = nfserr_toosmall; /* In nfsv4, "." and ".." never make it onto the wire.. */ if (name && isdotent(name, namlen)) { @@ -1663,102 +1861,44 @@ nfsd4_encode_dirent(struct readdir_cd *ccd, const char *name, int namlen, buflen = cd->buflen - 4 - XDR_QUADLEN(namlen); if (buflen < 0) - goto nospc; + goto fail; *p++ = xdr_one; /* mark entry present */ cd->offset = p; /* remember pointer */ p = xdr_encode_hyper(p, NFS_OFFSET_MAX); /* offset of next entry */ p = xdr_encode_array(p, name, namlen); /* name length & name */ - /* - * Now we come to the ugly part: writing the fattr for this entry. - */ - bmval0 = cd->rd_bmval[0]; - bmval1 = cd->rd_bmval[1]; - if ((bmval0 & ~(FATTR4_WORD0_RDATTR_ERROR | FATTR4_WORD0_FILEID)) || bmval1) { - /* - * "Heavyweight" case: we have no choice except to - * call nfsd4_encode_fattr(). - */ - dentry = lookup_one_len(name, cd->rd_fhp->fh_dentry, namlen); - if (IS_ERR(dentry)) { - nfserr = nfserrno(PTR_ERR(dentry)); - goto error; - } - - if (d_mountpoint(dentry)) { - if ((nfserr = nfsd_cross_mnt(cd->rd_rqstp, &dentry, - &exp))) { - /* - * -EAGAIN is the only error returned from - * nfsd_cross_mnt() and it indicates that an - * up-call has been initiated to fill in the export - * options on exp. When the answer comes back, - * this call will be retried. - */ - dput(dentry); - nfserr = nfserr_dropit; - goto error; - } - - } - - nfserr = nfsd4_encode_fattr(NULL, exp, - dentry, p, &buflen, cd->rd_bmval, - cd->rd_rqstp); - if (!nfserr) { - p += buflen; - goto out; - } - if (nfserr == nfserr_resource) - goto nospc; - -error: + nfserr = nfsd4_encode_dirent_fattr(cd, name, namlen, p, &buflen); + switch (nfserr) { + case nfs_ok: + p += buflen; + break; + case nfserr_resource: + nfserr = nfserr_toosmall; + goto fail; + case nfserr_dropit: + goto fail; + default: /* - * If we get here, we experienced a miscellaneous - * failure while writing the attributes. If the - * client requested the RDATTR_ERROR attribute, + * If the client requested the RDATTR_ERROR attribute, * we stuff the error code into this attribute * and continue. If this attribute was not requested, * then in accordance with the spec, we fail the * entire READDIR operation(!) */ - if (!(bmval0 & FATTR4_WORD0_RDATTR_ERROR)) { - cd->common.err = nfserr; - return -EINVAL; - } - - bmval0 = FATTR4_WORD0_RDATTR_ERROR; - bmval1 = 0; - /* falling through here will do the right thing... */ + if (!(cd->rd_bmval[0] & FATTR4_WORD0_RDATTR_ERROR)) + goto fail; + nfserr = nfserr_toosmall; + p = nfsd4_encode_rdattr_error(p, buflen, nfserr); + if (p == NULL) + goto fail; } - - /* - * In the common "lightweight" case, we avoid - * the overhead of nfsd4_encode_fattr() by assembling - * a small fattr by hand. - */ - if (buflen < 6) - goto nospc; - *p++ = htonl(2); - *p++ = htonl(bmval0); - *p++ = htonl(bmval1); - - attrlenp = p++; - if (bmval0 & FATTR4_WORD0_RDATTR_ERROR) - *p++ = nfserr; /* no htonl */ - if (bmval0 & FATTR4_WORD0_FILEID) - p = xdr_encode_hyper(p, (u64)ino); - *attrlenp = htonl((char *)p - (char *)attrlenp - 4); - -out: cd->buflen -= (p - cd->buffer); cd->buffer = p; cd->common.err = nfs_ok; return 0; - -nospc: - cd->common.err = nfserr_toosmall; +fail: + cd->common.err = nfserr; return -EINVAL; } @@ -1860,13 +2000,19 @@ nfsd4_encode_lock_denied(struct nfsd4_compoundres *resp, struct nfsd4_lock_denie { ENCODE_HEAD; - RESERVE_SPACE(32 + XDR_LEN(ld->ld_sop->so_owner.len)); + RESERVE_SPACE(32 + XDR_LEN(ld->ld_sop ? ld->ld_sop->so_owner.len : 0)); WRITE64(ld->ld_start); WRITE64(ld->ld_length); WRITE32(ld->ld_type); - WRITEMEM(&ld->ld_sop->so_client->cl_clientid, 8); - WRITE32(ld->ld_sop->so_owner.len); - WRITEMEM(ld->ld_sop->so_owner.data, ld->ld_sop->so_owner.len); + if (ld->ld_sop) { + WRITEMEM(&ld->ld_clientid, 8); + WRITE32(ld->ld_sop->so_owner.len); + WRITEMEM(ld->ld_sop->so_owner.data, ld->ld_sop->so_owner.len); + kref_put(&ld->ld_sop->so_ref, nfs4_free_stateowner); + } else { /* non - nfsv4 lock in conflict, no clientid nor owner */ + WRITE64((u64)0); /* clientid */ + WRITE32(0); /* length of owner name */ + } ADJUST_ARGS(); } @@ -1946,8 +2092,8 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_open case NFS4_OPEN_DELEGATE_NONE: break; case NFS4_OPEN_DELEGATE_READ: - RESERVE_SPACE(20 + sizeof(delegation_stateid_t)); - WRITEMEM(&open->op_delegate_stateid, sizeof(delegation_stateid_t)); + RESERVE_SPACE(20 + sizeof(stateid_t)); + WRITEMEM(&open->op_delegate_stateid, sizeof(stateid_t)); WRITE32(0); /* @@ -1960,8 +2106,8 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_open ADJUST_ARGS(); break; case NFS4_OPEN_DELEGATE_WRITE: - RESERVE_SPACE(32 + sizeof(delegation_stateid_t)); - WRITEMEM(&open->op_delegate_stateid, sizeof(delegation_stateid_t)); + RESERVE_SPACE(32 + sizeof(stateid_t)); + WRITEMEM(&open->op_delegate_stateid, sizeof(stateid_t)); WRITE32(0); /* @@ -2325,6 +2471,8 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) case OP_CREATE: nfsd4_encode_create(resp, op->status, &op->u.create); break; + case OP_DELEGRETURN: + break; case OP_GETATTR: op->status = nfsd4_encode_getattr(resp, op->status, &op->u.getattr); break; @@ -2433,7 +2581,6 @@ nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op) RESERVE_SPACE(rp->rp_buflen); WRITEMEM(rp->rp_buf, rp->rp_buflen); ADJUST_ARGS(); - nfs4_unlock_state(); } /* @@ -2446,6 +2593,24 @@ nfs4svc_encode_voidres(struct svc_rqst *rqstp, u32 *p, void *dummy) return xdr_ressize_check(rqstp, p); } +void nfsd4_release_compoundargs(struct nfsd4_compoundargs *args) +{ + if (args->ops != args->iops) { + kfree(args->ops); + args->ops = args->iops; + } + if (args->tmpp) { + kfree(args->tmpp); + args->tmpp = NULL; + } + while (args->to_free) { + struct tmpbuf *tb = args->to_free; + args->to_free = tb->next; + tb->release(tb->buf); + kfree(tb); + } +} + int nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, u32 *p, struct nfsd4_compoundargs *args) { @@ -2462,20 +2627,7 @@ nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, u32 *p, struct nfsd4_compoun status = nfsd4_decode_compound(args); if (status) { - if (args->ops != args->iops) { - kfree(args->ops); - args->ops = args->iops; - } - if (args->tmpp) { - kfree(args->tmpp); - args->tmpp = NULL; - } - while (args->to_free) { - struct tmpbuf *tb = args->to_free; - args->to_free = tb->next; - kfree(tb->buf); - kfree(tb); - } + nfsd4_release_compoundargs(args); } return !status; } @@ -2486,7 +2638,7 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, u32 *p, struct nfsd4_compound /* * All that remains is to write the tag and operation count... */ - struct iovec *iov; + struct kvec *iov; p = resp->tagp; *p++ = htonl(resp->taglen); memcpy(p, resp->tag, resp->taglen);