diff options
-rw-r--r-- | fs/nfsd/nfs4proc.c | 247 | ||||
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 37 | ||||
-rw-r--r-- | fs/nfsd/xdr4.h | 1 |
3 files changed, 248 insertions, 37 deletions
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 460eeb329d81..752a367e0e3d 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/file.h> | 35 | #include <linux/file.h> |
36 | #include <linux/slab.h> | 36 | #include <linux/slab.h> |
37 | 37 | ||
38 | #include "idmap.h" | ||
38 | #include "cache.h" | 39 | #include "cache.h" |
39 | #include "xdr4.h" | 40 | #include "xdr4.h" |
40 | #include "vfs.h" | 41 | #include "vfs.h" |
@@ -1003,6 +1004,8 @@ static inline void nfsd4_increment_op_stats(u32 opnum) | |||
1003 | 1004 | ||
1004 | typedef __be32(*nfsd4op_func)(struct svc_rqst *, struct nfsd4_compound_state *, | 1005 | typedef __be32(*nfsd4op_func)(struct svc_rqst *, struct nfsd4_compound_state *, |
1005 | void *); | 1006 | void *); |
1007 | typedef u32(*nfsd4op_rsize)(struct svc_rqst *, struct nfsd4_op *op); | ||
1008 | |||
1006 | enum nfsd4_op_flags { | 1009 | enum nfsd4_op_flags { |
1007 | ALLOWED_WITHOUT_FH = 1 << 0, /* No current filehandle required */ | 1010 | ALLOWED_WITHOUT_FH = 1 << 0, /* No current filehandle required */ |
1008 | ALLOWED_ON_ABSENT_FS = 1 << 1, /* ops processed on absent fs */ | 1011 | ALLOWED_ON_ABSENT_FS = 1 << 1, /* ops processed on absent fs */ |
@@ -1010,6 +1013,7 @@ enum nfsd4_op_flags { | |||
1010 | /* For rfc 5661 section 2.6.3.1.1: */ | 1013 | /* For rfc 5661 section 2.6.3.1.1: */ |
1011 | OP_HANDLES_WRONGSEC = 1 << 3, | 1014 | OP_HANDLES_WRONGSEC = 1 << 3, |
1012 | OP_IS_PUTFH_LIKE = 1 << 4, | 1015 | OP_IS_PUTFH_LIKE = 1 << 4, |
1016 | OP_MODIFIES_SOMETHING = 1 << 5, /* op is non-idempotent */ | ||
1013 | }; | 1017 | }; |
1014 | 1018 | ||
1015 | struct nfsd4_operation { | 1019 | struct nfsd4_operation { |
@@ -1025,6 +1029,8 @@ struct nfsd4_operation { | |||
1025 | * the v4.0 case). | 1029 | * the v4.0 case). |
1026 | */ | 1030 | */ |
1027 | bool op_cacheresult; | 1031 | bool op_cacheresult; |
1032 | /* Try to get response size before operation */ | ||
1033 | nfsd4op_rsize op_rsize_bop; | ||
1028 | }; | 1034 | }; |
1029 | 1035 | ||
1030 | static struct nfsd4_operation nfsd4_ops[]; | 1036 | static struct nfsd4_operation nfsd4_ops[]; |
@@ -1119,6 +1125,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
1119 | struct nfsd4_operation *opdesc; | 1125 | struct nfsd4_operation *opdesc; |
1120 | struct nfsd4_compound_state *cstate = &resp->cstate; | 1126 | struct nfsd4_compound_state *cstate = &resp->cstate; |
1121 | int slack_bytes; | 1127 | int slack_bytes; |
1128 | u32 plen = 0; | ||
1122 | __be32 status; | 1129 | __be32 status; |
1123 | 1130 | ||
1124 | resp->xbuf = &rqstp->rq_res; | 1131 | resp->xbuf = &rqstp->rq_res; |
@@ -1197,6 +1204,15 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
1197 | goto encode_op; | 1204 | goto encode_op; |
1198 | } | 1205 | } |
1199 | 1206 | ||
1207 | /* If op is non-idempotent */ | ||
1208 | if (opdesc->op_flags & OP_MODIFIES_SOMETHING) { | ||
1209 | plen = opdesc->op_rsize_bop(rqstp, op); | ||
1210 | op->status = nfsd4_check_resp_size(resp, plen); | ||
1211 | } | ||
1212 | |||
1213 | if (op->status) | ||
1214 | goto encode_op; | ||
1215 | |||
1200 | if (opdesc->op_func) | 1216 | if (opdesc->op_func) |
1201 | op->status = opdesc->op_func(rqstp, cstate, &op->u); | 1217 | op->status = opdesc->op_func(rqstp, cstate, &op->u); |
1202 | else | 1218 | else |
@@ -1247,6 +1263,144 @@ out: | |||
1247 | return status; | 1263 | return status; |
1248 | } | 1264 | } |
1249 | 1265 | ||
1266 | #define op_encode_hdr_size (2) | ||
1267 | #define op_encode_stateid_maxsz (XDR_QUADLEN(NFS4_STATEID_SIZE)) | ||
1268 | #define op_encode_verifier_maxsz (XDR_QUADLEN(NFS4_VERIFIER_SIZE)) | ||
1269 | #define op_encode_change_info_maxsz (5) | ||
1270 | #define nfs4_fattr_bitmap_maxsz (4) | ||
1271 | |||
1272 | #define op_encode_lockowner_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ)) | ||
1273 | #define op_encode_lock_denied_maxsz (8 + op_encode_lockowner_maxsz) | ||
1274 | |||
1275 | #define nfs4_owner_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ)) | ||
1276 | |||
1277 | #define op_encode_ace_maxsz (3 + nfs4_owner_maxsz) | ||
1278 | #define op_encode_delegation_maxsz (1 + op_encode_stateid_maxsz + 1 + \ | ||
1279 | op_encode_ace_maxsz) | ||
1280 | |||
1281 | #define op_encode_channel_attrs_maxsz (6 + 1 + 1) | ||
1282 | |||
1283 | static inline u32 nfsd4_only_status_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1284 | { | ||
1285 | return (op_encode_hdr_size) * sizeof(__be32); | ||
1286 | } | ||
1287 | |||
1288 | static inline u32 nfsd4_status_stateid_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1289 | { | ||
1290 | return (op_encode_hdr_size + op_encode_stateid_maxsz)* sizeof(__be32); | ||
1291 | } | ||
1292 | |||
1293 | static inline u32 nfsd4_commit_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1294 | { | ||
1295 | return (op_encode_hdr_size + op_encode_verifier_maxsz) * sizeof(__be32); | ||
1296 | } | ||
1297 | |||
1298 | static inline u32 nfsd4_create_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1299 | { | ||
1300 | return (op_encode_hdr_size + op_encode_change_info_maxsz | ||
1301 | + nfs4_fattr_bitmap_maxsz) * sizeof(__be32); | ||
1302 | } | ||
1303 | |||
1304 | static inline u32 nfsd4_link_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1305 | { | ||
1306 | return (op_encode_hdr_size + op_encode_change_info_maxsz) | ||
1307 | * sizeof(__be32); | ||
1308 | } | ||
1309 | |||
1310 | static inline u32 nfsd4_lock_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1311 | { | ||
1312 | return (op_encode_hdr_size + op_encode_lock_denied_maxsz) | ||
1313 | * sizeof(__be32); | ||
1314 | } | ||
1315 | |||
1316 | static inline u32 nfsd4_open_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1317 | { | ||
1318 | return (op_encode_hdr_size + op_encode_stateid_maxsz | ||
1319 | + op_encode_change_info_maxsz + 1 | ||
1320 | + nfs4_fattr_bitmap_maxsz | ||
1321 | + op_encode_delegation_maxsz) * sizeof(__be32); | ||
1322 | } | ||
1323 | |||
1324 | static inline u32 nfsd4_read_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1325 | { | ||
1326 | u32 maxcount = 0, rlen = 0; | ||
1327 | |||
1328 | maxcount = svc_max_payload(rqstp); | ||
1329 | rlen = op->u.read.rd_length; | ||
1330 | |||
1331 | if (rlen > maxcount) | ||
1332 | rlen = maxcount; | ||
1333 | |||
1334 | return (op_encode_hdr_size + 2) * sizeof(__be32) + rlen; | ||
1335 | } | ||
1336 | |||
1337 | static inline u32 nfsd4_readdir_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1338 | { | ||
1339 | u32 rlen = op->u.readdir.rd_maxcount; | ||
1340 | |||
1341 | if (rlen > PAGE_SIZE) | ||
1342 | rlen = PAGE_SIZE; | ||
1343 | |||
1344 | return (op_encode_hdr_size + op_encode_verifier_maxsz) | ||
1345 | * sizeof(__be32) + rlen; | ||
1346 | } | ||
1347 | |||
1348 | static inline u32 nfsd4_remove_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1349 | { | ||
1350 | return (op_encode_hdr_size + op_encode_change_info_maxsz) | ||
1351 | * sizeof(__be32); | ||
1352 | } | ||
1353 | |||
1354 | static inline u32 nfsd4_rename_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1355 | { | ||
1356 | return (op_encode_hdr_size + op_encode_change_info_maxsz | ||
1357 | + op_encode_change_info_maxsz) * sizeof(__be32); | ||
1358 | } | ||
1359 | |||
1360 | static inline u32 nfsd4_setattr_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1361 | { | ||
1362 | return (op_encode_hdr_size + nfs4_fattr_bitmap_maxsz) * sizeof(__be32); | ||
1363 | } | ||
1364 | |||
1365 | static inline u32 nfsd4_setclientid_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1366 | { | ||
1367 | return (op_encode_hdr_size + 2 + 1024) * sizeof(__be32); | ||
1368 | } | ||
1369 | |||
1370 | static inline u32 nfsd4_write_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1371 | { | ||
1372 | return (op_encode_hdr_size + op_encode_verifier_maxsz) * sizeof(__be32); | ||
1373 | } | ||
1374 | |||
1375 | static inline u32 nfsd4_exchange_id_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1376 | { | ||
1377 | return (op_encode_hdr_size + 2 + 1 + /* eir_clientid, eir_sequenceid */\ | ||
1378 | 1 + 1 + 0 + /* eir_flags, spr_how, SP4_NONE (for now) */\ | ||
1379 | 2 + /*eir_server_owner.so_minor_id */\ | ||
1380 | /* eir_server_owner.so_major_id<> */\ | ||
1381 | XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 +\ | ||
1382 | /* eir_server_scope<> */\ | ||
1383 | XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 +\ | ||
1384 | 1 + /* eir_server_impl_id array length */\ | ||
1385 | 0 /* ignored eir_server_impl_id contents */) * sizeof(__be32); | ||
1386 | } | ||
1387 | |||
1388 | static inline u32 nfsd4_bind_conn_to_session_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1389 | { | ||
1390 | return (op_encode_hdr_size + \ | ||
1391 | XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + /* bctsr_sessid */\ | ||
1392 | 2 /* bctsr_dir, use_conn_in_rdma_mode */) * sizeof(__be32); | ||
1393 | } | ||
1394 | |||
1395 | static inline u32 nfsd4_create_session_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1396 | { | ||
1397 | return (op_encode_hdr_size + \ | ||
1398 | XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + /* sessionid */\ | ||
1399 | 2 + /* csr_sequence, csr_flags */\ | ||
1400 | op_encode_channel_attrs_maxsz + \ | ||
1401 | op_encode_channel_attrs_maxsz) * sizeof(__be32); | ||
1402 | } | ||
1403 | |||
1250 | static struct nfsd4_operation nfsd4_ops[] = { | 1404 | static struct nfsd4_operation nfsd4_ops[] = { |
1251 | [OP_ACCESS] = { | 1405 | [OP_ACCESS] = { |
1252 | .op_func = (nfsd4op_func)nfsd4_access, | 1406 | .op_func = (nfsd4op_func)nfsd4_access, |
@@ -1254,20 +1408,28 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1254 | }, | 1408 | }, |
1255 | [OP_CLOSE] = { | 1409 | [OP_CLOSE] = { |
1256 | .op_func = (nfsd4op_func)nfsd4_close, | 1410 | .op_func = (nfsd4op_func)nfsd4_close, |
1411 | .op_flags = OP_MODIFIES_SOMETHING, | ||
1257 | .op_name = "OP_CLOSE", | 1412 | .op_name = "OP_CLOSE", |
1413 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize, | ||
1258 | }, | 1414 | }, |
1259 | [OP_COMMIT] = { | 1415 | [OP_COMMIT] = { |
1260 | .op_func = (nfsd4op_func)nfsd4_commit, | 1416 | .op_func = (nfsd4op_func)nfsd4_commit, |
1417 | .op_flags = OP_MODIFIES_SOMETHING, | ||
1261 | .op_name = "OP_COMMIT", | 1418 | .op_name = "OP_COMMIT", |
1419 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_commit_rsize, | ||
1262 | }, | 1420 | }, |
1263 | [OP_CREATE] = { | 1421 | [OP_CREATE] = { |
1264 | .op_func = (nfsd4op_func)nfsd4_create, | 1422 | .op_func = (nfsd4op_func)nfsd4_create, |
1423 | .op_flags = OP_MODIFIES_SOMETHING, | ||
1265 | .op_name = "OP_CREATE", | 1424 | .op_name = "OP_CREATE", |
1266 | .op_cacheresult = true, | 1425 | .op_cacheresult = true, |
1426 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_create_rsize, | ||
1267 | }, | 1427 | }, |
1268 | [OP_DELEGRETURN] = { | 1428 | [OP_DELEGRETURN] = { |
1269 | .op_func = (nfsd4op_func)nfsd4_delegreturn, | 1429 | .op_func = (nfsd4op_func)nfsd4_delegreturn, |
1430 | .op_flags = OP_MODIFIES_SOMETHING, | ||
1270 | .op_name = "OP_DELEGRETURN", | 1431 | .op_name = "OP_DELEGRETURN", |
1432 | .op_rsize_bop = nfsd4_only_status_rsize, | ||
1271 | }, | 1433 | }, |
1272 | [OP_GETATTR] = { | 1434 | [OP_GETATTR] = { |
1273 | .op_func = (nfsd4op_func)nfsd4_getattr, | 1435 | .op_func = (nfsd4op_func)nfsd4_getattr, |
@@ -1280,12 +1442,16 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1280 | }, | 1442 | }, |
1281 | [OP_LINK] = { | 1443 | [OP_LINK] = { |
1282 | .op_func = (nfsd4op_func)nfsd4_link, | 1444 | .op_func = (nfsd4op_func)nfsd4_link, |
1445 | .op_flags = ALLOWED_ON_ABSENT_FS | OP_MODIFIES_SOMETHING, | ||
1283 | .op_name = "OP_LINK", | 1446 | .op_name = "OP_LINK", |
1284 | .op_cacheresult = true, | 1447 | .op_cacheresult = true, |
1448 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_link_rsize, | ||
1285 | }, | 1449 | }, |
1286 | [OP_LOCK] = { | 1450 | [OP_LOCK] = { |
1287 | .op_func = (nfsd4op_func)nfsd4_lock, | 1451 | .op_func = (nfsd4op_func)nfsd4_lock, |
1452 | .op_flags = OP_MODIFIES_SOMETHING, | ||
1288 | .op_name = "OP_LOCK", | 1453 | .op_name = "OP_LOCK", |
1454 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_lock_rsize, | ||
1289 | }, | 1455 | }, |
1290 | [OP_LOCKT] = { | 1456 | [OP_LOCKT] = { |
1291 | .op_func = (nfsd4op_func)nfsd4_lockt, | 1457 | .op_func = (nfsd4op_func)nfsd4_lockt, |
@@ -1293,7 +1459,9 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1293 | }, | 1459 | }, |
1294 | [OP_LOCKU] = { | 1460 | [OP_LOCKU] = { |
1295 | .op_func = (nfsd4op_func)nfsd4_locku, | 1461 | .op_func = (nfsd4op_func)nfsd4_locku, |
1462 | .op_flags = OP_MODIFIES_SOMETHING, | ||
1296 | .op_name = "OP_LOCKU", | 1463 | .op_name = "OP_LOCKU", |
1464 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize, | ||
1297 | }, | 1465 | }, |
1298 | [OP_LOOKUP] = { | 1466 | [OP_LOOKUP] = { |
1299 | .op_func = (nfsd4op_func)nfsd4_lookup, | 1467 | .op_func = (nfsd4op_func)nfsd4_lookup, |
@@ -1311,42 +1479,54 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1311 | }, | 1479 | }, |
1312 | [OP_OPEN] = { | 1480 | [OP_OPEN] = { |
1313 | .op_func = (nfsd4op_func)nfsd4_open, | 1481 | .op_func = (nfsd4op_func)nfsd4_open, |
1314 | .op_flags = OP_HANDLES_WRONGSEC, | 1482 | .op_flags = OP_HANDLES_WRONGSEC | OP_MODIFIES_SOMETHING, |
1315 | .op_name = "OP_OPEN", | 1483 | .op_name = "OP_OPEN", |
1484 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_open_rsize, | ||
1316 | }, | 1485 | }, |
1317 | [OP_OPEN_CONFIRM] = { | 1486 | [OP_OPEN_CONFIRM] = { |
1318 | .op_func = (nfsd4op_func)nfsd4_open_confirm, | 1487 | .op_func = (nfsd4op_func)nfsd4_open_confirm, |
1488 | .op_flags = OP_MODIFIES_SOMETHING, | ||
1319 | .op_name = "OP_OPEN_CONFIRM", | 1489 | .op_name = "OP_OPEN_CONFIRM", |
1490 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize, | ||
1320 | }, | 1491 | }, |
1321 | [OP_OPEN_DOWNGRADE] = { | 1492 | [OP_OPEN_DOWNGRADE] = { |
1322 | .op_func = (nfsd4op_func)nfsd4_open_downgrade, | 1493 | .op_func = (nfsd4op_func)nfsd4_open_downgrade, |
1494 | .op_flags = OP_MODIFIES_SOMETHING, | ||
1323 | .op_name = "OP_OPEN_DOWNGRADE", | 1495 | .op_name = "OP_OPEN_DOWNGRADE", |
1496 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize, | ||
1324 | }, | 1497 | }, |
1325 | [OP_PUTFH] = { | 1498 | [OP_PUTFH] = { |
1326 | .op_func = (nfsd4op_func)nfsd4_putfh, | 1499 | .op_func = (nfsd4op_func)nfsd4_putfh, |
1327 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS | 1500 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1328 | | OP_IS_PUTFH_LIKE, | 1501 | | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING, |
1329 | .op_name = "OP_PUTFH", | 1502 | .op_name = "OP_PUTFH", |
1503 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | ||
1330 | }, | 1504 | }, |
1331 | [OP_PUTPUBFH] = { | 1505 | [OP_PUTPUBFH] = { |
1332 | .op_func = (nfsd4op_func)nfsd4_putrootfh, | 1506 | .op_func = (nfsd4op_func)nfsd4_putrootfh, |
1333 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS | 1507 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1334 | | OP_IS_PUTFH_LIKE, | 1508 | | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING, |
1335 | .op_name = "OP_PUTPUBFH", | 1509 | .op_name = "OP_PUTPUBFH", |
1510 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | ||
1336 | }, | 1511 | }, |
1337 | [OP_PUTROOTFH] = { | 1512 | [OP_PUTROOTFH] = { |
1338 | .op_func = (nfsd4op_func)nfsd4_putrootfh, | 1513 | .op_func = (nfsd4op_func)nfsd4_putrootfh, |
1339 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS | 1514 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1340 | | OP_IS_PUTFH_LIKE, | 1515 | | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING, |
1341 | .op_name = "OP_PUTROOTFH", | 1516 | .op_name = "OP_PUTROOTFH", |
1517 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | ||
1342 | }, | 1518 | }, |
1343 | [OP_READ] = { | 1519 | [OP_READ] = { |
1344 | .op_func = (nfsd4op_func)nfsd4_read, | 1520 | .op_func = (nfsd4op_func)nfsd4_read, |
1521 | .op_flags = OP_MODIFIES_SOMETHING, | ||
1345 | .op_name = "OP_READ", | 1522 | .op_name = "OP_READ", |
1523 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_read_rsize, | ||
1346 | }, | 1524 | }, |
1347 | [OP_READDIR] = { | 1525 | [OP_READDIR] = { |
1348 | .op_func = (nfsd4op_func)nfsd4_readdir, | 1526 | .op_func = (nfsd4op_func)nfsd4_readdir, |
1527 | .op_flags = OP_MODIFIES_SOMETHING, | ||
1349 | .op_name = "OP_READDIR", | 1528 | .op_name = "OP_READDIR", |
1529 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_readdir_rsize, | ||
1350 | }, | 1530 | }, |
1351 | [OP_READLINK] = { | 1531 | [OP_READLINK] = { |
1352 | .op_func = (nfsd4op_func)nfsd4_readlink, | 1532 | .op_func = (nfsd4op_func)nfsd4_readlink, |
@@ -1354,29 +1534,38 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1354 | }, | 1534 | }, |
1355 | [OP_REMOVE] = { | 1535 | [OP_REMOVE] = { |
1356 | .op_func = (nfsd4op_func)nfsd4_remove, | 1536 | .op_func = (nfsd4op_func)nfsd4_remove, |
1537 | .op_flags = OP_MODIFIES_SOMETHING, | ||
1357 | .op_name = "OP_REMOVE", | 1538 | .op_name = "OP_REMOVE", |
1358 | .op_cacheresult = true, | 1539 | .op_cacheresult = true, |
1540 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_remove_rsize, | ||
1359 | }, | 1541 | }, |
1360 | [OP_RENAME] = { | 1542 | [OP_RENAME] = { |
1361 | .op_name = "OP_RENAME", | ||
1362 | .op_func = (nfsd4op_func)nfsd4_rename, | 1543 | .op_func = (nfsd4op_func)nfsd4_rename, |
1544 | .op_flags = OP_MODIFIES_SOMETHING, | ||
1545 | .op_name = "OP_RENAME", | ||
1363 | .op_cacheresult = true, | 1546 | .op_cacheresult = true, |
1547 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_rename_rsize, | ||
1364 | }, | 1548 | }, |
1365 | [OP_RENEW] = { | 1549 | [OP_RENEW] = { |
1366 | .op_func = (nfsd4op_func)nfsd4_renew, | 1550 | .op_func = (nfsd4op_func)nfsd4_renew, |
1367 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, | 1551 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1552 | | OP_MODIFIES_SOMETHING, | ||
1368 | .op_name = "OP_RENEW", | 1553 | .op_name = "OP_RENEW", |
1554 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | ||
1555 | |||
1369 | }, | 1556 | }, |
1370 | [OP_RESTOREFH] = { | 1557 | [OP_RESTOREFH] = { |
1371 | .op_func = (nfsd4op_func)nfsd4_restorefh, | 1558 | .op_func = (nfsd4op_func)nfsd4_restorefh, |
1372 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS | 1559 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1373 | | OP_IS_PUTFH_LIKE, | 1560 | | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING, |
1374 | .op_name = "OP_RESTOREFH", | 1561 | .op_name = "OP_RESTOREFH", |
1562 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | ||
1375 | }, | 1563 | }, |
1376 | [OP_SAVEFH] = { | 1564 | [OP_SAVEFH] = { |
1377 | .op_func = (nfsd4op_func)nfsd4_savefh, | 1565 | .op_func = (nfsd4op_func)nfsd4_savefh, |
1378 | .op_flags = OP_HANDLES_WRONGSEC, | 1566 | .op_flags = OP_HANDLES_WRONGSEC | OP_MODIFIES_SOMETHING, |
1379 | .op_name = "OP_SAVEFH", | 1567 | .op_name = "OP_SAVEFH", |
1568 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | ||
1380 | }, | 1569 | }, |
1381 | [OP_SECINFO] = { | 1570 | [OP_SECINFO] = { |
1382 | .op_func = (nfsd4op_func)nfsd4_secinfo, | 1571 | .op_func = (nfsd4op_func)nfsd4_secinfo, |
@@ -1386,19 +1575,25 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1386 | [OP_SETATTR] = { | 1575 | [OP_SETATTR] = { |
1387 | .op_func = (nfsd4op_func)nfsd4_setattr, | 1576 | .op_func = (nfsd4op_func)nfsd4_setattr, |
1388 | .op_name = "OP_SETATTR", | 1577 | .op_name = "OP_SETATTR", |
1578 | .op_flags = OP_MODIFIES_SOMETHING, | ||
1389 | .op_cacheresult = true, | 1579 | .op_cacheresult = true, |
1580 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_setattr_rsize, | ||
1390 | }, | 1581 | }, |
1391 | [OP_SETCLIENTID] = { | 1582 | [OP_SETCLIENTID] = { |
1392 | .op_func = (nfsd4op_func)nfsd4_setclientid, | 1583 | .op_func = (nfsd4op_func)nfsd4_setclientid, |
1393 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, | 1584 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1585 | | OP_MODIFIES_SOMETHING, | ||
1394 | .op_name = "OP_SETCLIENTID", | 1586 | .op_name = "OP_SETCLIENTID", |
1395 | .op_cacheresult = true, | 1587 | .op_cacheresult = true, |
1588 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_setclientid_rsize, | ||
1396 | }, | 1589 | }, |
1397 | [OP_SETCLIENTID_CONFIRM] = { | 1590 | [OP_SETCLIENTID_CONFIRM] = { |
1398 | .op_func = (nfsd4op_func)nfsd4_setclientid_confirm, | 1591 | .op_func = (nfsd4op_func)nfsd4_setclientid_confirm, |
1399 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, | 1592 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1593 | | OP_MODIFIES_SOMETHING, | ||
1400 | .op_name = "OP_SETCLIENTID_CONFIRM", | 1594 | .op_name = "OP_SETCLIENTID_CONFIRM", |
1401 | .op_cacheresult = true, | 1595 | .op_cacheresult = true, |
1596 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | ||
1402 | }, | 1597 | }, |
1403 | [OP_VERIFY] = { | 1598 | [OP_VERIFY] = { |
1404 | .op_func = (nfsd4op_func)nfsd4_verify, | 1599 | .op_func = (nfsd4op_func)nfsd4_verify, |
@@ -1406,35 +1601,47 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1406 | }, | 1601 | }, |
1407 | [OP_WRITE] = { | 1602 | [OP_WRITE] = { |
1408 | .op_func = (nfsd4op_func)nfsd4_write, | 1603 | .op_func = (nfsd4op_func)nfsd4_write, |
1604 | .op_flags = OP_MODIFIES_SOMETHING, | ||
1409 | .op_name = "OP_WRITE", | 1605 | .op_name = "OP_WRITE", |
1410 | .op_cacheresult = true, | 1606 | .op_cacheresult = true, |
1607 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_write_rsize, | ||
1411 | }, | 1608 | }, |
1412 | [OP_RELEASE_LOCKOWNER] = { | 1609 | [OP_RELEASE_LOCKOWNER] = { |
1413 | .op_func = (nfsd4op_func)nfsd4_release_lockowner, | 1610 | .op_func = (nfsd4op_func)nfsd4_release_lockowner, |
1414 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, | 1611 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1612 | | OP_MODIFIES_SOMETHING, | ||
1415 | .op_name = "OP_RELEASE_LOCKOWNER", | 1613 | .op_name = "OP_RELEASE_LOCKOWNER", |
1614 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | ||
1416 | }, | 1615 | }, |
1417 | 1616 | ||
1418 | /* NFSv4.1 operations */ | 1617 | /* NFSv4.1 operations */ |
1419 | [OP_EXCHANGE_ID] = { | 1618 | [OP_EXCHANGE_ID] = { |
1420 | .op_func = (nfsd4op_func)nfsd4_exchange_id, | 1619 | .op_func = (nfsd4op_func)nfsd4_exchange_id, |
1421 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, | 1620 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP |
1621 | | OP_MODIFIES_SOMETHING, | ||
1422 | .op_name = "OP_EXCHANGE_ID", | 1622 | .op_name = "OP_EXCHANGE_ID", |
1623 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_exchange_id_rsize, | ||
1423 | }, | 1624 | }, |
1424 | [OP_BIND_CONN_TO_SESSION] = { | 1625 | [OP_BIND_CONN_TO_SESSION] = { |
1425 | .op_func = (nfsd4op_func)nfsd4_bind_conn_to_session, | 1626 | .op_func = (nfsd4op_func)nfsd4_bind_conn_to_session, |
1426 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, | 1627 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP |
1628 | | OP_MODIFIES_SOMETHING, | ||
1427 | .op_name = "OP_BIND_CONN_TO_SESSION", | 1629 | .op_name = "OP_BIND_CONN_TO_SESSION", |
1630 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_bind_conn_to_session_rsize, | ||
1428 | }, | 1631 | }, |
1429 | [OP_CREATE_SESSION] = { | 1632 | [OP_CREATE_SESSION] = { |
1430 | .op_func = (nfsd4op_func)nfsd4_create_session, | 1633 | .op_func = (nfsd4op_func)nfsd4_create_session, |
1431 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, | 1634 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP |
1635 | | OP_MODIFIES_SOMETHING, | ||
1432 | .op_name = "OP_CREATE_SESSION", | 1636 | .op_name = "OP_CREATE_SESSION", |
1637 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_create_session_rsize, | ||
1433 | }, | 1638 | }, |
1434 | [OP_DESTROY_SESSION] = { | 1639 | [OP_DESTROY_SESSION] = { |
1435 | .op_func = (nfsd4op_func)nfsd4_destroy_session, | 1640 | .op_func = (nfsd4op_func)nfsd4_destroy_session, |
1436 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, | 1641 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP |
1642 | | OP_MODIFIES_SOMETHING, | ||
1437 | .op_name = "OP_DESTROY_SESSION", | 1643 | .op_name = "OP_DESTROY_SESSION", |
1644 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | ||
1438 | }, | 1645 | }, |
1439 | [OP_SEQUENCE] = { | 1646 | [OP_SEQUENCE] = { |
1440 | .op_func = (nfsd4op_func)nfsd4_sequence, | 1647 | .op_func = (nfsd4op_func)nfsd4_sequence, |
@@ -1443,13 +1650,16 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1443 | }, | 1650 | }, |
1444 | [OP_DESTROY_CLIENTID] = { | 1651 | [OP_DESTROY_CLIENTID] = { |
1445 | .op_func = NULL, | 1652 | .op_func = NULL, |
1446 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, | 1653 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP |
1654 | | OP_MODIFIES_SOMETHING, | ||
1447 | .op_name = "OP_DESTROY_CLIENTID", | 1655 | .op_name = "OP_DESTROY_CLIENTID", |
1656 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | ||
1448 | }, | 1657 | }, |
1449 | [OP_RECLAIM_COMPLETE] = { | 1658 | [OP_RECLAIM_COMPLETE] = { |
1450 | .op_func = (nfsd4op_func)nfsd4_reclaim_complete, | 1659 | .op_func = (nfsd4op_func)nfsd4_reclaim_complete, |
1451 | .op_flags = ALLOWED_WITHOUT_FH, | 1660 | .op_flags = ALLOWED_WITHOUT_FH | OP_MODIFIES_SOMETHING, |
1452 | .op_name = "OP_RECLAIM_COMPLETE", | 1661 | .op_name = "OP_RECLAIM_COMPLETE", |
1662 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | ||
1453 | }, | 1663 | }, |
1454 | [OP_SECINFO_NO_NAME] = { | 1664 | [OP_SECINFO_NO_NAME] = { |
1455 | .op_func = (nfsd4op_func)nfsd4_secinfo_no_name, | 1665 | .op_func = (nfsd4op_func)nfsd4_secinfo_no_name, |
@@ -1463,8 +1673,9 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1463 | }, | 1673 | }, |
1464 | [OP_FREE_STATEID] = { | 1674 | [OP_FREE_STATEID] = { |
1465 | .op_func = (nfsd4op_func)nfsd4_free_stateid, | 1675 | .op_func = (nfsd4op_func)nfsd4_free_stateid, |
1466 | .op_flags = ALLOWED_WITHOUT_FH, | 1676 | .op_flags = ALLOWED_WITHOUT_FH | OP_MODIFIES_SOMETHING, |
1467 | .op_name = "OP_FREE_STATEID", | 1677 | .op_name = "OP_FREE_STATEID", |
1678 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | ||
1468 | }, | 1679 | }, |
1469 | }; | 1680 | }; |
1470 | 1681 | ||
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 5252d6681960..f4116cf16595 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -3387,34 +3387,29 @@ static nfsd4_enc nfsd4_enc_ops[] = { | |||
3387 | 3387 | ||
3388 | /* | 3388 | /* |
3389 | * Calculate the total amount of memory that the compound response has taken | 3389 | * Calculate the total amount of memory that the compound response has taken |
3390 | * after encoding the current operation. | 3390 | * after encoding the current operation with pad. |
3391 | * | 3391 | * |
3392 | * pad: add on 8 bytes for the next operation's op_code and status so that | 3392 | * pad: if operation is non-idempotent, pad was calculate by op_rsize_bop() |
3393 | * there is room to cache a failure on the next operation. | 3393 | * which was specified at nfsd4_operation, else pad is zero. |
3394 | * | 3394 | * |
3395 | * Compare this length to the session se_fmaxresp_cached. | 3395 | * Compare this length to the session se_fmaxresp_sz and se_fmaxresp_cached. |
3396 | * | 3396 | * |
3397 | * Our se_fmaxresp_cached will always be a multiple of PAGE_SIZE, and so | 3397 | * Our se_fmaxresp_cached will always be a multiple of PAGE_SIZE, and so |
3398 | * will be at least a page and will therefore hold the xdr_buf head. | 3398 | * will be at least a page and will therefore hold the xdr_buf head. |
3399 | */ | 3399 | */ |
3400 | static int nfsd4_check_drc_limit(struct nfsd4_compoundres *resp) | 3400 | int nfsd4_check_resp_size(struct nfsd4_compoundres *resp, u32 pad) |
3401 | { | 3401 | { |
3402 | int status = 0; | ||
3403 | struct xdr_buf *xb = &resp->rqstp->rq_res; | 3402 | struct xdr_buf *xb = &resp->rqstp->rq_res; |
3404 | struct nfsd4_compoundargs *args = resp->rqstp->rq_argp; | ||
3405 | struct nfsd4_session *session = NULL; | 3403 | struct nfsd4_session *session = NULL; |
3406 | struct nfsd4_slot *slot = resp->cstate.slot; | 3404 | struct nfsd4_slot *slot = resp->cstate.slot; |
3407 | u32 length, tlen = 0, pad = 8; | 3405 | u32 length, tlen = 0; |
3408 | 3406 | ||
3409 | if (!nfsd4_has_session(&resp->cstate)) | 3407 | if (!nfsd4_has_session(&resp->cstate)) |
3410 | return status; | 3408 | return 0; |
3411 | 3409 | ||
3412 | session = resp->cstate.session; | 3410 | session = resp->cstate.session; |
3413 | if (session == NULL || slot->sl_cachethis == 0) | 3411 | if (session == NULL) |
3414 | return status; | 3412 | return 0; |
3415 | |||
3416 | if (resp->opcnt >= args->opcnt) | ||
3417 | pad = 0; /* this is the last operation */ | ||
3418 | 3413 | ||
3419 | if (xb->page_len == 0) { | 3414 | if (xb->page_len == 0) { |
3420 | length = (char *)resp->p - (char *)xb->head[0].iov_base + pad; | 3415 | length = (char *)resp->p - (char *)xb->head[0].iov_base + pad; |
@@ -3427,10 +3422,14 @@ static int nfsd4_check_drc_limit(struct nfsd4_compoundres *resp) | |||
3427 | dprintk("%s length %u, xb->page_len %u tlen %u pad %u\n", __func__, | 3422 | dprintk("%s length %u, xb->page_len %u tlen %u pad %u\n", __func__, |
3428 | length, xb->page_len, tlen, pad); | 3423 | length, xb->page_len, tlen, pad); |
3429 | 3424 | ||
3430 | if (length <= session->se_fchannel.maxresp_cached) | 3425 | if (length > session->se_fchannel.maxresp_sz) |
3431 | return status; | 3426 | return nfserr_rep_too_big; |
3432 | else | 3427 | |
3428 | if (slot->sl_cachethis == 1 && | ||
3429 | length > session->se_fchannel.maxresp_cached) | ||
3433 | return nfserr_rep_too_big_to_cache; | 3430 | return nfserr_rep_too_big_to_cache; |
3431 | |||
3432 | return 0; | ||
3434 | } | 3433 | } |
3435 | 3434 | ||
3436 | void | 3435 | void |
@@ -3450,8 +3449,8 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) | |||
3450 | !nfsd4_enc_ops[op->opnum]); | 3449 | !nfsd4_enc_ops[op->opnum]); |
3451 | op->status = nfsd4_enc_ops[op->opnum](resp, op->status, &op->u); | 3450 | op->status = nfsd4_enc_ops[op->opnum](resp, op->status, &op->u); |
3452 | /* nfsd4_check_drc_limit guarantees enough room for error status */ | 3451 | /* nfsd4_check_drc_limit guarantees enough room for error status */ |
3453 | if (!op->status && nfsd4_check_drc_limit(resp)) | 3452 | if (!op->status) |
3454 | op->status = nfserr_rep_too_big_to_cache; | 3453 | op->status = nfsd4_check_resp_size(resp, 0); |
3455 | status: | 3454 | status: |
3456 | /* | 3455 | /* |
3457 | * Note: We write the status directly, instead of using WRITE32(), | 3456 | * Note: We write the status directly, instead of using WRITE32(), |
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index f95a72482064..a767b57b8208 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h | |||
@@ -524,6 +524,7 @@ int nfs4svc_decode_compoundargs(struct svc_rqst *, __be32 *, | |||
524 | struct nfsd4_compoundargs *); | 524 | struct nfsd4_compoundargs *); |
525 | int nfs4svc_encode_compoundres(struct svc_rqst *, __be32 *, | 525 | int nfs4svc_encode_compoundres(struct svc_rqst *, __be32 *, |
526 | struct nfsd4_compoundres *); | 526 | struct nfsd4_compoundres *); |
527 | int nfsd4_check_resp_size(struct nfsd4_compoundres *, u32); | ||
527 | void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *); | 528 | void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *); |
528 | void nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op); | 529 | void nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op); |
529 | __be32 nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | 530 | __be32 nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, |