diff options
Diffstat (limited to 'fs/nfsd/nfs4xdr.c')
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 4cfacc557b40..0589852007e6 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -1223,6 +1223,119 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) | |||
1223 | stateowner->so_replay.rp_buflen); \ | 1223 | stateowner->so_replay.rp_buflen); \ |
1224 | } } while (0); | 1224 | } } while (0); |
1225 | 1225 | ||
1226 | /* Encode as an array of strings the string given with components | ||
1227 | * seperated @sep. | ||
1228 | */ | ||
1229 | static int nfsd4_encode_components(char sep, char *components, | ||
1230 | u32 **pp, int *buflen) | ||
1231 | { | ||
1232 | u32 *p = *pp; | ||
1233 | u32 *countp = p; | ||
1234 | int strlen, count=0; | ||
1235 | char *str, *end; | ||
1236 | |||
1237 | dprintk("nfsd4_encode_components(%s)\n", components); | ||
1238 | if ((*buflen -= 4) < 0) | ||
1239 | return nfserr_resource; | ||
1240 | WRITE32(0); /* We will fill this in with @count later */ | ||
1241 | end = str = components; | ||
1242 | while (*end) { | ||
1243 | for (; *end && (*end != sep); end++) | ||
1244 | ; /* Point to end of component */ | ||
1245 | strlen = end - str; | ||
1246 | if (strlen) { | ||
1247 | if ((*buflen -= ((XDR_QUADLEN(strlen) << 2) + 4)) < 0) | ||
1248 | return nfserr_resource; | ||
1249 | WRITE32(strlen); | ||
1250 | WRITEMEM(str, strlen); | ||
1251 | count++; | ||
1252 | } | ||
1253 | else | ||
1254 | end++; | ||
1255 | str = end; | ||
1256 | } | ||
1257 | *pp = p; | ||
1258 | p = countp; | ||
1259 | WRITE32(count); | ||
1260 | return 0; | ||
1261 | } | ||
1262 | |||
1263 | /* | ||
1264 | * encode a location element of a fs_locations structure | ||
1265 | */ | ||
1266 | static int nfsd4_encode_fs_location4(struct nfsd4_fs_location *location, | ||
1267 | u32 **pp, int *buflen) | ||
1268 | { | ||
1269 | int status; | ||
1270 | u32 *p = *pp; | ||
1271 | |||
1272 | status = nfsd4_encode_components(':', location->hosts, &p, buflen); | ||
1273 | if (status) | ||
1274 | return status; | ||
1275 | status = nfsd4_encode_components('/', location->path, &p, buflen); | ||
1276 | if (status) | ||
1277 | return status; | ||
1278 | *pp = p; | ||
1279 | return 0; | ||
1280 | } | ||
1281 | |||
1282 | /* | ||
1283 | * Return the path to an export point in the pseudo filesystem namespace | ||
1284 | * Returned string is safe to use as long as the caller holds a reference | ||
1285 | * to @exp. | ||
1286 | */ | ||
1287 | static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp) | ||
1288 | { | ||
1289 | struct svc_fh tmp_fh; | ||
1290 | char *path, *rootpath; | ||
1291 | int stat; | ||
1292 | |||
1293 | fh_init(&tmp_fh, NFS4_FHSIZE); | ||
1294 | stat = exp_pseudoroot(rqstp->rq_client, &tmp_fh, &rqstp->rq_chandle); | ||
1295 | if (stat) | ||
1296 | return ERR_PTR(stat); | ||
1297 | rootpath = tmp_fh.fh_export->ex_path; | ||
1298 | |||
1299 | path = exp->ex_path; | ||
1300 | |||
1301 | if (strncmp(path, rootpath, strlen(rootpath))) { | ||
1302 | printk("nfsd: fs_locations failed;" | ||
1303 | "%s is not contained in %s\n", path, rootpath); | ||
1304 | return ERR_PTR(-EOPNOTSUPP); | ||
1305 | } | ||
1306 | |||
1307 | return path + strlen(rootpath); | ||
1308 | } | ||
1309 | |||
1310 | /* | ||
1311 | * encode a fs_locations structure | ||
1312 | */ | ||
1313 | static int nfsd4_encode_fs_locations(struct svc_rqst *rqstp, | ||
1314 | struct svc_export *exp, | ||
1315 | u32 **pp, int *buflen) | ||
1316 | { | ||
1317 | int status, i; | ||
1318 | u32 *p = *pp; | ||
1319 | struct nfsd4_fs_locations *fslocs = &exp->ex_fslocs; | ||
1320 | char *root = nfsd4_path(rqstp, exp); | ||
1321 | |||
1322 | if (IS_ERR(root)) | ||
1323 | return PTR_ERR(root); | ||
1324 | status = nfsd4_encode_components('/', root, &p, buflen); | ||
1325 | if (status) | ||
1326 | return status; | ||
1327 | if ((*buflen -= 4) < 0) | ||
1328 | return nfserr_resource; | ||
1329 | WRITE32(fslocs->locations_count); | ||
1330 | for (i=0; i<fslocs->locations_count; i++) { | ||
1331 | status = nfsd4_encode_fs_location4(&fslocs->locations[i], | ||
1332 | &p, buflen); | ||
1333 | if (status) | ||
1334 | return status; | ||
1335 | } | ||
1336 | *pp = p; | ||
1337 | return 0; | ||
1338 | } | ||
1226 | 1339 | ||
1227 | static u32 nfs4_ftypes[16] = { | 1340 | static u32 nfs4_ftypes[16] = { |
1228 | NF4BAD, NF4FIFO, NF4CHR, NF4BAD, | 1341 | NF4BAD, NF4FIFO, NF4CHR, NF4BAD, |
@@ -1334,6 +1447,11 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | |||
1334 | goto out_nfserr; | 1447 | goto out_nfserr; |
1335 | } | 1448 | } |
1336 | } | 1449 | } |
1450 | if (bmval0 & FATTR4_WORD0_FS_LOCATIONS) { | ||
1451 | if (exp->ex_fslocs.locations == NULL) { | ||
1452 | bmval0 &= ~FATTR4_WORD0_FS_LOCATIONS; | ||
1453 | } | ||
1454 | } | ||
1337 | if ((buflen -= 16) < 0) | 1455 | if ((buflen -= 16) < 0) |
1338 | goto out_resource; | 1456 | goto out_resource; |
1339 | 1457 | ||
@@ -1513,6 +1631,13 @@ out_acl: | |||
1513 | goto out_resource; | 1631 | goto out_resource; |
1514 | WRITE64((u64) statfs.f_files); | 1632 | WRITE64((u64) statfs.f_files); |
1515 | } | 1633 | } |
1634 | if (bmval0 & FATTR4_WORD0_FS_LOCATIONS) { | ||
1635 | status = nfsd4_encode_fs_locations(rqstp, exp, &p, &buflen); | ||
1636 | if (status == nfserr_resource) | ||
1637 | goto out_resource; | ||
1638 | if (status) | ||
1639 | goto out; | ||
1640 | } | ||
1516 | if (bmval0 & FATTR4_WORD0_HOMOGENEOUS) { | 1641 | if (bmval0 & FATTR4_WORD0_HOMOGENEOUS) { |
1517 | if ((buflen -= 4) < 0) | 1642 | if ((buflen -= 4) < 0) |
1518 | goto out_resource; | 1643 | goto out_resource; |