diff options
Diffstat (limited to 'fs/nfsd/nfs4xdr.c')
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 324 |
1 files changed, 156 insertions, 168 deletions
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index fd548d155088..0dc11586682f 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -53,6 +53,7 @@ | |||
53 | #include "vfs.h" | 53 | #include "vfs.h" |
54 | #include "state.h" | 54 | #include "state.h" |
55 | #include "cache.h" | 55 | #include "cache.h" |
56 | #include "netns.h" | ||
56 | 57 | ||
57 | #define NFSDDBG_FACILITY NFSDDBG_XDR | 58 | #define NFSDDBG_FACILITY NFSDDBG_XDR |
58 | 59 | ||
@@ -65,17 +66,17 @@ | |||
65 | #define NFS4_REFERRAL_FSID_MINOR 0x8000000ULL | 66 | #define NFS4_REFERRAL_FSID_MINOR 0x8000000ULL |
66 | 67 | ||
67 | static __be32 | 68 | static __be32 |
68 | check_filename(char *str, int len, __be32 err) | 69 | check_filename(char *str, int len) |
69 | { | 70 | { |
70 | int i; | 71 | int i; |
71 | 72 | ||
72 | if (len == 0) | 73 | if (len == 0) |
73 | return nfserr_inval; | 74 | return nfserr_inval; |
74 | if (isdotent(str, len)) | 75 | if (isdotent(str, len)) |
75 | return err; | 76 | return nfserr_badname; |
76 | for (i = 0; i < len; i++) | 77 | for (i = 0; i < len; i++) |
77 | if (str[i] == '/') | 78 | if (str[i] == '/') |
78 | return err; | 79 | return nfserr_badname; |
79 | return 0; | 80 | return 0; |
80 | } | 81 | } |
81 | 82 | ||
@@ -422,6 +423,86 @@ nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access | |||
422 | DECODE_TAIL; | 423 | DECODE_TAIL; |
423 | } | 424 | } |
424 | 425 | ||
426 | static __be32 nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_cb_sec *cbs) | ||
427 | { | ||
428 | DECODE_HEAD; | ||
429 | u32 dummy, uid, gid; | ||
430 | char *machine_name; | ||
431 | int i; | ||
432 | int nr_secflavs; | ||
433 | |||
434 | /* callback_sec_params4 */ | ||
435 | READ_BUF(4); | ||
436 | READ32(nr_secflavs); | ||
437 | cbs->flavor = (u32)(-1); | ||
438 | for (i = 0; i < nr_secflavs; ++i) { | ||
439 | READ_BUF(4); | ||
440 | READ32(dummy); | ||
441 | switch (dummy) { | ||
442 | case RPC_AUTH_NULL: | ||
443 | /* Nothing to read */ | ||
444 | if (cbs->flavor == (u32)(-1)) | ||
445 | cbs->flavor = RPC_AUTH_NULL; | ||
446 | break; | ||
447 | case RPC_AUTH_UNIX: | ||
448 | READ_BUF(8); | ||
449 | /* stamp */ | ||
450 | READ32(dummy); | ||
451 | |||
452 | /* machine name */ | ||
453 | READ32(dummy); | ||
454 | READ_BUF(dummy); | ||
455 | SAVEMEM(machine_name, dummy); | ||
456 | |||
457 | /* uid, gid */ | ||
458 | READ_BUF(8); | ||
459 | READ32(uid); | ||
460 | READ32(gid); | ||
461 | |||
462 | /* more gids */ | ||
463 | READ_BUF(4); | ||
464 | READ32(dummy); | ||
465 | READ_BUF(dummy * 4); | ||
466 | if (cbs->flavor == (u32)(-1)) { | ||
467 | cbs->uid = uid; | ||
468 | cbs->gid = gid; | ||
469 | cbs->flavor = RPC_AUTH_UNIX; | ||
470 | } | ||
471 | break; | ||
472 | case RPC_AUTH_GSS: | ||
473 | dprintk("RPC_AUTH_GSS callback secflavor " | ||
474 | "not supported!\n"); | ||
475 | READ_BUF(8); | ||
476 | /* gcbp_service */ | ||
477 | READ32(dummy); | ||
478 | /* gcbp_handle_from_server */ | ||
479 | READ32(dummy); | ||
480 | READ_BUF(dummy); | ||
481 | p += XDR_QUADLEN(dummy); | ||
482 | /* gcbp_handle_from_client */ | ||
483 | READ_BUF(4); | ||
484 | READ32(dummy); | ||
485 | READ_BUF(dummy); | ||
486 | break; | ||
487 | default: | ||
488 | dprintk("Illegal callback secflavor\n"); | ||
489 | return nfserr_inval; | ||
490 | } | ||
491 | } | ||
492 | DECODE_TAIL; | ||
493 | } | ||
494 | |||
495 | static __be32 nfsd4_decode_backchannel_ctl(struct nfsd4_compoundargs *argp, struct nfsd4_backchannel_ctl *bc) | ||
496 | { | ||
497 | DECODE_HEAD; | ||
498 | |||
499 | READ_BUF(4); | ||
500 | READ32(bc->bc_cb_program); | ||
501 | nfsd4_decode_cb_sec(argp, &bc->bc_cb_sec); | ||
502 | |||
503 | DECODE_TAIL; | ||
504 | } | ||
505 | |||
425 | static __be32 nfsd4_decode_bind_conn_to_session(struct nfsd4_compoundargs *argp, struct nfsd4_bind_conn_to_session *bcts) | 506 | static __be32 nfsd4_decode_bind_conn_to_session(struct nfsd4_compoundargs *argp, struct nfsd4_bind_conn_to_session *bcts) |
426 | { | 507 | { |
427 | DECODE_HEAD; | 508 | DECODE_HEAD; |
@@ -490,7 +571,7 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create | |||
490 | READ32(create->cr_namelen); | 571 | READ32(create->cr_namelen); |
491 | READ_BUF(create->cr_namelen); | 572 | READ_BUF(create->cr_namelen); |
492 | SAVEMEM(create->cr_name, create->cr_namelen); | 573 | SAVEMEM(create->cr_name, create->cr_namelen); |
493 | if ((status = check_filename(create->cr_name, create->cr_namelen, nfserr_inval))) | 574 | if ((status = check_filename(create->cr_name, create->cr_namelen))) |
494 | return status; | 575 | return status; |
495 | 576 | ||
496 | status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr, | 577 | status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr, |
@@ -522,7 +603,7 @@ nfsd4_decode_link(struct nfsd4_compoundargs *argp, struct nfsd4_link *link) | |||
522 | READ32(link->li_namelen); | 603 | READ32(link->li_namelen); |
523 | READ_BUF(link->li_namelen); | 604 | READ_BUF(link->li_namelen); |
524 | SAVEMEM(link->li_name, link->li_namelen); | 605 | SAVEMEM(link->li_name, link->li_namelen); |
525 | if ((status = check_filename(link->li_name, link->li_namelen, nfserr_inval))) | 606 | if ((status = check_filename(link->li_name, link->li_namelen))) |
526 | return status; | 607 | return status; |
527 | 608 | ||
528 | DECODE_TAIL; | 609 | DECODE_TAIL; |
@@ -616,7 +697,7 @@ nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, struct nfsd4_lookup *lookup | |||
616 | READ32(lookup->lo_len); | 697 | READ32(lookup->lo_len); |
617 | READ_BUF(lookup->lo_len); | 698 | READ_BUF(lookup->lo_len); |
618 | SAVEMEM(lookup->lo_name, lookup->lo_len); | 699 | SAVEMEM(lookup->lo_name, lookup->lo_len); |
619 | if ((status = check_filename(lookup->lo_name, lookup->lo_len, nfserr_noent))) | 700 | if ((status = check_filename(lookup->lo_name, lookup->lo_len))) |
620 | return status; | 701 | return status; |
621 | 702 | ||
622 | DECODE_TAIL; | 703 | DECODE_TAIL; |
@@ -780,7 +861,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) | |||
780 | READ32(open->op_fname.len); | 861 | READ32(open->op_fname.len); |
781 | READ_BUF(open->op_fname.len); | 862 | READ_BUF(open->op_fname.len); |
782 | SAVEMEM(open->op_fname.data, open->op_fname.len); | 863 | SAVEMEM(open->op_fname.data, open->op_fname.len); |
783 | if ((status = check_filename(open->op_fname.data, open->op_fname.len, nfserr_inval))) | 864 | if ((status = check_filename(open->op_fname.data, open->op_fname.len))) |
784 | return status; | 865 | return status; |
785 | break; | 866 | break; |
786 | case NFS4_OPEN_CLAIM_PREVIOUS: | 867 | case NFS4_OPEN_CLAIM_PREVIOUS: |
@@ -795,7 +876,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) | |||
795 | READ32(open->op_fname.len); | 876 | READ32(open->op_fname.len); |
796 | READ_BUF(open->op_fname.len); | 877 | READ_BUF(open->op_fname.len); |
797 | SAVEMEM(open->op_fname.data, open->op_fname.len); | 878 | SAVEMEM(open->op_fname.data, open->op_fname.len); |
798 | if ((status = check_filename(open->op_fname.data, open->op_fname.len, nfserr_inval))) | 879 | if ((status = check_filename(open->op_fname.data, open->op_fname.len))) |
799 | return status; | 880 | return status; |
800 | break; | 881 | break; |
801 | case NFS4_OPEN_CLAIM_FH: | 882 | case NFS4_OPEN_CLAIM_FH: |
@@ -907,7 +988,7 @@ nfsd4_decode_remove(struct nfsd4_compoundargs *argp, struct nfsd4_remove *remove | |||
907 | READ32(remove->rm_namelen); | 988 | READ32(remove->rm_namelen); |
908 | READ_BUF(remove->rm_namelen); | 989 | READ_BUF(remove->rm_namelen); |
909 | SAVEMEM(remove->rm_name, remove->rm_namelen); | 990 | SAVEMEM(remove->rm_name, remove->rm_namelen); |
910 | if ((status = check_filename(remove->rm_name, remove->rm_namelen, nfserr_noent))) | 991 | if ((status = check_filename(remove->rm_name, remove->rm_namelen))) |
911 | return status; | 992 | return status; |
912 | 993 | ||
913 | DECODE_TAIL; | 994 | DECODE_TAIL; |
@@ -925,9 +1006,9 @@ nfsd4_decode_rename(struct nfsd4_compoundargs *argp, struct nfsd4_rename *rename | |||
925 | READ32(rename->rn_tnamelen); | 1006 | READ32(rename->rn_tnamelen); |
926 | READ_BUF(rename->rn_tnamelen); | 1007 | READ_BUF(rename->rn_tnamelen); |
927 | SAVEMEM(rename->rn_tname, rename->rn_tnamelen); | 1008 | SAVEMEM(rename->rn_tname, rename->rn_tnamelen); |
928 | if ((status = check_filename(rename->rn_sname, rename->rn_snamelen, nfserr_noent))) | 1009 | if ((status = check_filename(rename->rn_sname, rename->rn_snamelen))) |
929 | return status; | 1010 | return status; |
930 | if ((status = check_filename(rename->rn_tname, rename->rn_tnamelen, nfserr_inval))) | 1011 | if ((status = check_filename(rename->rn_tname, rename->rn_tnamelen))) |
931 | return status; | 1012 | return status; |
932 | 1013 | ||
933 | DECODE_TAIL; | 1014 | DECODE_TAIL; |
@@ -954,8 +1035,7 @@ nfsd4_decode_secinfo(struct nfsd4_compoundargs *argp, | |||
954 | READ32(secinfo->si_namelen); | 1035 | READ32(secinfo->si_namelen); |
955 | READ_BUF(secinfo->si_namelen); | 1036 | READ_BUF(secinfo->si_namelen); |
956 | SAVEMEM(secinfo->si_name, secinfo->si_namelen); | 1037 | SAVEMEM(secinfo->si_name, secinfo->si_namelen); |
957 | status = check_filename(secinfo->si_name, secinfo->si_namelen, | 1038 | status = check_filename(secinfo->si_name, secinfo->si_namelen); |
958 | nfserr_noent); | ||
959 | if (status) | 1039 | if (status) |
960 | return status; | 1040 | return status; |
961 | DECODE_TAIL; | 1041 | DECODE_TAIL; |
@@ -1026,31 +1106,14 @@ nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_s | |||
1026 | static __be32 | 1106 | static __be32 |
1027 | nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify) | 1107 | nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify) |
1028 | { | 1108 | { |
1029 | #if 0 | ||
1030 | struct nfsd4_compoundargs save = { | ||
1031 | .p = argp->p, | ||
1032 | .end = argp->end, | ||
1033 | .rqstp = argp->rqstp, | ||
1034 | }; | ||
1035 | u32 ve_bmval[2]; | ||
1036 | struct iattr ve_iattr; /* request */ | ||
1037 | struct nfs4_acl *ve_acl; /* request */ | ||
1038 | #endif | ||
1039 | DECODE_HEAD; | 1109 | DECODE_HEAD; |
1040 | 1110 | ||
1041 | if ((status = nfsd4_decode_bitmap(argp, verify->ve_bmval))) | 1111 | if ((status = nfsd4_decode_bitmap(argp, verify->ve_bmval))) |
1042 | goto out; | 1112 | goto out; |
1043 | 1113 | ||
1044 | /* For convenience's sake, we compare raw xdr'd attributes in | 1114 | /* For convenience's sake, we compare raw xdr'd attributes in |
1045 | * nfsd4_proc_verify; however we still decode here just to return | 1115 | * nfsd4_proc_verify */ |
1046 | * correct error in case of bad xdr. */ | 1116 | |
1047 | #if 0 | ||
1048 | status = nfsd4_decode_fattr(ve_bmval, &ve_iattr, &ve_acl); | ||
1049 | if (status == nfserr_inval) { | ||
1050 | status = nfserrno(status); | ||
1051 | goto out; | ||
1052 | } | ||
1053 | #endif | ||
1054 | READ_BUF(4); | 1117 | READ_BUF(4); |
1055 | READ32(verify->ve_attrlen); | 1118 | READ32(verify->ve_attrlen); |
1056 | READ_BUF(verify->ve_attrlen); | 1119 | READ_BUF(verify->ve_attrlen); |
@@ -1063,7 +1126,6 @@ static __be32 | |||
1063 | nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) | 1126 | nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) |
1064 | { | 1127 | { |
1065 | int avail; | 1128 | int avail; |
1066 | int v; | ||
1067 | int len; | 1129 | int len; |
1068 | DECODE_HEAD; | 1130 | DECODE_HEAD; |
1069 | 1131 | ||
@@ -1087,27 +1149,26 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) | |||
1087 | __FILE__, __LINE__); | 1149 | __FILE__, __LINE__); |
1088 | goto xdr_error; | 1150 | goto xdr_error; |
1089 | } | 1151 | } |
1090 | argp->rqstp->rq_vec[0].iov_base = p; | 1152 | write->wr_head.iov_base = p; |
1091 | argp->rqstp->rq_vec[0].iov_len = avail; | 1153 | write->wr_head.iov_len = avail; |
1092 | v = 0; | 1154 | WARN_ON(avail != (XDR_QUADLEN(avail) << 2)); |
1093 | len = write->wr_buflen; | 1155 | write->wr_pagelist = argp->pagelist; |
1094 | while (len > argp->rqstp->rq_vec[v].iov_len) { | 1156 | |
1095 | len -= argp->rqstp->rq_vec[v].iov_len; | 1157 | len = XDR_QUADLEN(write->wr_buflen) << 2; |
1096 | v++; | 1158 | if (len >= avail) { |
1097 | argp->rqstp->rq_vec[v].iov_base = page_address(argp->pagelist[0]); | 1159 | int pages; |
1098 | argp->pagelist++; | 1160 | |
1099 | if (argp->pagelen >= PAGE_SIZE) { | 1161 | len -= avail; |
1100 | argp->rqstp->rq_vec[v].iov_len = PAGE_SIZE; | 1162 | |
1101 | argp->pagelen -= PAGE_SIZE; | 1163 | pages = len >> PAGE_SHIFT; |
1102 | } else { | 1164 | argp->pagelist += pages; |
1103 | argp->rqstp->rq_vec[v].iov_len = argp->pagelen; | 1165 | argp->pagelen -= pages * PAGE_SIZE; |
1104 | argp->pagelen -= len; | 1166 | len -= pages * PAGE_SIZE; |
1105 | } | 1167 | |
1168 | argp->p = (__be32 *)page_address(argp->pagelist[0]); | ||
1169 | argp->end = argp->p + XDR_QUADLEN(PAGE_SIZE); | ||
1106 | } | 1170 | } |
1107 | argp->end = (__be32*) (argp->rqstp->rq_vec[v].iov_base + argp->rqstp->rq_vec[v].iov_len); | 1171 | argp->p += XDR_QUADLEN(len); |
1108 | argp->p = (__be32*) (argp->rqstp->rq_vec[v].iov_base + (XDR_QUADLEN(len) << 2)); | ||
1109 | argp->rqstp->rq_vec[v].iov_len = len; | ||
1110 | write->wr_vlen = v+1; | ||
1111 | 1172 | ||
1112 | DECODE_TAIL; | 1173 | DECODE_TAIL; |
1113 | } | 1174 | } |
@@ -1237,11 +1298,7 @@ nfsd4_decode_create_session(struct nfsd4_compoundargs *argp, | |||
1237 | struct nfsd4_create_session *sess) | 1298 | struct nfsd4_create_session *sess) |
1238 | { | 1299 | { |
1239 | DECODE_HEAD; | 1300 | DECODE_HEAD; |
1240 | |||
1241 | u32 dummy; | 1301 | u32 dummy; |
1242 | char *machine_name; | ||
1243 | int i; | ||
1244 | int nr_secflavs; | ||
1245 | 1302 | ||
1246 | READ_BUF(16); | 1303 | READ_BUF(16); |
1247 | COPYMEM(&sess->clientid, 8); | 1304 | COPYMEM(&sess->clientid, 8); |
@@ -1282,58 +1339,9 @@ nfsd4_decode_create_session(struct nfsd4_compoundargs *argp, | |||
1282 | goto xdr_error; | 1339 | goto xdr_error; |
1283 | } | 1340 | } |
1284 | 1341 | ||
1285 | READ_BUF(8); | 1342 | READ_BUF(4); |
1286 | READ32(sess->callback_prog); | 1343 | READ32(sess->callback_prog); |
1287 | 1344 | nfsd4_decode_cb_sec(argp, &sess->cb_sec); | |
1288 | /* callback_sec_params4 */ | ||
1289 | READ32(nr_secflavs); | ||
1290 | for (i = 0; i < nr_secflavs; ++i) { | ||
1291 | READ_BUF(4); | ||
1292 | READ32(dummy); | ||
1293 | switch (dummy) { | ||
1294 | case RPC_AUTH_NULL: | ||
1295 | /* Nothing to read */ | ||
1296 | break; | ||
1297 | case RPC_AUTH_UNIX: | ||
1298 | READ_BUF(8); | ||
1299 | /* stamp */ | ||
1300 | READ32(dummy); | ||
1301 | |||
1302 | /* machine name */ | ||
1303 | READ32(dummy); | ||
1304 | READ_BUF(dummy); | ||
1305 | SAVEMEM(machine_name, dummy); | ||
1306 | |||
1307 | /* uid, gid */ | ||
1308 | READ_BUF(8); | ||
1309 | READ32(sess->uid); | ||
1310 | READ32(sess->gid); | ||
1311 | |||
1312 | /* more gids */ | ||
1313 | READ_BUF(4); | ||
1314 | READ32(dummy); | ||
1315 | READ_BUF(dummy * 4); | ||
1316 | break; | ||
1317 | case RPC_AUTH_GSS: | ||
1318 | dprintk("RPC_AUTH_GSS callback secflavor " | ||
1319 | "not supported!\n"); | ||
1320 | READ_BUF(8); | ||
1321 | /* gcbp_service */ | ||
1322 | READ32(dummy); | ||
1323 | /* gcbp_handle_from_server */ | ||
1324 | READ32(dummy); | ||
1325 | READ_BUF(dummy); | ||
1326 | p += XDR_QUADLEN(dummy); | ||
1327 | /* gcbp_handle_from_client */ | ||
1328 | READ_BUF(4); | ||
1329 | READ32(dummy); | ||
1330 | READ_BUF(dummy); | ||
1331 | break; | ||
1332 | default: | ||
1333 | dprintk("Illegal callback secflavor\n"); | ||
1334 | return nfserr_inval; | ||
1335 | } | ||
1336 | } | ||
1337 | DECODE_TAIL; | 1345 | DECODE_TAIL; |
1338 | } | 1346 | } |
1339 | 1347 | ||
@@ -1528,7 +1536,7 @@ static nfsd4_dec nfsd41_dec_ops[] = { | |||
1528 | [OP_RELEASE_LOCKOWNER] = (nfsd4_dec)nfsd4_decode_notsupp, | 1536 | [OP_RELEASE_LOCKOWNER] = (nfsd4_dec)nfsd4_decode_notsupp, |
1529 | 1537 | ||
1530 | /* new operations for NFSv4.1 */ | 1538 | /* new operations for NFSv4.1 */ |
1531 | [OP_BACKCHANNEL_CTL] = (nfsd4_dec)nfsd4_decode_notsupp, | 1539 | [OP_BACKCHANNEL_CTL] = (nfsd4_dec)nfsd4_decode_backchannel_ctl, |
1532 | [OP_BIND_CONN_TO_SESSION]= (nfsd4_dec)nfsd4_decode_bind_conn_to_session, | 1540 | [OP_BIND_CONN_TO_SESSION]= (nfsd4_dec)nfsd4_decode_bind_conn_to_session, |
1533 | [OP_EXCHANGE_ID] = (nfsd4_dec)nfsd4_decode_exchange_id, | 1541 | [OP_EXCHANGE_ID] = (nfsd4_dec)nfsd4_decode_exchange_id, |
1534 | [OP_CREATE_SESSION] = (nfsd4_dec)nfsd4_decode_create_session, | 1542 | [OP_CREATE_SESSION] = (nfsd4_dec)nfsd4_decode_create_session, |
@@ -1568,12 +1576,6 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) | |||
1568 | bool cachethis = false; | 1576 | bool cachethis = false; |
1569 | int i; | 1577 | int i; |
1570 | 1578 | ||
1571 | /* | ||
1572 | * XXX: According to spec, we should check the tag | ||
1573 | * for UTF-8 compliance. I'm postponing this for | ||
1574 | * now because it seems that some clients do use | ||
1575 | * binary tags. | ||
1576 | */ | ||
1577 | READ_BUF(4); | 1579 | READ_BUF(4); |
1578 | READ32(argp->taglen); | 1580 | READ32(argp->taglen); |
1579 | READ_BUF(argp->taglen + 8); | 1581 | READ_BUF(argp->taglen + 8); |
@@ -1603,38 +1605,8 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) | |||
1603 | op = &argp->ops[i]; | 1605 | op = &argp->ops[i]; |
1604 | op->replay = NULL; | 1606 | op->replay = NULL; |
1605 | 1607 | ||
1606 | /* | 1608 | READ_BUF(4); |
1607 | * We can't use READ_BUF() here because we need to handle | 1609 | READ32(op->opnum); |
1608 | * a missing opcode as an OP_WRITE + 1. So we need to check | ||
1609 | * to see if we're truly at the end of our buffer or if there | ||
1610 | * is another page we need to flip to. | ||
1611 | */ | ||
1612 | |||
1613 | if (argp->p == argp->end) { | ||
1614 | if (argp->pagelen < 4) { | ||
1615 | /* There isn't an opcode still on the wire */ | ||
1616 | op->opnum = OP_WRITE + 1; | ||
1617 | op->status = nfserr_bad_xdr; | ||
1618 | argp->opcnt = i+1; | ||
1619 | break; | ||
1620 | } | ||
1621 | |||
1622 | /* | ||
1623 | * False alarm. We just hit a page boundary, but there | ||
1624 | * is still data available. Move pointer across page | ||
1625 | * boundary. *snip from READ_BUF* | ||
1626 | */ | ||
1627 | argp->p = page_address(argp->pagelist[0]); | ||
1628 | argp->pagelist++; | ||
1629 | if (argp->pagelen < PAGE_SIZE) { | ||
1630 | argp->end = argp->p + (argp->pagelen>>2); | ||
1631 | argp->pagelen = 0; | ||
1632 | } else { | ||
1633 | argp->end = argp->p + (PAGE_SIZE>>2); | ||
1634 | argp->pagelen -= PAGE_SIZE; | ||
1635 | } | ||
1636 | } | ||
1637 | op->opnum = ntohl(*argp->p++); | ||
1638 | 1610 | ||
1639 | if (op->opnum >= FIRST_NFS4_OP && op->opnum <= LAST_NFS4_OP) | 1611 | if (op->opnum >= FIRST_NFS4_OP && op->opnum <= LAST_NFS4_OP) |
1640 | op->status = ops->decoders[op->opnum](argp, &op->u); | 1612 | op->status = ops->decoders[op->opnum](argp, &op->u); |
@@ -2014,6 +1986,22 @@ static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err) | |||
2014 | return 0; | 1986 | return 0; |
2015 | } | 1987 | } |
2016 | 1988 | ||
1989 | |||
1990 | static int get_parent_attributes(struct svc_export *exp, struct kstat *stat) | ||
1991 | { | ||
1992 | struct path path = exp->ex_path; | ||
1993 | int err; | ||
1994 | |||
1995 | path_get(&path); | ||
1996 | while (follow_up(&path)) { | ||
1997 | if (path.dentry != path.mnt->mnt_root) | ||
1998 | break; | ||
1999 | } | ||
2000 | err = vfs_getattr(path.mnt, path.dentry, stat); | ||
2001 | path_put(&path); | ||
2002 | return err; | ||
2003 | } | ||
2004 | |||
2017 | /* | 2005 | /* |
2018 | * Note: @fhp can be NULL; in this case, we might have to compose the filehandle | 2006 | * Note: @fhp can be NULL; in this case, we might have to compose the filehandle |
2019 | * ourselves. | 2007 | * ourselves. |
@@ -2048,6 +2036,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | |||
2048 | .mnt = exp->ex_path.mnt, | 2036 | .mnt = exp->ex_path.mnt, |
2049 | .dentry = dentry, | 2037 | .dentry = dentry, |
2050 | }; | 2038 | }; |
2039 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
2051 | 2040 | ||
2052 | BUG_ON(bmval1 & NFSD_WRITEONLY_ATTRS_WORD1); | 2041 | BUG_ON(bmval1 & NFSD_WRITEONLY_ATTRS_WORD1); |
2053 | BUG_ON(bmval0 & ~nfsd_suppattrs0(minorversion)); | 2042 | BUG_ON(bmval0 & ~nfsd_suppattrs0(minorversion)); |
@@ -2208,7 +2197,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | |||
2208 | if (bmval0 & FATTR4_WORD0_LEASE_TIME) { | 2197 | if (bmval0 & FATTR4_WORD0_LEASE_TIME) { |
2209 | if ((buflen -= 4) < 0) | 2198 | if ((buflen -= 4) < 0) |
2210 | goto out_resource; | 2199 | goto out_resource; |
2211 | WRITE32(nfsd4_lease); | 2200 | WRITE32(nn->nfsd4_lease); |
2212 | } | 2201 | } |
2213 | if (bmval0 & FATTR4_WORD0_RDATTR_ERROR) { | 2202 | if (bmval0 & FATTR4_WORD0_RDATTR_ERROR) { |
2214 | if ((buflen -= 4) < 0) | 2203 | if ((buflen -= 4) < 0) |
@@ -2430,18 +2419,8 @@ out_acl: | |||
2430 | * and this is the root of a cross-mounted filesystem. | 2419 | * and this is the root of a cross-mounted filesystem. |
2431 | */ | 2420 | */ |
2432 | if (ignore_crossmnt == 0 && | 2421 | if (ignore_crossmnt == 0 && |
2433 | dentry == exp->ex_path.mnt->mnt_root) { | 2422 | dentry == exp->ex_path.mnt->mnt_root) |
2434 | struct path path = exp->ex_path; | 2423 | get_parent_attributes(exp, &stat); |
2435 | path_get(&path); | ||
2436 | while (follow_up(&path)) { | ||
2437 | if (path.dentry != path.mnt->mnt_root) | ||
2438 | break; | ||
2439 | } | ||
2440 | err = vfs_getattr(path.mnt, path.dentry, &stat); | ||
2441 | path_put(&path); | ||
2442 | if (err) | ||
2443 | goto out_nfserr; | ||
2444 | } | ||
2445 | WRITE64(stat.ino); | 2424 | WRITE64(stat.ino); |
2446 | } | 2425 | } |
2447 | if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) { | 2426 | if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) { |
@@ -2927,7 +2906,8 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, | |||
2927 | struct nfsd4_read *read) | 2906 | struct nfsd4_read *read) |
2928 | { | 2907 | { |
2929 | u32 eof; | 2908 | u32 eof; |
2930 | int v, pn; | 2909 | int v; |
2910 | struct page *page; | ||
2931 | unsigned long maxcount; | 2911 | unsigned long maxcount; |
2932 | long len; | 2912 | long len; |
2933 | __be32 *p; | 2913 | __be32 *p; |
@@ -2946,11 +2926,15 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, | |||
2946 | len = maxcount; | 2926 | len = maxcount; |
2947 | v = 0; | 2927 | v = 0; |
2948 | while (len > 0) { | 2928 | while (len > 0) { |
2949 | pn = resp->rqstp->rq_resused++; | 2929 | page = *(resp->rqstp->rq_next_page); |
2950 | resp->rqstp->rq_vec[v].iov_base = | 2930 | if (!page) { /* ran out of pages */ |
2951 | page_address(resp->rqstp->rq_respages[pn]); | 2931 | maxcount -= len; |
2932 | break; | ||
2933 | } | ||
2934 | resp->rqstp->rq_vec[v].iov_base = page_address(page); | ||
2952 | resp->rqstp->rq_vec[v].iov_len = | 2935 | resp->rqstp->rq_vec[v].iov_len = |
2953 | len < PAGE_SIZE ? len : PAGE_SIZE; | 2936 | len < PAGE_SIZE ? len : PAGE_SIZE; |
2937 | resp->rqstp->rq_next_page++; | ||
2954 | v++; | 2938 | v++; |
2955 | len -= PAGE_SIZE; | 2939 | len -= PAGE_SIZE; |
2956 | } | 2940 | } |
@@ -2996,8 +2980,10 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd | |||
2996 | return nfserr; | 2980 | return nfserr; |
2997 | if (resp->xbuf->page_len) | 2981 | if (resp->xbuf->page_len) |
2998 | return nfserr_resource; | 2982 | return nfserr_resource; |
2983 | if (!*resp->rqstp->rq_next_page) | ||
2984 | return nfserr_resource; | ||
2999 | 2985 | ||
3000 | page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused++]); | 2986 | page = page_address(*(resp->rqstp->rq_next_page++)); |
3001 | 2987 | ||
3002 | maxcount = PAGE_SIZE; | 2988 | maxcount = PAGE_SIZE; |
3003 | RESERVE_SPACE(4); | 2989 | RESERVE_SPACE(4); |
@@ -3045,6 +3031,8 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 | |||
3045 | return nfserr; | 3031 | return nfserr; |
3046 | if (resp->xbuf->page_len) | 3032 | if (resp->xbuf->page_len) |
3047 | return nfserr_resource; | 3033 | return nfserr_resource; |
3034 | if (!*resp->rqstp->rq_next_page) | ||
3035 | return nfserr_resource; | ||
3048 | 3036 | ||
3049 | RESERVE_SPACE(NFS4_VERIFIER_SIZE); | 3037 | RESERVE_SPACE(NFS4_VERIFIER_SIZE); |
3050 | savep = p; | 3038 | savep = p; |
@@ -3071,7 +3059,7 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 | |||
3071 | goto err_no_verf; | 3059 | goto err_no_verf; |
3072 | } | 3060 | } |
3073 | 3061 | ||
3074 | page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused++]); | 3062 | page = page_address(*(resp->rqstp->rq_next_page++)); |
3075 | readdir->common.err = 0; | 3063 | readdir->common.err = 0; |
3076 | readdir->buflen = maxcount; | 3064 | readdir->buflen = maxcount; |
3077 | readdir->buffer = page; | 3065 | readdir->buffer = page; |
@@ -3094,8 +3082,8 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 | |||
3094 | p = readdir->buffer; | 3082 | p = readdir->buffer; |
3095 | *p++ = 0; /* no more entries */ | 3083 | *p++ = 0; /* no more entries */ |
3096 | *p++ = htonl(readdir->common.err == nfserr_eof); | 3084 | *p++ = htonl(readdir->common.err == nfserr_eof); |
3097 | resp->xbuf->page_len = ((char*)p) - (char*)page_address( | 3085 | resp->xbuf->page_len = ((char*)p) - |
3098 | resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]); | 3086 | (char*)page_address(*(resp->rqstp->rq_next_page-1)); |
3099 | 3087 | ||
3100 | /* Use rest of head for padding and remaining ops: */ | 3088 | /* Use rest of head for padding and remaining ops: */ |
3101 | resp->xbuf->tail[0].iov_base = tailbase; | 3089 | resp->xbuf->tail[0].iov_base = tailbase; |