diff options
Diffstat (limited to 'fs/nfsd/nfs4xdr.c')
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 36 |
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 | ||
151 | static __be32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes) | 151 | static __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 |
1449 | nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | 1454 | nfsd4_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); |
1893 | out_put: | 1915 | out_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; |