aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs4xdr.c
diff options
context:
space:
mode:
authorFrank Filz <ffilzlnx@us.ibm.com>2007-11-27 14:34:05 -0500
committerJ. Bruce Fields <bfields@citi.umich.edu>2008-02-01 16:42:06 -0500
commit406a7ea97d9dc1a9348ba92c4cd0e7c678185c4c (patch)
treebf3d7e7fe94343aad6a57a60917ebecfa64376e7 /fs/nfsd/nfs4xdr.c
parent39325bd03fc16d903f1e0f51104436d939899c8c (diff)
nfsd: Allow AIX client to read dir containing mountpoints
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. Signed-off-by: Frank Filz <ffilzlnx@us.ibm.com> Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Diffstat (limited to 'fs/nfsd/nfs4xdr.c')
-rw-r--r--fs/nfsd/nfs4xdr.c27
1 files changed, 22 insertions, 5 deletions
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index bf1e792a65a0..b0592e7c378d 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1453,7 +1453,7 @@ static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err)
1453__be32 1453__be32
1454nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, 1454nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
1455 struct dentry *dentry, __be32 *buffer, int *countp, u32 *bmval, 1455 struct dentry *dentry, __be32 *buffer, int *countp, u32 *bmval,
1456 struct svc_rqst *rqstp) 1456 struct svc_rqst *rqstp, int ignore_crossmnt)
1457{ 1457{
1458 u32 bmval0 = bmval[0]; 1458 u32 bmval0 = bmval[0];
1459 u32 bmval1 = bmval[1]; 1459 u32 bmval1 = bmval[1];
@@ -1833,7 +1833,12 @@ out_acl:
1833 if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) { 1833 if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) {
1834 if ((buflen -= 8) < 0) 1834 if ((buflen -= 8) < 0)
1835 goto out_resource; 1835 goto out_resource;
1836 if (exp->ex_mnt->mnt_root->d_inode == dentry->d_inode) { 1836 /*
1837 * Get parent's attributes if not ignoring crossmount
1838 * and this is the root of a cross-mounted filesystem.
1839 */
1840 if (ignore_crossmnt == 0 &&
1841 exp->ex_mnt->mnt_root->d_inode == dentry->d_inode) {
1837 err = vfs_getattr(exp->ex_mnt->mnt_parent, 1842 err = vfs_getattr(exp->ex_mnt->mnt_parent,
1838 exp->ex_mnt->mnt_mountpoint, &stat); 1843 exp->ex_mnt->mnt_mountpoint, &stat);
1839 if (err) 1844 if (err)
@@ -1869,13 +1874,25 @@ nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
1869 struct svc_export *exp = cd->rd_fhp->fh_export; 1874 struct svc_export *exp = cd->rd_fhp->fh_export;
1870 struct dentry *dentry; 1875 struct dentry *dentry;
1871 __be32 nfserr; 1876 __be32 nfserr;
1877 int ignore_crossmnt = 0;
1872 1878
1873 dentry = lookup_one_len(name, cd->rd_fhp->fh_dentry, namlen); 1879 dentry = lookup_one_len(name, cd->rd_fhp->fh_dentry, namlen);
1874 if (IS_ERR(dentry)) 1880 if (IS_ERR(dentry))
1875 return nfserrno(PTR_ERR(dentry)); 1881 return nfserrno(PTR_ERR(dentry));
1876 1882
1877 exp_get(exp); 1883 exp_get(exp);
1878 if (d_mountpoint(dentry)) { 1884 /*
1885 * In the case of a mountpoint, the client may be asking for
1886 * attributes that are only properties of the underlying filesystem
1887 * as opposed to the cross-mounted file system. In such a case,
1888 * we will not follow the cross mount and will fill the attribtutes
1889 * directly from the mountpoint dentry.
1890 */
1891 if (d_mountpoint(dentry) &&
1892 (cd->rd_bmval[0] & ~FATTR4_WORD0_RDATTR_ERROR) == 0 &&
1893 (cd->rd_bmval[1] & ~FATTR4_WORD1_MOUNTED_ON_FILEID) == 0)
1894 ignore_crossmnt = 1;
1895 else if (d_mountpoint(dentry)) {
1879 int err; 1896 int err;
1880 1897
1881 /* 1898 /*
@@ -1894,7 +1911,7 @@ nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
1894 1911
1895 } 1912 }
1896 nfserr = nfsd4_encode_fattr(NULL, exp, dentry, p, buflen, cd->rd_bmval, 1913 nfserr = nfsd4_encode_fattr(NULL, exp, dentry, p, buflen, cd->rd_bmval,
1897 cd->rd_rqstp); 1914 cd->rd_rqstp, ignore_crossmnt);
1898out_put: 1915out_put:
1899 dput(dentry); 1916 dput(dentry);
1900 exp_put(exp); 1917 exp_put(exp);
@@ -2048,7 +2065,7 @@ nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
2048 buflen = resp->end - resp->p - (COMPOUND_ERR_SLACK_SPACE >> 2); 2065 buflen = resp->end - resp->p - (COMPOUND_ERR_SLACK_SPACE >> 2);
2049 nfserr = nfsd4_encode_fattr(fhp, fhp->fh_export, fhp->fh_dentry, 2066 nfserr = nfsd4_encode_fattr(fhp, fhp->fh_export, fhp->fh_dentry,
2050 resp->p, &buflen, getattr->ga_bmval, 2067 resp->p, &buflen, getattr->ga_bmval,
2051 resp->rqstp); 2068 resp->rqstp, 0);
2052 if (!nfserr) 2069 if (!nfserr)
2053 resp->p += buflen; 2070 resp->p += buflen;
2054 return nfserr; 2071 return nfserr;