X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fnfsd%2Fnfs4xdr.c;h=d35dfeec4aa6f68b6a5f1d07733cb685d2631f6c;hb=f7f1b0f1e2fbadeab12d24236000e778aa9b1ead;hp=e95b02a70ba96cb66031c6340cb82055dbfaad6f;hpb=9bf4aaab3e101692164d49b7ca357651eb691cb6;p=linux-2.6.git diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index e95b02a70..d35dfeec4 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -55,125 +55,12 @@ #include #include #include +#include +#include #include #define NFSDDBG_FACILITY NFSDDBG_XDR -static const char utf8_byte_len[256] = { - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, 4,4,4,4,4,4,4,4,5,5,5,5,6,6,0,0 -}; - -static inline int -is_legal_utf8_sequence(unsigned char *source, int length) -{ - unsigned char *ptr; - unsigned char c; - - if (length==1) return 1; - - /* Check for overlong sequence, and check second byte */ - c = *(source + 1); - switch (*source) { - case 0xE0: /* 3 bytes */ - if ( c < 0xA0 ) return 0; - break; - case 0xF0: /* 4 bytes */ - if ( c < 0x90 ) return 0; - break; - case 0xF8: /* 5 bytes */ - if ( c < 0xC8 ) return 0; - break; - case 0xFC: /* 6 bytes */ - if ( c < 0x84 ) return 0; - break; - default: - if ( (c & 0xC0) != 0x80) return 0; - } - - /* Check that trailing bytes look like 10xxxxxx */ - for (ptr = source++ + length - 1; ptr>source; ptr--) - if ( ((*ptr) & 0xC0) != 0x80 ) return 0; - return 1; -} - -/* This does some screening on disallowed unicode characters. It is NOT - * comprehensive. - */ -static int -is_allowed_utf8_char(unsigned char *source, int length) -{ - /* We assume length and source point to a valid utf8 sequence */ - unsigned char c; - - /* Disallow F0000 and up (in utf8, F3B08080) */ - if (*source > 0xF3 ) return 0; - c = *(source + 1); - switch (*source) { - case 0xF3: - if (c >= 0xB0) return 0; - break; - /* Disallow D800-F8FF (in utf8, EDA080-EFA3BF */ - case 0xED: - if (c >= 0xA0) return 0; - break; - case 0xEE: - return 0; - break; - case 0xEF: - if (c <= 0xA3) return 0; - /* Disallow FFF9-FFFF (EFBFB9-EFBFBF) */ - if (c==0xBF) - /* Don't need to check <=0xBF, since valid utf8 */ - if ( *(source+2) >= 0xB9) return 0; - break; - } - return 1; -} - -/* This routine should really check to see that the proper stringprep - * mappings have been applied. Instead, we do a simple screen of some - * of the more obvious illegal values by calling is_allowed_utf8_char. - * This will allow many illegal strings through, but if a client behaves, - * it will get full functionality. The other option (apart from full - * stringprep checking) is to limit everything to an easily handled subset, - * such as 7-bit ascii. - * - * Note - currently calling routines ignore return value except as boolean. - */ -static int -check_utf8(char *str, int len) -{ - unsigned char *chunk, *sourceend; - int chunklen; - - chunk = str; - sourceend = str + len; - - while (chunk < sourceend) { - chunklen = utf8_byte_len[*chunk]; - if (!chunklen) - return nfserr_inval; - if (chunk + chunklen > sourceend) - return nfserr_inval; - if (!is_legal_utf8_sequence(chunk, chunklen)) - return nfserr_inval; - if (!is_allowed_utf8_char(chunk, chunklen)) - return nfserr_inval; - if ( (chunklen==1) && (!*chunk) ) - return nfserr_inval; /* Disallow embedded nulls */ - chunk += chunklen; - } - - return 0; -} - static int check_filename(char *str, int len, int err) { @@ -186,7 +73,7 @@ check_filename(char *str, int len, int err) for (i = 0; i < len; i++) if (str[i] == '/') return err; - return check_utf8(str, len); + return 0; } /* @@ -349,7 +236,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; @@ -378,6 +266,49 @@ 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); + 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; @@ -392,8 +323,6 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *ia READ_BUF(dummy32); len += (XDR_QUADLEN(dummy32) << 2); READMEM(buf, dummy32); - if (check_utf8(buf, dummy32)) - return nfserr_inval; if ((status = nfsd_map_name_to_uid(argp->rqstp, buf, dummy32, &iattr->ia_uid))) goto out_nfserr; iattr->ia_valid |= ATTR_UID; @@ -405,8 +334,6 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *ia READ_BUF(dummy32); len += (XDR_QUADLEN(dummy32) << 2); READMEM(buf, dummy32); - if (check_utf8(buf, dummy32)) - return nfserr_inval; if ((status = nfsd_map_name_to_gid(argp->rqstp, buf, dummy32, &iattr->ia_gid))) goto out_nfserr; iattr->ia_valid |= ATTR_GID; @@ -498,14 +425,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); @@ -540,8 +465,6 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create READ32(create->cr_linklen); READ_BUF(create->cr_linklen); SAVEMEM(create->cr_linkname, create->cr_linklen); - if (check_utf8(create->cr_linkname, create->cr_linklen)) - return nfserr_inval; break; case NF4BLK: case NF4CHR: @@ -563,12 +486,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) { @@ -595,7 +530,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) */ @@ -653,7 +588,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)) @@ -689,7 +624,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)); @@ -712,7 +647,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: @@ -745,8 +680,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); @@ -765,7 +700,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)); @@ -779,8 +714,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); @@ -889,7 +824,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; @@ -1125,6 +1060,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; @@ -1280,8 +1218,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; \ @@ -1289,10 +1226,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] = { @@ -1303,14 +1237,16 @@ static u32 nfs4_ftypes[16] = { }; static int -nfsd4_encode_name(struct svc_rqst *rqstp, int group, uid_t id, +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 (group) + 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)); @@ -1325,13 +1261,20 @@ nfsd4_encode_name(struct svc_rqst *rqstp, int group, uid_t id, static inline int nfsd4_encode_user(struct svc_rqst *rqstp, uid_t uid, u32 **p, int *buflen) { - return nfsd4_encode_name(rqstp, uid, 0, p, 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, gid, 1, p, 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); } @@ -1358,6 +1301,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); @@ -1373,13 +1318,27 @@ 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 (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 == -EINVAL) { + status = nfserr_attrnotsupp; + goto out; + } else if (status != 0) + goto out_nfserr; + } + } if ((buflen -= 16) < 0) goto out_resource; @@ -1392,7 +1351,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) { @@ -1443,10 +1404,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) @@ -1463,10 +1429,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) @@ -1653,6 +1653,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; @@ -1668,6 +1669,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) @@ -1675,11 +1728,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)) { @@ -1692,106 +1741,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; - } - - exp_get(exp); - 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); - exp_put(exp); - nfserr = nfserr_dropit; - goto error; - } - - } - - nfserr = nfsd4_encode_fattr(NULL, exp, - dentry, p, &buflen, cd->rd_bmval, - cd->rd_rqstp); - dput(dentry); - exp_put(exp); - 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; } @@ -1893,13 +1880,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(); } @@ -1979,8 +1972,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); /* @@ -1993,8 +1986,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); /* @@ -2083,10 +2076,10 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_read } read->rd_vlen = v; - nfserr = nfsd_read(read->rd_rqstp, read->rd_fhp, - read->rd_offset, - read->rd_iov, read->rd_vlen, - &maxcount); + nfserr = nfsd_read(read->rd_rqstp, read->rd_fhp, read->rd_filp, + read->rd_offset, read->rd_iov, read->rd_vlen, + &maxcount); + if (nfserr == nfserr_symlink) nfserr = nfserr_inval; if (nfserr) @@ -2358,6 +2351,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; @@ -2466,7 +2461,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(); } /*