diff options
Diffstat (limited to 'fs/nfsd/nfs4state.c')
| -rw-r--r-- | fs/nfsd/nfs4state.c | 538 |
1 files changed, 251 insertions, 287 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 7f71c69cdcdf..8fdc9ec5c5d3 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
| @@ -42,6 +42,7 @@ | |||
| 42 | #include <linux/sunrpc/clnt.h> | 42 | #include <linux/sunrpc/clnt.h> |
| 43 | #include "xdr4.h" | 43 | #include "xdr4.h" |
| 44 | #include "vfs.h" | 44 | #include "vfs.h" |
| 45 | #include "current_stateid.h" | ||
| 45 | 46 | ||
| 46 | #define NFSDDBG_FACILITY NFSDDBG_PROC | 47 | #define NFSDDBG_FACILITY NFSDDBG_PROC |
| 47 | 48 | ||
| @@ -447,37 +448,69 @@ static struct list_head close_lru; | |||
| 447 | * | 448 | * |
| 448 | * which we should reject. | 449 | * which we should reject. |
| 449 | */ | 450 | */ |
| 450 | static void | 451 | static unsigned int |
| 451 | set_access(unsigned int *access, unsigned long bmap) { | 452 | bmap_to_share_mode(unsigned long bmap) { |
| 452 | int i; | 453 | int i; |
| 454 | unsigned int access = 0; | ||
| 453 | 455 | ||
| 454 | *access = 0; | ||
| 455 | for (i = 1; i < 4; i++) { | 456 | for (i = 1; i < 4; i++) { |
| 456 | if (test_bit(i, &bmap)) | 457 | if (test_bit(i, &bmap)) |
| 457 | *access |= i; | 458 | access |= i; |
| 458 | } | ||
| 459 | } | ||
| 460 | |||
| 461 | static void | ||
| 462 | set_deny(unsigned int *deny, unsigned long bmap) { | ||
| 463 | int i; | ||
| 464 | |||
| 465 | *deny = 0; | ||
| 466 | for (i = 0; i < 4; i++) { | ||
| 467 | if (test_bit(i, &bmap)) | ||
| 468 | *deny |= i ; | ||
| 469 | } | 459 | } |
| 460 | return access; | ||
| 470 | } | 461 | } |
| 471 | 462 | ||
| 472 | static int | 463 | static bool |
| 473 | test_share(struct nfs4_ol_stateid *stp, struct nfsd4_open *open) { | 464 | test_share(struct nfs4_ol_stateid *stp, struct nfsd4_open *open) { |
| 474 | unsigned int access, deny; | 465 | unsigned int access, deny; |
| 475 | 466 | ||
| 476 | set_access(&access, stp->st_access_bmap); | 467 | access = bmap_to_share_mode(stp->st_access_bmap); |
| 477 | set_deny(&deny, stp->st_deny_bmap); | 468 | deny = bmap_to_share_mode(stp->st_deny_bmap); |
| 478 | if ((access & open->op_share_deny) || (deny & open->op_share_access)) | 469 | if ((access & open->op_share_deny) || (deny & open->op_share_access)) |
| 479 | return 0; | 470 | return false; |
| 480 | return 1; | 471 | return true; |
| 472 | } | ||
| 473 | |||
| 474 | /* set share access for a given stateid */ | ||
| 475 | static inline void | ||
| 476 | set_access(u32 access, struct nfs4_ol_stateid *stp) | ||
| 477 | { | ||
| 478 | __set_bit(access, &stp->st_access_bmap); | ||
| 479 | } | ||
| 480 | |||
| 481 | /* clear share access for a given stateid */ | ||
| 482 | static inline void | ||
| 483 | clear_access(u32 access, struct nfs4_ol_stateid *stp) | ||
| 484 | { | ||
| 485 | __clear_bit(access, &stp->st_access_bmap); | ||
| 486 | } | ||
| 487 | |||
| 488 | /* test whether a given stateid has access */ | ||
| 489 | static inline bool | ||
| 490 | test_access(u32 access, struct nfs4_ol_stateid *stp) | ||
| 491 | { | ||
| 492 | return test_bit(access, &stp->st_access_bmap); | ||
| 493 | } | ||
| 494 | |||
| 495 | /* set share deny for a given stateid */ | ||
| 496 | static inline void | ||
| 497 | set_deny(u32 access, struct nfs4_ol_stateid *stp) | ||
| 498 | { | ||
| 499 | __set_bit(access, &stp->st_deny_bmap); | ||
| 500 | } | ||
| 501 | |||
| 502 | /* clear share deny for a given stateid */ | ||
| 503 | static inline void | ||
| 504 | clear_deny(u32 access, struct nfs4_ol_stateid *stp) | ||
| 505 | { | ||
| 506 | __clear_bit(access, &stp->st_deny_bmap); | ||
| 507 | } | ||
| 508 | |||
| 509 | /* test whether a given stateid is denying specific access */ | ||
| 510 | static inline bool | ||
| 511 | test_deny(u32 access, struct nfs4_ol_stateid *stp) | ||
| 512 | { | ||
| 513 | return test_bit(access, &stp->st_deny_bmap); | ||
| 481 | } | 514 | } |
| 482 | 515 | ||
| 483 | static int nfs4_access_to_omode(u32 access) | 516 | static int nfs4_access_to_omode(u32 access) |
| @@ -493,6 +526,20 @@ static int nfs4_access_to_omode(u32 access) | |||
| 493 | BUG(); | 526 | BUG(); |
| 494 | } | 527 | } |
| 495 | 528 | ||
| 529 | /* release all access and file references for a given stateid */ | ||
| 530 | static void | ||
| 531 | release_all_access(struct nfs4_ol_stateid *stp) | ||
| 532 | { | ||
| 533 | int i; | ||
| 534 | |||
| 535 | for (i = 1; i < 4; i++) { | ||
| 536 | if (test_access(i, stp)) | ||
| 537 | nfs4_file_put_access(stp->st_file, | ||
| 538 | nfs4_access_to_omode(i)); | ||
| 539 | clear_access(i, stp); | ||
| 540 | } | ||
| 541 | } | ||
| 542 | |||
| 496 | static void unhash_generic_stateid(struct nfs4_ol_stateid *stp) | 543 | static void unhash_generic_stateid(struct nfs4_ol_stateid *stp) |
| 497 | { | 544 | { |
| 498 | list_del(&stp->st_perfile); | 545 | list_del(&stp->st_perfile); |
| @@ -501,16 +548,7 @@ static void unhash_generic_stateid(struct nfs4_ol_stateid *stp) | |||
| 501 | 548 | ||
| 502 | static void close_generic_stateid(struct nfs4_ol_stateid *stp) | 549 | static void close_generic_stateid(struct nfs4_ol_stateid *stp) |
| 503 | { | 550 | { |
| 504 | int i; | 551 | release_all_access(stp); |
| 505 | |||
| 506 | if (stp->st_access_bmap) { | ||
| 507 | for (i = 1; i < 4; i++) { | ||
| 508 | if (test_bit(i, &stp->st_access_bmap)) | ||
| 509 | nfs4_file_put_access(stp->st_file, | ||
| 510 | nfs4_access_to_omode(i)); | ||
| 511 | __clear_bit(i, &stp->st_access_bmap); | ||
| 512 | } | ||
| 513 | } | ||
| 514 | put_nfs4_file(stp->st_file); | 552 | put_nfs4_file(stp->st_file); |
| 515 | stp->st_file = NULL; | 553 | stp->st_file = NULL; |
| 516 | } | 554 | } |
| @@ -885,7 +923,7 @@ static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct n | |||
| 885 | struct nfsd4_session *new; | 923 | struct nfsd4_session *new; |
| 886 | struct nfsd4_channel_attrs *fchan = &cses->fore_channel; | 924 | struct nfsd4_channel_attrs *fchan = &cses->fore_channel; |
| 887 | int numslots, slotsize; | 925 | int numslots, slotsize; |
| 888 | int status; | 926 | __be32 status; |
| 889 | int idx; | 927 | int idx; |
| 890 | 928 | ||
| 891 | /* | 929 | /* |
| @@ -984,7 +1022,8 @@ static inline void | |||
| 984 | renew_client_locked(struct nfs4_client *clp) | 1022 | renew_client_locked(struct nfs4_client *clp) |
| 985 | { | 1023 | { |
| 986 | if (is_client_expired(clp)) { | 1024 | if (is_client_expired(clp)) { |
| 987 | dprintk("%s: client (clientid %08x/%08x) already expired\n", | 1025 | WARN_ON(1); |
| 1026 | printk("%s: client (clientid %08x/%08x) already expired\n", | ||
| 988 | __func__, | 1027 | __func__, |
| 989 | clp->cl_clientid.cl_boot, | 1028 | clp->cl_clientid.cl_boot, |
| 990 | clp->cl_clientid.cl_id); | 1029 | clp->cl_clientid.cl_id); |
| @@ -1049,9 +1088,7 @@ free_client(struct nfs4_client *clp) | |||
| 1049 | list_del(&ses->se_perclnt); | 1088 | list_del(&ses->se_perclnt); |
| 1050 | nfsd4_put_session_locked(ses); | 1089 | nfsd4_put_session_locked(ses); |
| 1051 | } | 1090 | } |
| 1052 | if (clp->cl_cred.cr_group_info) | 1091 | free_svc_cred(&clp->cl_cred); |
| 1053 | put_group_info(clp->cl_cred.cr_group_info); | ||
| 1054 | kfree(clp->cl_principal); | ||
| 1055 | kfree(clp->cl_name.data); | 1092 | kfree(clp->cl_name.data); |
| 1056 | kfree(clp); | 1093 | kfree(clp); |
| 1057 | } | 1094 | } |
| @@ -1132,12 +1169,21 @@ static void copy_clid(struct nfs4_client *target, struct nfs4_client *source) | |||
| 1132 | target->cl_clientid.cl_id = source->cl_clientid.cl_id; | 1169 | target->cl_clientid.cl_id = source->cl_clientid.cl_id; |
| 1133 | } | 1170 | } |
| 1134 | 1171 | ||
| 1135 | static void copy_cred(struct svc_cred *target, struct svc_cred *source) | 1172 | static int copy_cred(struct svc_cred *target, struct svc_cred *source) |
| 1136 | { | 1173 | { |
| 1174 | if (source->cr_principal) { | ||
| 1175 | target->cr_principal = | ||
| 1176 | kstrdup(source->cr_principal, GFP_KERNEL); | ||
| 1177 | if (target->cr_principal == NULL) | ||
| 1178 | return -ENOMEM; | ||
| 1179 | } else | ||
| 1180 | target->cr_principal = NULL; | ||
| 1181 | target->cr_flavor = source->cr_flavor; | ||
| 1137 | target->cr_uid = source->cr_uid; | 1182 | target->cr_uid = source->cr_uid; |
| 1138 | target->cr_gid = source->cr_gid; | 1183 | target->cr_gid = source->cr_gid; |
| 1139 | target->cr_group_info = source->cr_group_info; | 1184 | target->cr_group_info = source->cr_group_info; |
| 1140 | get_group_info(target->cr_group_info); | 1185 | get_group_info(target->cr_group_info); |
| 1186 | return 0; | ||
| 1141 | } | 1187 | } |
| 1142 | 1188 | ||
| 1143 | static int same_name(const char *n1, const char *n2) | 1189 | static int same_name(const char *n1, const char *n2) |
| @@ -1157,11 +1203,31 @@ same_clid(clientid_t *cl1, clientid_t *cl2) | |||
| 1157 | return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id); | 1203 | return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id); |
| 1158 | } | 1204 | } |
| 1159 | 1205 | ||
| 1160 | /* XXX what about NGROUP */ | 1206 | static bool groups_equal(struct group_info *g1, struct group_info *g2) |
| 1207 | { | ||
| 1208 | int i; | ||
| 1209 | |||
| 1210 | if (g1->ngroups != g2->ngroups) | ||
| 1211 | return false; | ||
| 1212 | for (i=0; i<g1->ngroups; i++) | ||
| 1213 | if (GROUP_AT(g1, i) != GROUP_AT(g2, i)) | ||
| 1214 | return false; | ||
| 1215 | return true; | ||
| 1216 | } | ||
| 1217 | |||
| 1161 | static int | 1218 | static int |
| 1162 | same_creds(struct svc_cred *cr1, struct svc_cred *cr2) | 1219 | same_creds(struct svc_cred *cr1, struct svc_cred *cr2) |
| 1163 | { | 1220 | { |
| 1164 | return cr1->cr_uid == cr2->cr_uid; | 1221 | if ((cr1->cr_flavor != cr2->cr_flavor) |
| 1222 | || (cr1->cr_uid != cr2->cr_uid) | ||
| 1223 | || (cr1->cr_gid != cr2->cr_gid) | ||
| 1224 | || !groups_equal(cr1->cr_group_info, cr2->cr_group_info)) | ||
| 1225 | return false; | ||
| 1226 | if (cr1->cr_principal == cr2->cr_principal) | ||
| 1227 | return true; | ||
| 1228 | if (!cr1->cr_principal || !cr2->cr_principal) | ||
| 1229 | return false; | ||
| 1230 | return 0 == strcmp(cr1->cr_principal, cr1->cr_principal); | ||
| 1165 | } | 1231 | } |
| 1166 | 1232 | ||
| 1167 | static void gen_clid(struct nfs4_client *clp) | 1233 | static void gen_clid(struct nfs4_client *clp) |
| @@ -1204,25 +1270,20 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, | |||
| 1204 | { | 1270 | { |
| 1205 | struct nfs4_client *clp; | 1271 | struct nfs4_client *clp; |
| 1206 | struct sockaddr *sa = svc_addr(rqstp); | 1272 | struct sockaddr *sa = svc_addr(rqstp); |
| 1207 | char *princ; | 1273 | int ret; |
| 1208 | 1274 | ||
| 1209 | clp = alloc_client(name); | 1275 | clp = alloc_client(name); |
| 1210 | if (clp == NULL) | 1276 | if (clp == NULL) |
| 1211 | return NULL; | 1277 | return NULL; |
| 1212 | 1278 | ||
| 1213 | INIT_LIST_HEAD(&clp->cl_sessions); | 1279 | INIT_LIST_HEAD(&clp->cl_sessions); |
| 1214 | 1280 | ret = copy_cred(&clp->cl_cred, &rqstp->rq_cred); | |
| 1215 | princ = svc_gss_principal(rqstp); | 1281 | if (ret) { |
| 1216 | if (princ) { | 1282 | spin_lock(&client_lock); |
| 1217 | clp->cl_principal = kstrdup(princ, GFP_KERNEL); | 1283 | free_client(clp); |
| 1218 | if (clp->cl_principal == NULL) { | 1284 | spin_unlock(&client_lock); |
| 1219 | spin_lock(&client_lock); | 1285 | return NULL; |
| 1220 | free_client(clp); | ||
| 1221 | spin_unlock(&client_lock); | ||
| 1222 | return NULL; | ||
| 1223 | } | ||
| 1224 | } | 1286 | } |
| 1225 | |||
| 1226 | idr_init(&clp->cl_stateids); | 1287 | idr_init(&clp->cl_stateids); |
| 1227 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); | 1288 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); |
| 1228 | atomic_set(&clp->cl_refcount, 0); | 1289 | atomic_set(&clp->cl_refcount, 0); |
| @@ -1240,8 +1301,6 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, | |||
| 1240 | rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); | 1301 | rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); |
| 1241 | copy_verf(clp, verf); | 1302 | copy_verf(clp, verf); |
| 1242 | rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa); | 1303 | rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa); |
| 1243 | clp->cl_flavor = rqstp->rq_flavor; | ||
| 1244 | copy_cred(&clp->cl_cred, &rqstp->rq_cred); | ||
| 1245 | gen_confirm(clp); | 1304 | gen_confirm(clp); |
| 1246 | clp->cl_cb_session = NULL; | 1305 | clp->cl_cb_session = NULL; |
| 1247 | return clp; | 1306 | return clp; |
| @@ -1470,18 +1529,32 @@ nfsd4_set_ex_flags(struct nfs4_client *new, struct nfsd4_exchange_id *clid) | |||
| 1470 | clid->flags = new->cl_exchange_flags; | 1529 | clid->flags = new->cl_exchange_flags; |
| 1471 | } | 1530 | } |
| 1472 | 1531 | ||
| 1532 | static bool client_has_state(struct nfs4_client *clp) | ||
| 1533 | { | ||
| 1534 | /* | ||
| 1535 | * Note clp->cl_openowners check isn't quite right: there's no | ||
| 1536 | * need to count owners without stateid's. | ||
| 1537 | * | ||
| 1538 | * Also note we should probably be using this in 4.0 case too. | ||
| 1539 | */ | ||
| 1540 | return !list_empty(&clp->cl_openowners) | ||
| 1541 | || !list_empty(&clp->cl_delegations) | ||
| 1542 | || !list_empty(&clp->cl_sessions); | ||
| 1543 | } | ||
| 1544 | |||
| 1473 | __be32 | 1545 | __be32 |
| 1474 | nfsd4_exchange_id(struct svc_rqst *rqstp, | 1546 | nfsd4_exchange_id(struct svc_rqst *rqstp, |
| 1475 | struct nfsd4_compound_state *cstate, | 1547 | struct nfsd4_compound_state *cstate, |
| 1476 | struct nfsd4_exchange_id *exid) | 1548 | struct nfsd4_exchange_id *exid) |
| 1477 | { | 1549 | { |
| 1478 | struct nfs4_client *unconf, *conf, *new; | 1550 | struct nfs4_client *unconf, *conf, *new; |
| 1479 | int status; | 1551 | __be32 status; |
| 1480 | unsigned int strhashval; | 1552 | unsigned int strhashval; |
| 1481 | char dname[HEXDIR_LEN]; | 1553 | char dname[HEXDIR_LEN]; |
| 1482 | char addr_str[INET6_ADDRSTRLEN]; | 1554 | char addr_str[INET6_ADDRSTRLEN]; |
| 1483 | nfs4_verifier verf = exid->verifier; | 1555 | nfs4_verifier verf = exid->verifier; |
| 1484 | struct sockaddr *sa = svc_addr(rqstp); | 1556 | struct sockaddr *sa = svc_addr(rqstp); |
| 1557 | bool update = exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A; | ||
| 1485 | 1558 | ||
| 1486 | rpc_ntop(sa, addr_str, sizeof(addr_str)); | 1559 | rpc_ntop(sa, addr_str, sizeof(addr_str)); |
| 1487 | dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " | 1560 | dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " |
| @@ -1507,71 +1580,63 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
| 1507 | status = nfs4_make_rec_clidname(dname, &exid->clname); | 1580 | status = nfs4_make_rec_clidname(dname, &exid->clname); |
| 1508 | 1581 | ||
| 1509 | if (status) | 1582 | if (status) |
| 1510 | goto error; | 1583 | return status; |
| 1511 | 1584 | ||
| 1512 | strhashval = clientstr_hashval(dname); | 1585 | strhashval = clientstr_hashval(dname); |
| 1513 | 1586 | ||
| 1587 | /* Cases below refer to rfc 5661 section 18.35.4: */ | ||
| 1514 | nfs4_lock_state(); | 1588 | nfs4_lock_state(); |
| 1515 | status = nfs_ok; | ||
| 1516 | |||
| 1517 | conf = find_confirmed_client_by_str(dname, strhashval); | 1589 | conf = find_confirmed_client_by_str(dname, strhashval); |
| 1518 | if (conf) { | 1590 | if (conf) { |
| 1519 | if (!clp_used_exchangeid(conf)) { | 1591 | bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred); |
| 1520 | status = nfserr_clid_inuse; /* XXX: ? */ | 1592 | bool verfs_match = same_verf(&verf, &conf->cl_verifier); |
| 1521 | goto out; | 1593 | |
| 1522 | } | 1594 | if (update) { |
| 1523 | if (!same_verf(&verf, &conf->cl_verifier)) { | 1595 | if (!clp_used_exchangeid(conf)) { /* buggy client */ |
| 1524 | /* 18.35.4 case 8 */ | 1596 | status = nfserr_inval; |
| 1525 | if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { | 1597 | goto out; |
| 1598 | } | ||
| 1599 | if (!creds_match) { /* case 9 */ | ||
| 1600 | status = nfserr_perm; | ||
| 1601 | goto out; | ||
| 1602 | } | ||
| 1603 | if (!verfs_match) { /* case 8 */ | ||
| 1526 | status = nfserr_not_same; | 1604 | status = nfserr_not_same; |
| 1527 | goto out; | 1605 | goto out; |
| 1528 | } | 1606 | } |
| 1529 | /* Client reboot: destroy old state */ | 1607 | /* case 6 */ |
| 1530 | expire_client(conf); | 1608 | exid->flags |= EXCHGID4_FLAG_CONFIRMED_R; |
| 1531 | goto out_new; | 1609 | new = conf; |
| 1610 | goto out_copy; | ||
| 1532 | } | 1611 | } |
| 1533 | if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { | 1612 | if (!creds_match) { /* case 3 */ |
| 1534 | /* 18.35.4 case 9 */ | 1613 | if (client_has_state(conf)) { |
| 1535 | if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { | 1614 | status = nfserr_clid_inuse; |
| 1536 | status = nfserr_perm; | ||
| 1537 | goto out; | 1615 | goto out; |
| 1538 | } | 1616 | } |
| 1539 | expire_client(conf); | 1617 | expire_client(conf); |
| 1540 | goto out_new; | 1618 | goto out_new; |
| 1541 | } | 1619 | } |
| 1542 | /* | 1620 | if (verfs_match) { /* case 2 */ |
| 1543 | * Set bit when the owner id and verifier map to an already | 1621 | conf->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R; |
| 1544 | * confirmed client id (18.35.3). | 1622 | new = conf; |
| 1545 | */ | 1623 | goto out_copy; |
| 1546 | exid->flags |= EXCHGID4_FLAG_CONFIRMED_R; | 1624 | } |
| 1547 | 1625 | /* case 5, client reboot */ | |
| 1548 | /* | 1626 | goto out_new; |
| 1549 | * Falling into 18.35.4 case 2, possible router replay. | ||
| 1550 | * Leave confirmed record intact and return same result. | ||
| 1551 | */ | ||
| 1552 | copy_verf(conf, &verf); | ||
| 1553 | new = conf; | ||
| 1554 | goto out_copy; | ||
| 1555 | } | 1627 | } |
| 1556 | 1628 | ||
| 1557 | /* 18.35.4 case 7 */ | 1629 | if (update) { /* case 7 */ |
| 1558 | if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { | ||
| 1559 | status = nfserr_noent; | 1630 | status = nfserr_noent; |
| 1560 | goto out; | 1631 | goto out; |
| 1561 | } | 1632 | } |
| 1562 | 1633 | ||
| 1563 | unconf = find_unconfirmed_client_by_str(dname, strhashval); | 1634 | unconf = find_unconfirmed_client_by_str(dname, strhashval); |
| 1564 | if (unconf) { | 1635 | if (unconf) /* case 4, possible retry or client restart */ |
| 1565 | /* | ||
| 1566 | * Possible retry or client restart. Per 18.35.4 case 4, | ||
| 1567 | * a new unconfirmed record should be generated regardless | ||
| 1568 | * of whether any properties have changed. | ||
| 1569 | */ | ||
| 1570 | expire_client(unconf); | 1636 | expire_client(unconf); |
| 1571 | } | ||
| 1572 | 1637 | ||
| 1638 | /* case 1 (normal case) */ | ||
| 1573 | out_new: | 1639 | out_new: |
| 1574 | /* Normal case */ | ||
| 1575 | new = create_client(exid->clname, dname, rqstp, &verf); | 1640 | new = create_client(exid->clname, dname, rqstp, &verf); |
| 1576 | if (new == NULL) { | 1641 | if (new == NULL) { |
| 1577 | status = nfserr_jukebox; | 1642 | status = nfserr_jukebox; |
| @@ -1584,7 +1649,7 @@ out_copy: | |||
| 1584 | exid->clientid.cl_boot = new->cl_clientid.cl_boot; | 1649 | exid->clientid.cl_boot = new->cl_clientid.cl_boot; |
| 1585 | exid->clientid.cl_id = new->cl_clientid.cl_id; | 1650 | exid->clientid.cl_id = new->cl_clientid.cl_id; |
| 1586 | 1651 | ||
| 1587 | exid->seqid = 1; | 1652 | exid->seqid = new->cl_cs_slot.sl_seqid + 1; |
| 1588 | nfsd4_set_ex_flags(new, exid); | 1653 | nfsd4_set_ex_flags(new, exid); |
| 1589 | 1654 | ||
| 1590 | dprintk("nfsd4_exchange_id seqid %d flags %x\n", | 1655 | dprintk("nfsd4_exchange_id seqid %d flags %x\n", |
| @@ -1593,12 +1658,10 @@ out_copy: | |||
| 1593 | 1658 | ||
| 1594 | out: | 1659 | out: |
| 1595 | nfs4_unlock_state(); | 1660 | nfs4_unlock_state(); |
| 1596 | error: | ||
| 1597 | dprintk("nfsd4_exchange_id returns %d\n", ntohl(status)); | ||
| 1598 | return status; | 1661 | return status; |
| 1599 | } | 1662 | } |
| 1600 | 1663 | ||
| 1601 | static int | 1664 | static __be32 |
| 1602 | check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse) | 1665 | check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse) |
| 1603 | { | 1666 | { |
| 1604 | dprintk("%s enter. seqid %d slot_seqid %d\n", __func__, seqid, | 1667 | dprintk("%s enter. seqid %d slot_seqid %d\n", __func__, seqid, |
| @@ -1626,7 +1689,7 @@ check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse) | |||
| 1626 | */ | 1689 | */ |
| 1627 | static void | 1690 | static void |
| 1628 | nfsd4_cache_create_session(struct nfsd4_create_session *cr_ses, | 1691 | nfsd4_cache_create_session(struct nfsd4_create_session *cr_ses, |
| 1629 | struct nfsd4_clid_slot *slot, int nfserr) | 1692 | struct nfsd4_clid_slot *slot, __be32 nfserr) |
| 1630 | { | 1693 | { |
| 1631 | slot->sl_status = nfserr; | 1694 | slot->sl_status = nfserr; |
| 1632 | memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses)); | 1695 | memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses)); |
| @@ -1657,7 +1720,7 @@ nfsd4_replay_create_session(struct nfsd4_create_session *cr_ses, | |||
| 1657 | /* seqid, slotID, slotID, slotID, status */ \ | 1720 | /* seqid, slotID, slotID, slotID, status */ \ |
| 1658 | 5 ) * sizeof(__be32)) | 1721 | 5 ) * sizeof(__be32)) |
| 1659 | 1722 | ||
| 1660 | static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs fchannel) | 1723 | static bool check_forechannel_attrs(struct nfsd4_channel_attrs fchannel) |
| 1661 | { | 1724 | { |
| 1662 | return fchannel.maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ | 1725 | return fchannel.maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ |
| 1663 | || fchannel.maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ; | 1726 | || fchannel.maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ; |
| @@ -1673,7 +1736,7 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
| 1673 | struct nfsd4_session *new; | 1736 | struct nfsd4_session *new; |
| 1674 | struct nfsd4_clid_slot *cs_slot = NULL; | 1737 | struct nfsd4_clid_slot *cs_slot = NULL; |
| 1675 | bool confirm_me = false; | 1738 | bool confirm_me = false; |
| 1676 | int status = 0; | 1739 | __be32 status = 0; |
| 1677 | 1740 | ||
| 1678 | if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) | 1741 | if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) |
| 1679 | return nfserr_inval; | 1742 | return nfserr_inval; |
| @@ -1686,16 +1749,10 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
| 1686 | cs_slot = &conf->cl_cs_slot; | 1749 | cs_slot = &conf->cl_cs_slot; |
| 1687 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); | 1750 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); |
| 1688 | if (status == nfserr_replay_cache) { | 1751 | if (status == nfserr_replay_cache) { |
| 1689 | dprintk("Got a create_session replay! seqid= %d\n", | ||
| 1690 | cs_slot->sl_seqid); | ||
| 1691 | /* Return the cached reply status */ | ||
| 1692 | status = nfsd4_replay_create_session(cr_ses, cs_slot); | 1752 | status = nfsd4_replay_create_session(cr_ses, cs_slot); |
| 1693 | goto out; | 1753 | goto out; |
| 1694 | } else if (cr_ses->seqid != cs_slot->sl_seqid + 1) { | 1754 | } else if (cr_ses->seqid != cs_slot->sl_seqid + 1) { |
| 1695 | status = nfserr_seq_misordered; | 1755 | status = nfserr_seq_misordered; |
| 1696 | dprintk("Sequence misordered!\n"); | ||
| 1697 | dprintk("Expected seqid= %d but got seqid= %d\n", | ||
| 1698 | cs_slot->sl_seqid, cr_ses->seqid); | ||
| 1699 | goto out; | 1756 | goto out; |
| 1700 | } | 1757 | } |
| 1701 | } else if (unconf) { | 1758 | } else if (unconf) { |
| @@ -1704,7 +1761,6 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
| 1704 | status = nfserr_clid_inuse; | 1761 | status = nfserr_clid_inuse; |
| 1705 | goto out; | 1762 | goto out; |
| 1706 | } | 1763 | } |
| 1707 | |||
| 1708 | cs_slot = &unconf->cl_cs_slot; | 1764 | cs_slot = &unconf->cl_cs_slot; |
| 1709 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); | 1765 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); |
| 1710 | if (status) { | 1766 | if (status) { |
| @@ -1712,7 +1768,6 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
| 1712 | status = nfserr_seq_misordered; | 1768 | status = nfserr_seq_misordered; |
| 1713 | goto out; | 1769 | goto out; |
| 1714 | } | 1770 | } |
| 1715 | |||
| 1716 | confirm_me = true; | 1771 | confirm_me = true; |
| 1717 | conf = unconf; | 1772 | conf = unconf; |
| 1718 | } else { | 1773 | } else { |
| @@ -1749,8 +1804,14 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
| 1749 | 1804 | ||
| 1750 | /* cache solo and embedded create sessions under the state lock */ | 1805 | /* cache solo and embedded create sessions under the state lock */ |
| 1751 | nfsd4_cache_create_session(cr_ses, cs_slot, status); | 1806 | nfsd4_cache_create_session(cr_ses, cs_slot, status); |
| 1752 | if (confirm_me) | 1807 | if (confirm_me) { |
| 1808 | unsigned int hash = clientstr_hashval(unconf->cl_recdir); | ||
| 1809 | struct nfs4_client *old = | ||
| 1810 | find_confirmed_client_by_str(conf->cl_recdir, hash); | ||
| 1811 | if (old) | ||
| 1812 | expire_client(old); | ||
| 1753 | move_to_confirmed(conf); | 1813 | move_to_confirmed(conf); |
| 1814 | } | ||
| 1754 | out: | 1815 | out: |
| 1755 | nfs4_unlock_state(); | 1816 | nfs4_unlock_state(); |
| 1756 | dprintk("%s returns %d\n", __func__, ntohl(status)); | 1817 | dprintk("%s returns %d\n", __func__, ntohl(status)); |
| @@ -1818,7 +1879,7 @@ nfsd4_destroy_session(struct svc_rqst *r, | |||
| 1818 | struct nfsd4_destroy_session *sessionid) | 1879 | struct nfsd4_destroy_session *sessionid) |
| 1819 | { | 1880 | { |
| 1820 | struct nfsd4_session *ses; | 1881 | struct nfsd4_session *ses; |
| 1821 | u32 status = nfserr_badsession; | 1882 | __be32 status = nfserr_badsession; |
| 1822 | 1883 | ||
| 1823 | /* Notes: | 1884 | /* Notes: |
| 1824 | * - The confirmed nfs4_client->cl_sessionid holds destroyed sessinid | 1885 | * - The confirmed nfs4_client->cl_sessionid holds destroyed sessinid |
| @@ -1914,7 +1975,7 @@ nfsd4_sequence(struct svc_rqst *rqstp, | |||
| 1914 | struct nfsd4_session *session; | 1975 | struct nfsd4_session *session; |
| 1915 | struct nfsd4_slot *slot; | 1976 | struct nfsd4_slot *slot; |
| 1916 | struct nfsd4_conn *conn; | 1977 | struct nfsd4_conn *conn; |
| 1917 | int status; | 1978 | __be32 status; |
| 1918 | 1979 | ||
| 1919 | if (resp->opcnt != 1) | 1980 | if (resp->opcnt != 1) |
| 1920 | return nfserr_sequence_pos; | 1981 | return nfserr_sequence_pos; |
| @@ -2008,18 +2069,11 @@ out: | |||
| 2008 | return status; | 2069 | return status; |
| 2009 | } | 2070 | } |
| 2010 | 2071 | ||
| 2011 | static inline bool has_resources(struct nfs4_client *clp) | ||
| 2012 | { | ||
| 2013 | return !list_empty(&clp->cl_openowners) | ||
| 2014 | || !list_empty(&clp->cl_delegations) | ||
| 2015 | || !list_empty(&clp->cl_sessions); | ||
| 2016 | } | ||
| 2017 | |||
| 2018 | __be32 | 2072 | __be32 |
| 2019 | nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_destroy_clientid *dc) | 2073 | nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_destroy_clientid *dc) |
| 2020 | { | 2074 | { |
| 2021 | struct nfs4_client *conf, *unconf, *clp; | 2075 | struct nfs4_client *conf, *unconf, *clp; |
| 2022 | int status = 0; | 2076 | __be32 status = 0; |
| 2023 | 2077 | ||
| 2024 | nfs4_lock_state(); | 2078 | nfs4_lock_state(); |
| 2025 | unconf = find_unconfirmed_client(&dc->clientid); | 2079 | unconf = find_unconfirmed_client(&dc->clientid); |
| @@ -2028,7 +2082,7 @@ nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta | |||
| 2028 | if (conf) { | 2082 | if (conf) { |
| 2029 | clp = conf; | 2083 | clp = conf; |
| 2030 | 2084 | ||
| 2031 | if (!is_client_expired(conf) && has_resources(conf)) { | 2085 | if (!is_client_expired(conf) && client_has_state(conf)) { |
| 2032 | status = nfserr_clientid_busy; | 2086 | status = nfserr_clientid_busy; |
| 2033 | goto out; | 2087 | goto out; |
| 2034 | } | 2088 | } |
| @@ -2055,7 +2109,7 @@ out: | |||
| 2055 | __be32 | 2109 | __be32 |
| 2056 | nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_reclaim_complete *rc) | 2110 | nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_reclaim_complete *rc) |
| 2057 | { | 2111 | { |
| 2058 | int status = 0; | 2112 | __be32 status = 0; |
| 2059 | 2113 | ||
| 2060 | if (rc->rca_one_fs) { | 2114 | if (rc->rca_one_fs) { |
| 2061 | if (!cstate->current_fh.fh_dentry) | 2115 | if (!cstate->current_fh.fh_dentry) |
| @@ -2106,17 +2160,13 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 2106 | if (status) | 2160 | if (status) |
| 2107 | return status; | 2161 | return status; |
| 2108 | 2162 | ||
| 2109 | /* | ||
| 2110 | * XXX The Duplicate Request Cache (DRC) has been checked (??) | ||
| 2111 | * We get here on a DRC miss. | ||
| 2112 | */ | ||
| 2113 | |||
| 2114 | strhashval = clientstr_hashval(dname); | 2163 | strhashval = clientstr_hashval(dname); |
| 2115 | 2164 | ||
| 2165 | /* Cases below refer to rfc 3530 section 14.2.33: */ | ||
| 2116 | nfs4_lock_state(); | 2166 | nfs4_lock_state(); |
| 2117 | conf = find_confirmed_client_by_str(dname, strhashval); | 2167 | conf = find_confirmed_client_by_str(dname, strhashval); |
| 2118 | if (conf) { | 2168 | if (conf) { |
| 2119 | /* RFC 3530 14.2.33 CASE 0: */ | 2169 | /* case 0: */ |
| 2120 | status = nfserr_clid_inuse; | 2170 | status = nfserr_clid_inuse; |
| 2121 | if (clp_used_exchangeid(conf)) | 2171 | if (clp_used_exchangeid(conf)) |
| 2122 | goto out; | 2172 | goto out; |
| @@ -2129,63 +2179,18 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 2129 | goto out; | 2179 | goto out; |
| 2130 | } | 2180 | } |
| 2131 | } | 2181 | } |
| 2132 | /* | ||
| 2133 | * section 14.2.33 of RFC 3530 (under the heading "IMPLEMENTATION") | ||
| 2134 | * has a description of SETCLIENTID request processing consisting | ||
| 2135 | * of 5 bullet points, labeled as CASE0 - CASE4 below. | ||
| 2136 | */ | ||
| 2137 | unconf = find_unconfirmed_client_by_str(dname, strhashval); | 2182 | unconf = find_unconfirmed_client_by_str(dname, strhashval); |
| 2183 | if (unconf) | ||
| 2184 | expire_client(unconf); | ||
| 2138 | status = nfserr_jukebox; | 2185 | status = nfserr_jukebox; |
| 2139 | if (!conf) { | 2186 | new = create_client(clname, dname, rqstp, &clverifier); |
| 2140 | /* | 2187 | if (new == NULL) |
| 2141 | * RFC 3530 14.2.33 CASE 4: | 2188 | goto out; |
| 2142 | * placed first, because it is the normal case | 2189 | if (conf && same_verf(&conf->cl_verifier, &clverifier)) |
| 2143 | */ | 2190 | /* case 1: probable callback update */ |
| 2144 | if (unconf) | ||
| 2145 | expire_client(unconf); | ||
| 2146 | new = create_client(clname, dname, rqstp, &clverifier); | ||
| 2147 | if (new == NULL) | ||
| 2148 | goto out; | ||
| 2149 | gen_clid(new); | ||
| 2150 | } else if (same_verf(&conf->cl_verifier, &clverifier)) { | ||
| 2151 | /* | ||
| 2152 | * RFC 3530 14.2.33 CASE 1: | ||
| 2153 | * probable callback update | ||
| 2154 | */ | ||
| 2155 | if (unconf) { | ||
| 2156 | /* Note this is removing unconfirmed {*x***}, | ||
| 2157 | * which is stronger than RFC recommended {vxc**}. | ||
| 2158 | * This has the advantage that there is at most | ||
| 2159 | * one {*x***} in either list at any time. | ||
| 2160 | */ | ||
| 2161 | expire_client(unconf); | ||
| 2162 | } | ||
| 2163 | new = create_client(clname, dname, rqstp, &clverifier); | ||
| 2164 | if (new == NULL) | ||
| 2165 | goto out; | ||
| 2166 | copy_clid(new, conf); | 2191 | copy_clid(new, conf); |
| 2167 | } else if (!unconf) { | 2192 | else /* case 4 (new client) or cases 2, 3 (client reboot): */ |
| 2168 | /* | ||
| 2169 | * RFC 3530 14.2.33 CASE 2: | ||
| 2170 | * probable client reboot; state will be removed if | ||
| 2171 | * confirmed. | ||
| 2172 | */ | ||
| 2173 | new = create_client(clname, dname, rqstp, &clverifier); | ||
| 2174 | if (new == NULL) | ||
| 2175 | goto out; | ||
| 2176 | gen_clid(new); | ||
| 2177 | } else { | ||
| 2178 | /* | ||
| 2179 | * RFC 3530 14.2.33 CASE 3: | ||
| 2180 | * probable client reboot; state will be removed if | ||
| 2181 | * confirmed. | ||
| 2182 | */ | ||
| 2183 | expire_client(unconf); | ||
| 2184 | new = create_client(clname, dname, rqstp, &clverifier); | ||
| 2185 | if (new == NULL) | ||
| 2186 | goto out; | ||
| 2187 | gen_clid(new); | 2193 | gen_clid(new); |
| 2188 | } | ||
| 2189 | /* | 2194 | /* |
| 2190 | * XXX: we should probably set this at creation time, and check | 2195 | * XXX: we should probably set this at creation time, and check |
| 2191 | * for consistent minorversion use throughout: | 2196 | * for consistent minorversion use throughout: |
| @@ -2203,17 +2208,11 @@ out: | |||
| 2203 | } | 2208 | } |
| 2204 | 2209 | ||
| 2205 | 2210 | ||
| 2206 | /* | ||
| 2207 | * Section 14.2.34 of RFC 3530 (under the heading "IMPLEMENTATION") has | ||
| 2208 | * a description of SETCLIENTID_CONFIRM request processing consisting of 4 | ||
| 2209 | * bullets, labeled as CASE1 - CASE4 below. | ||
| 2210 | */ | ||
| 2211 | __be32 | 2211 | __be32 |
| 2212 | nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | 2212 | nfsd4_setclientid_confirm(struct svc_rqst *rqstp, |
| 2213 | struct nfsd4_compound_state *cstate, | 2213 | struct nfsd4_compound_state *cstate, |
| 2214 | struct nfsd4_setclientid_confirm *setclientid_confirm) | 2214 | struct nfsd4_setclientid_confirm *setclientid_confirm) |
| 2215 | { | 2215 | { |
| 2216 | struct sockaddr *sa = svc_addr(rqstp); | ||
| 2217 | struct nfs4_client *conf, *unconf; | 2216 | struct nfs4_client *conf, *unconf; |
| 2218 | nfs4_verifier confirm = setclientid_confirm->sc_confirm; | 2217 | nfs4_verifier confirm = setclientid_confirm->sc_confirm; |
| 2219 | clientid_t * clid = &setclientid_confirm->sc_clientid; | 2218 | clientid_t * clid = &setclientid_confirm->sc_clientid; |
| @@ -2221,84 +2220,44 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | |||
| 2221 | 2220 | ||
| 2222 | if (STALE_CLIENTID(clid)) | 2221 | if (STALE_CLIENTID(clid)) |
| 2223 | return nfserr_stale_clientid; | 2222 | return nfserr_stale_clientid; |
| 2224 | /* | ||
| 2225 | * XXX The Duplicate Request Cache (DRC) has been checked (??) | ||
| 2226 | * We get here on a DRC miss. | ||
| 2227 | */ | ||
| 2228 | |||
| 2229 | nfs4_lock_state(); | 2223 | nfs4_lock_state(); |
| 2230 | 2224 | ||
| 2231 | conf = find_confirmed_client(clid); | 2225 | conf = find_confirmed_client(clid); |
| 2232 | unconf = find_unconfirmed_client(clid); | 2226 | unconf = find_unconfirmed_client(clid); |
| 2233 | |||
| 2234 | status = nfserr_clid_inuse; | ||
| 2235 | if (conf && !rpc_cmp_addr((struct sockaddr *) &conf->cl_addr, sa)) | ||
| 2236 | goto out; | ||
| 2237 | if (unconf && !rpc_cmp_addr((struct sockaddr *) &unconf->cl_addr, sa)) | ||
| 2238 | goto out; | ||
| 2239 | |||
| 2240 | /* | 2227 | /* |
| 2241 | * section 14.2.34 of RFC 3530 has a description of | 2228 | * We try hard to give out unique clientid's, so if we get an |
| 2242 | * SETCLIENTID_CONFIRM request processing consisting | 2229 | * attempt to confirm the same clientid with a different cred, |
| 2243 | * of 4 bullet points, labeled as CASE1 - CASE4 below. | 2230 | * there's a bug somewhere. Let's charitably assume it's our |
| 2231 | * bug. | ||
| 2244 | */ | 2232 | */ |
| 2245 | if (conf && unconf && same_verf(&confirm, &unconf->cl_confirm)) { | 2233 | status = nfserr_serverfault; |
| 2246 | /* | 2234 | if (unconf && !same_creds(&unconf->cl_cred, &rqstp->rq_cred)) |
| 2247 | * RFC 3530 14.2.34 CASE 1: | 2235 | goto out; |
| 2248 | * callback update | 2236 | if (conf && !same_creds(&conf->cl_cred, &rqstp->rq_cred)) |
| 2249 | */ | 2237 | goto out; |
| 2250 | if (!same_creds(&conf->cl_cred, &unconf->cl_cred)) | 2238 | /* cases below refer to rfc 3530 section 14.2.34: */ |
| 2251 | status = nfserr_clid_inuse; | 2239 | if (!unconf || !same_verf(&confirm, &unconf->cl_confirm)) { |
| 2252 | else { | 2240 | if (conf && !unconf) /* case 2: probable retransmit */ |
| 2253 | nfsd4_change_callback(conf, &unconf->cl_cb_conn); | ||
| 2254 | nfsd4_probe_callback(conf); | ||
| 2255 | expire_client(unconf); | ||
| 2256 | status = nfs_ok; | 2241 | status = nfs_ok; |
| 2242 | else /* case 4: client hasn't noticed we rebooted yet? */ | ||
| 2243 | status = nfserr_stale_clientid; | ||
| 2244 | goto out; | ||
| 2245 | } | ||
| 2246 | status = nfs_ok; | ||
| 2247 | if (conf) { /* case 1: callback update */ | ||
| 2248 | nfsd4_change_callback(conf, &unconf->cl_cb_conn); | ||
| 2249 | nfsd4_probe_callback(conf); | ||
| 2250 | expire_client(unconf); | ||
| 2251 | } else { /* case 3: normal case; new or rebooted client */ | ||
| 2252 | unsigned int hash = clientstr_hashval(unconf->cl_recdir); | ||
| 2257 | 2253 | ||
| 2254 | conf = find_confirmed_client_by_str(unconf->cl_recdir, hash); | ||
| 2255 | if (conf) { | ||
| 2256 | nfsd4_client_record_remove(conf); | ||
| 2257 | expire_client(conf); | ||
| 2258 | } | 2258 | } |
| 2259 | } else if (conf && !unconf) { | 2259 | move_to_confirmed(unconf); |
| 2260 | /* | 2260 | nfsd4_probe_callback(unconf); |
| 2261 | * RFC 3530 14.2.34 CASE 2: | ||
| 2262 | * probable retransmitted request; play it safe and | ||
| 2263 | * do nothing. | ||
| 2264 | */ | ||
| 2265 | if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) | ||
| 2266 | status = nfserr_clid_inuse; | ||
| 2267 | else | ||
| 2268 | status = nfs_ok; | ||
| 2269 | } else if (!conf && unconf | ||
| 2270 | && same_verf(&unconf->cl_confirm, &confirm)) { | ||
| 2271 | /* | ||
| 2272 | * RFC 3530 14.2.34 CASE 3: | ||
| 2273 | * Normal case; new or rebooted client: | ||
| 2274 | */ | ||
| 2275 | if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred)) { | ||
| 2276 | status = nfserr_clid_inuse; | ||
| 2277 | } else { | ||
| 2278 | unsigned int hash = | ||
| 2279 | clientstr_hashval(unconf->cl_recdir); | ||
| 2280 | conf = find_confirmed_client_by_str(unconf->cl_recdir, | ||
| 2281 | hash); | ||
| 2282 | if (conf) { | ||
| 2283 | nfsd4_client_record_remove(conf); | ||
| 2284 | expire_client(conf); | ||
| 2285 | } | ||
| 2286 | move_to_confirmed(unconf); | ||
| 2287 | conf = unconf; | ||
| 2288 | nfsd4_probe_callback(conf); | ||
| 2289 | status = nfs_ok; | ||
| 2290 | } | ||
| 2291 | } else if ((!conf || (conf && !same_verf(&conf->cl_confirm, &confirm))) | ||
| 2292 | && (!unconf || (unconf && !same_verf(&unconf->cl_confirm, | ||
| 2293 | &confirm)))) { | ||
| 2294 | /* | ||
| 2295 | * RFC 3530 14.2.34 CASE 4: | ||
| 2296 | * Client probably hasn't noticed that we rebooted yet. | ||
| 2297 | */ | ||
| 2298 | status = nfserr_stale_clientid; | ||
| 2299 | } else { | ||
| 2300 | /* check that we have hit one of the cases...*/ | ||
| 2301 | status = nfserr_clid_inuse; | ||
| 2302 | } | 2261 | } |
| 2303 | out: | 2262 | out: |
| 2304 | nfs4_unlock_state(); | 2263 | nfs4_unlock_state(); |
| @@ -2454,8 +2413,8 @@ static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, | |||
| 2454 | stp->st_file = fp; | 2413 | stp->st_file = fp; |
| 2455 | stp->st_access_bmap = 0; | 2414 | stp->st_access_bmap = 0; |
| 2456 | stp->st_deny_bmap = 0; | 2415 | stp->st_deny_bmap = 0; |
| 2457 | __set_bit(open->op_share_access, &stp->st_access_bmap); | 2416 | set_access(open->op_share_access, stp); |
| 2458 | __set_bit(open->op_share_deny, &stp->st_deny_bmap); | 2417 | set_deny(open->op_share_deny, stp); |
| 2459 | stp->st_openstp = NULL; | 2418 | stp->st_openstp = NULL; |
| 2460 | } | 2419 | } |
| 2461 | 2420 | ||
| @@ -2534,8 +2493,8 @@ nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type) | |||
| 2534 | ret = nfserr_locked; | 2493 | ret = nfserr_locked; |
| 2535 | /* Search for conflicting share reservations */ | 2494 | /* Search for conflicting share reservations */ |
| 2536 | list_for_each_entry(stp, &fp->fi_stateids, st_perfile) { | 2495 | list_for_each_entry(stp, &fp->fi_stateids, st_perfile) { |
| 2537 | if (test_bit(deny_type, &stp->st_deny_bmap) || | 2496 | if (test_deny(deny_type, stp) || |
| 2538 | test_bit(NFS4_SHARE_DENY_BOTH, &stp->st_deny_bmap)) | 2497 | test_deny(NFS4_SHARE_DENY_BOTH, stp)) |
| 2539 | goto out; | 2498 | goto out; |
| 2540 | } | 2499 | } |
| 2541 | ret = nfs_ok; | 2500 | ret = nfs_ok; |
| @@ -2791,7 +2750,7 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *c | |||
| 2791 | bool new_access; | 2750 | bool new_access; |
| 2792 | __be32 status; | 2751 | __be32 status; |
| 2793 | 2752 | ||
| 2794 | new_access = !test_bit(op_share_access, &stp->st_access_bmap); | 2753 | new_access = !test_access(op_share_access, stp); |
| 2795 | if (new_access) { | 2754 | if (new_access) { |
| 2796 | status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open); | 2755 | status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open); |
| 2797 | if (status) | 2756 | if (status) |
| @@ -2806,8 +2765,8 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *c | |||
| 2806 | return status; | 2765 | return status; |
| 2807 | } | 2766 | } |
| 2808 | /* remember the open */ | 2767 | /* remember the open */ |
| 2809 | __set_bit(op_share_access, &stp->st_access_bmap); | 2768 | set_access(op_share_access, stp); |
| 2810 | __set_bit(open->op_share_deny, &stp->st_deny_bmap); | 2769 | set_deny(open->op_share_deny, stp); |
| 2811 | 2770 | ||
| 2812 | return nfs_ok; | 2771 | return nfs_ok; |
| 2813 | } | 2772 | } |
| @@ -3155,10 +3114,17 @@ out: | |||
| 3155 | static struct lock_manager nfsd4_manager = { | 3114 | static struct lock_manager nfsd4_manager = { |
| 3156 | }; | 3115 | }; |
| 3157 | 3116 | ||
| 3117 | static bool grace_ended; | ||
| 3118 | |||
| 3158 | static void | 3119 | static void |
| 3159 | nfsd4_end_grace(void) | 3120 | nfsd4_end_grace(void) |
| 3160 | { | 3121 | { |
| 3122 | /* do nothing if grace period already ended */ | ||
| 3123 | if (grace_ended) | ||
| 3124 | return; | ||
| 3125 | |||
| 3161 | dprintk("NFSD: end of grace period\n"); | 3126 | dprintk("NFSD: end of grace period\n"); |
| 3127 | grace_ended = true; | ||
| 3162 | nfsd4_record_grace_done(&init_net, boot_time); | 3128 | nfsd4_record_grace_done(&init_net, boot_time); |
| 3163 | locks_end_grace(&nfsd4_manager); | 3129 | locks_end_grace(&nfsd4_manager); |
| 3164 | /* | 3130 | /* |
| @@ -3183,8 +3149,7 @@ nfs4_laundromat(void) | |||
| 3183 | nfs4_lock_state(); | 3149 | nfs4_lock_state(); |
| 3184 | 3150 | ||
| 3185 | dprintk("NFSD: laundromat service - starting\n"); | 3151 | dprintk("NFSD: laundromat service - starting\n"); |
| 3186 | if (locks_in_grace()) | 3152 | nfsd4_end_grace(); |
| 3187 | nfsd4_end_grace(); | ||
| 3188 | INIT_LIST_HEAD(&reaplist); | 3153 | INIT_LIST_HEAD(&reaplist); |
| 3189 | spin_lock(&client_lock); | 3154 | spin_lock(&client_lock); |
| 3190 | list_for_each_safe(pos, next, &client_lru) { | 3155 | list_for_each_safe(pos, next, &client_lru) { |
| @@ -3276,18 +3241,18 @@ STALE_STATEID(stateid_t *stateid) | |||
| 3276 | } | 3241 | } |
| 3277 | 3242 | ||
| 3278 | static inline int | 3243 | static inline int |
| 3279 | access_permit_read(unsigned long access_bmap) | 3244 | access_permit_read(struct nfs4_ol_stateid *stp) |
| 3280 | { | 3245 | { |
| 3281 | return test_bit(NFS4_SHARE_ACCESS_READ, &access_bmap) || | 3246 | return test_access(NFS4_SHARE_ACCESS_READ, stp) || |
| 3282 | test_bit(NFS4_SHARE_ACCESS_BOTH, &access_bmap) || | 3247 | test_access(NFS4_SHARE_ACCESS_BOTH, stp) || |
| 3283 | test_bit(NFS4_SHARE_ACCESS_WRITE, &access_bmap); | 3248 | test_access(NFS4_SHARE_ACCESS_WRITE, stp); |
| 3284 | } | 3249 | } |
| 3285 | 3250 | ||
| 3286 | static inline int | 3251 | static inline int |
| 3287 | access_permit_write(unsigned long access_bmap) | 3252 | access_permit_write(struct nfs4_ol_stateid *stp) |
| 3288 | { | 3253 | { |
| 3289 | return test_bit(NFS4_SHARE_ACCESS_WRITE, &access_bmap) || | 3254 | return test_access(NFS4_SHARE_ACCESS_WRITE, stp) || |
| 3290 | test_bit(NFS4_SHARE_ACCESS_BOTH, &access_bmap); | 3255 | test_access(NFS4_SHARE_ACCESS_BOTH, stp); |
| 3291 | } | 3256 | } |
| 3292 | 3257 | ||
| 3293 | static | 3258 | static |
| @@ -3298,9 +3263,9 @@ __be32 nfs4_check_openmode(struct nfs4_ol_stateid *stp, int flags) | |||
| 3298 | /* For lock stateid's, we test the parent open, not the lock: */ | 3263 | /* For lock stateid's, we test the parent open, not the lock: */ |
| 3299 | if (stp->st_openstp) | 3264 | if (stp->st_openstp) |
| 3300 | stp = stp->st_openstp; | 3265 | stp = stp->st_openstp; |
| 3301 | if ((flags & WR_STATE) && (!access_permit_write(stp->st_access_bmap))) | 3266 | if ((flags & WR_STATE) && !access_permit_write(stp)) |
| 3302 | goto out; | 3267 | goto out; |
| 3303 | if ((flags & RD_STATE) && (!access_permit_read(stp->st_access_bmap))) | 3268 | if ((flags & RD_STATE) && !access_permit_read(stp)) |
| 3304 | goto out; | 3269 | goto out; |
| 3305 | status = nfs_ok; | 3270 | status = nfs_ok; |
| 3306 | out: | 3271 | out: |
| @@ -3340,7 +3305,7 @@ static bool stateid_generation_after(stateid_t *a, stateid_t *b) | |||
| 3340 | return (s32)a->si_generation - (s32)b->si_generation > 0; | 3305 | return (s32)a->si_generation - (s32)b->si_generation > 0; |
| 3341 | } | 3306 | } |
| 3342 | 3307 | ||
| 3343 | static int check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session) | 3308 | static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session) |
| 3344 | { | 3309 | { |
| 3345 | /* | 3310 | /* |
| 3346 | * When sessions are used the stateid generation number is ignored | 3311 | * When sessions are used the stateid generation number is ignored |
| @@ -3649,10 +3614,10 @@ out: | |||
| 3649 | 3614 | ||
| 3650 | static inline void nfs4_stateid_downgrade_bit(struct nfs4_ol_stateid *stp, u32 access) | 3615 | static inline void nfs4_stateid_downgrade_bit(struct nfs4_ol_stateid *stp, u32 access) |
| 3651 | { | 3616 | { |
| 3652 | if (!test_bit(access, &stp->st_access_bmap)) | 3617 | if (!test_access(access, stp)) |
| 3653 | return; | 3618 | return; |
| 3654 | nfs4_file_put_access(stp->st_file, nfs4_access_to_omode(access)); | 3619 | nfs4_file_put_access(stp->st_file, nfs4_access_to_omode(access)); |
| 3655 | __clear_bit(access, &stp->st_access_bmap); | 3620 | clear_access(access, stp); |
| 3656 | } | 3621 | } |
| 3657 | 3622 | ||
| 3658 | static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_access) | 3623 | static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_access) |
| @@ -3674,12 +3639,12 @@ static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_ac | |||
| 3674 | } | 3639 | } |
| 3675 | 3640 | ||
| 3676 | static void | 3641 | static void |
| 3677 | reset_union_bmap_deny(unsigned long deny, unsigned long *bmap) | 3642 | reset_union_bmap_deny(unsigned long deny, struct nfs4_ol_stateid *stp) |
| 3678 | { | 3643 | { |
| 3679 | int i; | 3644 | int i; |
| 3680 | for (i = 0; i < 4; i++) { | 3645 | for (i = 0; i < 4; i++) { |
| 3681 | if ((i & deny) != i) | 3646 | if ((i & deny) != i) |
| 3682 | __clear_bit(i, bmap); | 3647 | clear_deny(i, stp); |
| 3683 | } | 3648 | } |
| 3684 | } | 3649 | } |
| 3685 | 3650 | ||
| @@ -3706,19 +3671,19 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, | |||
| 3706 | if (status) | 3671 | if (status) |
| 3707 | goto out; | 3672 | goto out; |
| 3708 | status = nfserr_inval; | 3673 | status = nfserr_inval; |
| 3709 | if (!test_bit(od->od_share_access, &stp->st_access_bmap)) { | 3674 | if (!test_access(od->od_share_access, stp)) { |
| 3710 | dprintk("NFSD:access not a subset current bitmap: 0x%lx, input access=%08x\n", | 3675 | dprintk("NFSD: access not a subset current bitmap: 0x%lx, input access=%08x\n", |
| 3711 | stp->st_access_bmap, od->od_share_access); | 3676 | stp->st_access_bmap, od->od_share_access); |
| 3712 | goto out; | 3677 | goto out; |
| 3713 | } | 3678 | } |
| 3714 | if (!test_bit(od->od_share_deny, &stp->st_deny_bmap)) { | 3679 | if (!test_deny(od->od_share_deny, stp)) { |
| 3715 | dprintk("NFSD:deny not a subset current bitmap: 0x%lx, input deny=%08x\n", | 3680 | dprintk("NFSD:deny not a subset current bitmap: 0x%lx, input deny=%08x\n", |
| 3716 | stp->st_deny_bmap, od->od_share_deny); | 3681 | stp->st_deny_bmap, od->od_share_deny); |
| 3717 | goto out; | 3682 | goto out; |
| 3718 | } | 3683 | } |
| 3719 | nfs4_stateid_downgrade(stp, od->od_share_access); | 3684 | nfs4_stateid_downgrade(stp, od->od_share_access); |
| 3720 | 3685 | ||
| 3721 | reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap); | 3686 | reset_union_bmap_deny(od->od_share_deny, stp); |
| 3722 | 3687 | ||
| 3723 | update_stateid(&stp->st_stid.sc_stateid); | 3688 | update_stateid(&stp->st_stid.sc_stateid); |
| 3724 | memcpy(&od->od_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); | 3689 | memcpy(&od->od_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); |
| @@ -4008,13 +3973,13 @@ static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access) | |||
| 4008 | struct nfs4_file *fp = lock_stp->st_file; | 3973 | struct nfs4_file *fp = lock_stp->st_file; |
| 4009 | int oflag = nfs4_access_to_omode(access); | 3974 | int oflag = nfs4_access_to_omode(access); |
| 4010 | 3975 | ||
| 4011 | if (test_bit(access, &lock_stp->st_access_bmap)) | 3976 | if (test_access(access, lock_stp)) |
| 4012 | return; | 3977 | return; |
| 4013 | nfs4_file_get_access(fp, oflag); | 3978 | nfs4_file_get_access(fp, oflag); |
| 4014 | __set_bit(access, &lock_stp->st_access_bmap); | 3979 | set_access(access, lock_stp); |
| 4015 | } | 3980 | } |
| 4016 | 3981 | ||
| 4017 | __be32 lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, struct nfs4_ol_stateid *ost, struct nfsd4_lock *lock, struct nfs4_ol_stateid **lst, bool *new) | 3982 | static __be32 lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, struct nfs4_ol_stateid *ost, struct nfsd4_lock *lock, struct nfs4_ol_stateid **lst, bool *new) |
| 4018 | { | 3983 | { |
| 4019 | struct nfs4_file *fi = ost->st_file; | 3984 | struct nfs4_file *fi = ost->st_file; |
| 4020 | struct nfs4_openowner *oo = openowner(ost->st_stateowner); | 3985 | struct nfs4_openowner *oo = openowner(ost->st_stateowner); |
| @@ -4055,7 +4020,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 4055 | struct nfs4_openowner *open_sop = NULL; | 4020 | struct nfs4_openowner *open_sop = NULL; |
| 4056 | struct nfs4_lockowner *lock_sop = NULL; | 4021 | struct nfs4_lockowner *lock_sop = NULL; |
| 4057 | struct nfs4_ol_stateid *lock_stp; | 4022 | struct nfs4_ol_stateid *lock_stp; |
| 4058 | struct nfs4_file *fp; | ||
| 4059 | struct file *filp = NULL; | 4023 | struct file *filp = NULL; |
| 4060 | struct file_lock file_lock; | 4024 | struct file_lock file_lock; |
| 4061 | struct file_lock conflock; | 4025 | struct file_lock conflock; |
| @@ -4123,7 +4087,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 4123 | goto out; | 4087 | goto out; |
| 4124 | } | 4088 | } |
| 4125 | lock_sop = lockowner(lock_stp->st_stateowner); | 4089 | lock_sop = lockowner(lock_stp->st_stateowner); |
| 4126 | fp = lock_stp->st_file; | ||
| 4127 | 4090 | ||
| 4128 | lkflg = setlkflg(lock->lk_type); | 4091 | lkflg = setlkflg(lock->lk_type); |
| 4129 | status = nfs4_check_openmode(lock_stp, lkflg); | 4092 | status = nfs4_check_openmode(lock_stp, lkflg); |
| @@ -4715,6 +4678,7 @@ nfs4_state_start(void) | |||
| 4715 | nfsd4_client_tracking_init(&init_net); | 4678 | nfsd4_client_tracking_init(&init_net); |
| 4716 | boot_time = get_seconds(); | 4679 | boot_time = get_seconds(); |
| 4717 | locks_start_grace(&nfsd4_manager); | 4680 | locks_start_grace(&nfsd4_manager); |
| 4681 | grace_ended = false; | ||
| 4718 | printk(KERN_INFO "NFSD: starting %ld-second grace period\n", | 4682 | printk(KERN_INFO "NFSD: starting %ld-second grace period\n", |
| 4719 | nfsd4_grace); | 4683 | nfsd4_grace); |
| 4720 | ret = set_callback_cred(); | 4684 | ret = set_callback_cred(); |
