aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs4xdr.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd/nfs4xdr.c')
-rw-r--r--fs/nfsd/nfs4xdr.c36
1 files changed, 29 insertions, 7 deletions
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 57333944af7f..b0592e7c378d 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -148,12 +148,12 @@ xdr_error: \
148 } \ 148 } \
149} while (0) 149} while (0)
150 150
151static __be32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes) 151static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes)
152{ 152{
153 /* We want more bytes than seem to be available. 153 /* We want more bytes than seem to be available.
154 * Maybe we need a new page, maybe we have just run out 154 * Maybe we need a new page, maybe we have just run out
155 */ 155 */
156 int avail = (char*)argp->end - (char*)argp->p; 156 unsigned int avail = (char *)argp->end - (char *)argp->p;
157 __be32 *p; 157 __be32 *p;
158 if (avail + argp->pagelen < nbytes) 158 if (avail + argp->pagelen < nbytes)
159 return NULL; 159 return NULL;
@@ -169,6 +169,11 @@ static __be32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes)
169 return NULL; 169 return NULL;
170 170
171 } 171 }
172 /*
173 * The following memcpy is safe because read_buf is always
174 * called with nbytes > avail, and the two cases above both
175 * guarantee p points to at least nbytes bytes.
176 */
172 memcpy(p, argp->p, avail); 177 memcpy(p, argp->p, avail);
173 /* step to next page */ 178 /* step to next page */
174 argp->p = page_address(argp->pagelist[0]); 179 argp->p = page_address(argp->pagelist[0]);
@@ -1448,7 +1453,7 @@ static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err)
1448__be32 1453__be32
1449nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, 1454nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
1450 struct dentry *dentry, __be32 *buffer, int *countp, u32 *bmval, 1455 struct dentry *dentry, __be32 *buffer, int *countp, u32 *bmval,
1451 struct svc_rqst *rqstp) 1456 struct svc_rqst *rqstp, int ignore_crossmnt)
1452{ 1457{
1453 u32 bmval0 = bmval[0]; 1458 u32 bmval0 = bmval[0];
1454 u32 bmval1 = bmval[1]; 1459 u32 bmval1 = bmval[1];
@@ -1828,7 +1833,12 @@ out_acl:
1828 if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) { 1833 if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) {
1829 if ((buflen -= 8) < 0) 1834 if ((buflen -= 8) < 0)
1830 goto out_resource; 1835 goto out_resource;
1831 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) {
1832 err = vfs_getattr(exp->ex_mnt->mnt_parent, 1842 err = vfs_getattr(exp->ex_mnt->mnt_parent,
1833 exp->ex_mnt->mnt_mountpoint, &stat); 1843 exp->ex_mnt->mnt_mountpoint, &stat);
1834 if (err) 1844 if (err)
@@ -1864,13 +1874,25 @@ nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
1864 struct svc_export *exp = cd->rd_fhp->fh_export; 1874 struct svc_export *exp = cd->rd_fhp->fh_export;
1865 struct dentry *dentry; 1875 struct dentry *dentry;
1866 __be32 nfserr; 1876 __be32 nfserr;
1877 int ignore_crossmnt = 0;
1867 1878
1868 dentry = lookup_one_len(name, cd->rd_fhp->fh_dentry, namlen); 1879 dentry = lookup_one_len(name, cd->rd_fhp->fh_dentry, namlen);
1869 if (IS_ERR(dentry)) 1880 if (IS_ERR(dentry))
1870 return nfserrno(PTR_ERR(dentry)); 1881 return nfserrno(PTR_ERR(dentry));
1871 1882
1872 exp_get(exp); 1883 exp_get(exp);
1873 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)) {
1874 int err; 1896 int err;
1875 1897
1876 /* 1898 /*
@@ -1889,7 +1911,7 @@ nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
1889 1911
1890 } 1912 }
1891 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,
1892 cd->rd_rqstp); 1914 cd->rd_rqstp, ignore_crossmnt);
1893out_put: 1915out_put:
1894 dput(dentry); 1916 dput(dentry);
1895 exp_put(exp); 1917 exp_put(exp);
@@ -2043,7 +2065,7 @@ nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
2043 buflen = resp->end - resp->p - (COMPOUND_ERR_SLACK_SPACE >> 2); 2065 buflen = resp->end - resp->p - (COMPOUND_ERR_SLACK_SPACE >> 2);
2044 nfserr = nfsd4_encode_fattr(fhp, fhp->fh_export, fhp->fh_dentry, 2066 nfserr = nfsd4_encode_fattr(fhp, fhp->fh_export, fhp->fh_dentry,
2045 resp->p, &buflen, getattr->ga_bmval, 2067 resp->p, &buflen, getattr->ga_bmval,
2046 resp->rqstp); 2068 resp->rqstp, 0);
2047 if (!nfserr) 2069 if (!nfserr)
2048 resp->p += buflen; 2070 resp->p += buflen;
2049 return nfserr; 2071 return nfserr;