On Mon, Nov 26, 2007 at 01:19:11PM -0800, Frank Filz wrote:
> This patch addresses a compatibility issue with a Linux NFS server and
> AIX NFS client.
>
> I have exported /export as fsid=0 with sec=krb5:krb5i
> I have mount --bind /home onto /export/home
> I have exported /export/home with sec=krb5i
>
> The AIX client mounts / -o sec=krb5:krb5i onto /mnt
>
> If I do an ls /mnt, the AIX client gets a permission error. Looking at
> the network traceIwe see a READDIR looking for attributes
> FATTR4_RDATTR_ERROR and FATTR4_MOUNTED_ON_FILEID. The response gives a
> NFS4ERR_WRONGSEC which the AIX client is not expecting.
>
> Since the AIX client is only asking for an attribute that is an
> attribute of the parent file system (pseudo root in my example), it
> seems reasonable that there should not be an error.
>
> In discussing this issue with Bruce Fields, I initially proposed
> ignoring the error in nfsd4_encode_dirent_fattr() if all that was being
> asked for was FATTR4_RDATTR_ERROR and FATTR4_MOUNTED_ON_FILEID, however,
> Bruce suggested that we avoid calling cross_mnt() if only these
> attributes are requested.
>
> The following patch implements bypassing cross_mnt() if only
> FATTR4_RDATTR_ERROR and FATTR4_MOUNTED_ON_FILEID are called. Since there
> is some complexity in the code in nfsd4_encode_fattr(), I didn't want to
> duplicate code (and introduce a maintenance nightmare), so I added a
> parameter to nfsd4_encode_fattr() that indicates whether it should
> ignore cross mounts and simply fill in the attribute using the passed in
> dentry as opposed to it's parent.
OK, thanks! My only superficial complaint--I find the
OBEY_CROSSMNT/IGNORE_CROSSMNT defines to be minor overkill.
If you want to stick with them, then you should probably use a
comparison to IGNORE_CROSSMNT here instead of assuming which is zero:
> + if (!ignore_crossmnt &&
> + exp->ex_mnt->mnt_root->d_inode == dentry->d_inode) {
> err = vfs_getattr(exp->ex_mnt->mnt_parent,
> exp->ex_mnt->mnt_mountpoint, &stat);
But I think it'd be simplest just to use 0 and 1 directly instead of the
defines.
--b.
>
> Signed-off-by: Frank Filz <[EMAIL PROTECTED]>
>
> fs/nfsd/nfs4proc.c | 2 +-
> fs/nfsd/nfs4xdr.c | 27 ++++++++++++++++++++++-----
> include/linux/nfsd/xdr4.h | 4 +++-
> 3 files changed, 26 insertions(+), 7 deletions(-)
>
> diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
> index 18ead17..39766e9 100644
> --- a/fs/nfsd/nfs4proc.c
> +++ b/fs/nfsd/nfs4proc.c
> @@ -750,7 +750,7 @@ _nfsd4_verify(struct svc_rqst *rqstp, struct
> nfsd4_compound_state *cstate,
> cstate->current_fh.fh_export,
> cstate->current_fh.fh_dentry, buf,
> &count, verify->ve_bmval,
> - rqstp);
> + rqstp, NFSD4_OBEY_CROSSMNT);
>
> /* this means that nfsd4_encode_fattr() ran out of space */
> if (status == nfserr_resource && count == 0)
> diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
> index 5733394..21ff4cf 100644
> --- a/fs/nfsd/nfs4xdr.c
> +++ b/fs/nfsd/nfs4xdr.c
> @@ -1448,7 +1448,7 @@ static __be32 fattr_handle_absent_fs(u32 *bmval0, u32
> *bmval1, u32 *rdattr_err)
> __be32
> nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
> struct dentry *dentry, __be32 *buffer, int *countp, u32 *bmval,
> - struct svc_rqst *rqstp)
> + struct svc_rqst *rqstp, int ignore_crossmnt)
> {
> u32 bmval0 = bmval[0];
> u32 bmval1 = bmval[1];
> @@ -1828,7 +1828,12 @@ out_acl:
> if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) {
> if ((buflen -= 8) < 0)
> goto out_resource;
> - if (exp->ex_mnt->mnt_root->d_inode == dentry->d_inode) {
> + /*
> + * Get parent's attributes if not ignoring crossmount
> + * and this is the root of a cross-mounted filesystem.
> + */
> + if (!ignore_crossmnt &&
> + exp->ex_mnt->mnt_root->d_inode == dentry->d_inode) {
> err = vfs_getattr(exp->ex_mnt->mnt_parent,
> exp->ex_mnt->mnt_mountpoint, &stat);
> if (err)
> @@ -1864,13 +1869,25 @@ nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
> struct svc_export *exp = cd->rd_fhp->fh_export;
> struct dentry *dentry;
> __be32 nfserr;
> + int ignore_crossmnt = NFSD4_OBEY_CROSSMNT;
>
> 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)) {
> + /*
> + * In the case of a mountpoint, the client may be asking for
> + * attributes that are only properties of the underlying filesystem
> + * as opposed to the cross-mounted file system. In such a case,
> + * we will not follow the cross mount and will fill the attribtutes
> + * directly from the mountpoint dentry.
> + */
> + if (d_mountpoint(dentry) &&
> + (cd->rd_bmval[0] & ~FATTR4_WORD0_RDATTR_ERROR) == 0 &&
> + (cd->rd_bmval[1] & ~FATTR4_WORD1_MOUNTED_ON_FILEID) == 0)
> + ignore_crossmnt = NFSD4_IGNORE_CROSSMNT;
> + else if (d_mountpoint(dentry)) {
> int err;
>
> /*
> @@ -1889,7 +1906,7 @@ nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
>
> }
> nfserr = nfsd4_encode_fattr(NULL, exp, dentry, p, buflen, cd->rd_bmval,
> - cd->rd_rqstp);
> + cd->rd_rqstp, ignore_crossmnt);
> out_put:
> dput(dentry);
> exp_put(exp);
> @@ -2043,7 +2060,7 @@ nfsd4_encode_getattr(struct nfsd4_compoundres *resp,
> __be32 nfserr, struct nfsd4
> buflen = resp->end - resp->p - (COMPOUND_ERR_SLACK_SPACE >> 2);
> nfserr = nfsd4_encode_fattr(fhp, fhp->fh_export, fhp->fh_dentry,
> resp->p, &buflen, getattr->ga_bmval,
> - resp->rqstp);
> + resp->rqstp, NFSD4_OBEY_CROSSMNT);
> if (!nfserr)
> resp->p += buflen;
> return nfserr;
> diff --git a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h
> index b0ddfb4..b660ebc 100644
> --- a/include/linux/nfsd/xdr4.h
> +++ b/include/linux/nfsd/xdr4.h
> @@ -43,6 +43,8 @@
>
> #define NFSD4_MAX_TAGLEN 128
> #define XDR_LEN(n) (((n) + 3) & ~3)
> +#define NFSD4_IGNORE_CROSSMNT 1
> +#define NFSD4_OBEY_CROSSMNT 0
>
> struct nfsd4_compound_state {
> struct svc_fh current_fh;
> @@ -441,7 +443,7 @@ void nfsd4_encode_operation(struct nfsd4_compoundres *,
> struct nfsd4_op *);
> void nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op
> *op);
> __be32 nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
> struct dentry *dentry, __be32 *buffer, int *countp,
> - u32 *bmval, struct svc_rqst *);
> + u32 *bmval, struct svc_rqst *, int ignore_crossmnt);
> extern __be32 nfsd4_setclientid(struct svc_rqst *rqstp,
> struct nfsd4_compound_state *,
> struct nfsd4_setclientid *setclid);
>
>
-
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html