diff options
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r-- | fs/nfsd/nfs4state.c | 243 |
1 files changed, 145 insertions, 98 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index fbd18c3074bb..d98d0213285d 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -230,7 +230,8 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f | |||
230 | dp->dl_client = clp; | 230 | dp->dl_client = clp; |
231 | get_nfs4_file(fp); | 231 | get_nfs4_file(fp); |
232 | dp->dl_file = fp; | 232 | dp->dl_file = fp; |
233 | nfs4_file_get_access(fp, O_RDONLY); | 233 | dp->dl_vfs_file = find_readable_file(fp); |
234 | get_file(dp->dl_vfs_file); | ||
234 | dp->dl_flock = NULL; | 235 | dp->dl_flock = NULL; |
235 | dp->dl_type = type; | 236 | dp->dl_type = type; |
236 | dp->dl_stateid.si_boot = boot_time; | 237 | dp->dl_stateid.si_boot = boot_time; |
@@ -252,6 +253,7 @@ nfs4_put_delegation(struct nfs4_delegation *dp) | |||
252 | if (atomic_dec_and_test(&dp->dl_count)) { | 253 | if (atomic_dec_and_test(&dp->dl_count)) { |
253 | dprintk("NFSD: freeing dp %p\n",dp); | 254 | dprintk("NFSD: freeing dp %p\n",dp); |
254 | put_nfs4_file(dp->dl_file); | 255 | put_nfs4_file(dp->dl_file); |
256 | fput(dp->dl_vfs_file); | ||
255 | kmem_cache_free(deleg_slab, dp); | 257 | kmem_cache_free(deleg_slab, dp); |
256 | num_delegations--; | 258 | num_delegations--; |
257 | } | 259 | } |
@@ -265,12 +267,10 @@ nfs4_put_delegation(struct nfs4_delegation *dp) | |||
265 | static void | 267 | static void |
266 | nfs4_close_delegation(struct nfs4_delegation *dp) | 268 | nfs4_close_delegation(struct nfs4_delegation *dp) |
267 | { | 269 | { |
268 | struct file *filp = find_readable_file(dp->dl_file); | ||
269 | |||
270 | dprintk("NFSD: close_delegation dp %p\n",dp); | 270 | dprintk("NFSD: close_delegation dp %p\n",dp); |
271 | /* XXX: do we even need this check?: */ | ||
271 | if (dp->dl_flock) | 272 | if (dp->dl_flock) |
272 | vfs_setlease(filp, F_UNLCK, &dp->dl_flock); | 273 | vfs_setlease(dp->dl_vfs_file, F_UNLCK, &dp->dl_flock); |
273 | nfs4_file_put_access(dp->dl_file, O_RDONLY); | ||
274 | } | 274 | } |
275 | 275 | ||
276 | /* Called under the state lock. */ | 276 | /* Called under the state lock. */ |
@@ -642,6 +642,7 @@ static void nfsd4_conn_lost(struct svc_xpt_user *u) | |||
642 | free_conn(c); | 642 | free_conn(c); |
643 | } | 643 | } |
644 | spin_unlock(&clp->cl_lock); | 644 | spin_unlock(&clp->cl_lock); |
645 | nfsd4_probe_callback(clp); | ||
645 | } | 646 | } |
646 | 647 | ||
647 | static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags) | 648 | static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags) |
@@ -679,15 +680,12 @@ static int nfsd4_register_conn(struct nfsd4_conn *conn) | |||
679 | return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user); | 680 | return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user); |
680 | } | 681 | } |
681 | 682 | ||
682 | static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses) | 683 | static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses, u32 dir) |
683 | { | 684 | { |
684 | struct nfsd4_conn *conn; | 685 | struct nfsd4_conn *conn; |
685 | u32 flags = NFS4_CDFC4_FORE; | ||
686 | int ret; | 686 | int ret; |
687 | 687 | ||
688 | if (ses->se_flags & SESSION4_BACK_CHAN) | 688 | conn = alloc_conn(rqstp, dir); |
689 | flags |= NFS4_CDFC4_BACK; | ||
690 | conn = alloc_conn(rqstp, flags); | ||
691 | if (!conn) | 689 | if (!conn) |
692 | return nfserr_jukebox; | 690 | return nfserr_jukebox; |
693 | nfsd4_hash_conn(conn, ses); | 691 | nfsd4_hash_conn(conn, ses); |
@@ -698,6 +696,17 @@ static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses) | |||
698 | return nfs_ok; | 696 | return nfs_ok; |
699 | } | 697 | } |
700 | 698 | ||
699 | static __be32 nfsd4_new_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_session *ses) | ||
700 | { | ||
701 | u32 dir = NFS4_CDFC4_FORE; | ||
702 | |||
703 | if (ses->se_flags & SESSION4_BACK_CHAN) | ||
704 | dir |= NFS4_CDFC4_BACK; | ||
705 | |||
706 | return nfsd4_new_conn(rqstp, ses, dir); | ||
707 | } | ||
708 | |||
709 | /* must be called under client_lock */ | ||
701 | static void nfsd4_del_conns(struct nfsd4_session *s) | 710 | static void nfsd4_del_conns(struct nfsd4_session *s) |
702 | { | 711 | { |
703 | struct nfs4_client *clp = s->se_client; | 712 | struct nfs4_client *clp = s->se_client; |
@@ -749,6 +758,8 @@ static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct n | |||
749 | */ | 758 | */ |
750 | slotsize = nfsd4_sanitize_slot_size(fchan->maxresp_cached); | 759 | slotsize = nfsd4_sanitize_slot_size(fchan->maxresp_cached); |
751 | numslots = nfsd4_get_drc_mem(slotsize, fchan->maxreqs); | 760 | numslots = nfsd4_get_drc_mem(slotsize, fchan->maxreqs); |
761 | if (numslots < 1) | ||
762 | return NULL; | ||
752 | 763 | ||
753 | new = alloc_session(slotsize, numslots); | 764 | new = alloc_session(slotsize, numslots); |
754 | if (!new) { | 765 | if (!new) { |
@@ -769,25 +780,30 @@ static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct n | |||
769 | idx = hash_sessionid(&new->se_sessionid); | 780 | idx = hash_sessionid(&new->se_sessionid); |
770 | spin_lock(&client_lock); | 781 | spin_lock(&client_lock); |
771 | list_add(&new->se_hash, &sessionid_hashtbl[idx]); | 782 | list_add(&new->se_hash, &sessionid_hashtbl[idx]); |
783 | spin_lock(&clp->cl_lock); | ||
772 | list_add(&new->se_perclnt, &clp->cl_sessions); | 784 | list_add(&new->se_perclnt, &clp->cl_sessions); |
785 | spin_unlock(&clp->cl_lock); | ||
773 | spin_unlock(&client_lock); | 786 | spin_unlock(&client_lock); |
774 | 787 | ||
775 | status = nfsd4_new_conn(rqstp, new); | 788 | status = nfsd4_new_conn_from_crses(rqstp, new); |
776 | /* whoops: benny points out, status is ignored! (err, or bogus) */ | 789 | /* whoops: benny points out, status is ignored! (err, or bogus) */ |
777 | if (status) { | 790 | if (status) { |
778 | free_session(&new->se_ref); | 791 | free_session(&new->se_ref); |
779 | return NULL; | 792 | return NULL; |
780 | } | 793 | } |
781 | if (!clp->cl_cb_session && (cses->flags & SESSION4_BACK_CHAN)) { | 794 | if (cses->flags & SESSION4_BACK_CHAN) { |
782 | struct sockaddr *sa = svc_addr(rqstp); | 795 | struct sockaddr *sa = svc_addr(rqstp); |
783 | 796 | /* | |
784 | clp->cl_cb_session = new; | 797 | * This is a little silly; with sessions there's no real |
785 | clp->cl_cb_conn.cb_xprt = rqstp->rq_xprt; | 798 | * use for the callback address. Use the peer address |
786 | svc_xprt_get(rqstp->rq_xprt); | 799 | * as a reasonable default for now, but consider fixing |
800 | * the rpc client not to require an address in the | ||
801 | * future: | ||
802 | */ | ||
787 | rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa); | 803 | rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa); |
788 | clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa); | 804 | clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa); |
789 | nfsd4_probe_callback(clp); | ||
790 | } | 805 | } |
806 | nfsd4_probe_callback(clp); | ||
791 | return new; | 807 | return new; |
792 | } | 808 | } |
793 | 809 | ||
@@ -817,7 +833,9 @@ static void | |||
817 | unhash_session(struct nfsd4_session *ses) | 833 | unhash_session(struct nfsd4_session *ses) |
818 | { | 834 | { |
819 | list_del(&ses->se_hash); | 835 | list_del(&ses->se_hash); |
836 | spin_lock(&ses->se_client->cl_lock); | ||
820 | list_del(&ses->se_perclnt); | 837 | list_del(&ses->se_perclnt); |
838 | spin_unlock(&ses->se_client->cl_lock); | ||
821 | } | 839 | } |
822 | 840 | ||
823 | /* must be called under the client_lock */ | 841 | /* must be called under the client_lock */ |
@@ -923,8 +941,10 @@ unhash_client_locked(struct nfs4_client *clp) | |||
923 | 941 | ||
924 | mark_client_expired(clp); | 942 | mark_client_expired(clp); |
925 | list_del(&clp->cl_lru); | 943 | list_del(&clp->cl_lru); |
944 | spin_lock(&clp->cl_lock); | ||
926 | list_for_each_entry(ses, &clp->cl_sessions, se_perclnt) | 945 | list_for_each_entry(ses, &clp->cl_sessions, se_perclnt) |
927 | list_del_init(&ses->se_hash); | 946 | list_del_init(&ses->se_hash); |
947 | spin_unlock(&clp->cl_lock); | ||
928 | } | 948 | } |
929 | 949 | ||
930 | static void | 950 | static void |
@@ -1051,12 +1071,13 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, | |||
1051 | 1071 | ||
1052 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); | 1072 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); |
1053 | atomic_set(&clp->cl_refcount, 0); | 1073 | atomic_set(&clp->cl_refcount, 0); |
1054 | atomic_set(&clp->cl_cb_set, 0); | 1074 | clp->cl_cb_state = NFSD4_CB_UNKNOWN; |
1055 | INIT_LIST_HEAD(&clp->cl_idhash); | 1075 | INIT_LIST_HEAD(&clp->cl_idhash); |
1056 | INIT_LIST_HEAD(&clp->cl_strhash); | 1076 | INIT_LIST_HEAD(&clp->cl_strhash); |
1057 | INIT_LIST_HEAD(&clp->cl_openowners); | 1077 | INIT_LIST_HEAD(&clp->cl_openowners); |
1058 | INIT_LIST_HEAD(&clp->cl_delegations); | 1078 | INIT_LIST_HEAD(&clp->cl_delegations); |
1059 | INIT_LIST_HEAD(&clp->cl_lru); | 1079 | INIT_LIST_HEAD(&clp->cl_lru); |
1080 | INIT_LIST_HEAD(&clp->cl_callbacks); | ||
1060 | spin_lock_init(&clp->cl_lock); | 1081 | spin_lock_init(&clp->cl_lock); |
1061 | INIT_WORK(&clp->cl_cb_null.cb_work, nfsd4_do_callback_rpc); | 1082 | INIT_WORK(&clp->cl_cb_null.cb_work, nfsd4_do_callback_rpc); |
1062 | clp->cl_time = get_seconds(); | 1083 | clp->cl_time = get_seconds(); |
@@ -1132,54 +1153,55 @@ find_unconfirmed_client(clientid_t *clid) | |||
1132 | return NULL; | 1153 | return NULL; |
1133 | } | 1154 | } |
1134 | 1155 | ||
1135 | /* | 1156 | static bool clp_used_exchangeid(struct nfs4_client *clp) |
1136 | * Return 1 iff clp's clientid establishment method matches the use_exchange_id | ||
1137 | * parameter. Matching is based on the fact the at least one of the | ||
1138 | * EXCHGID4_FLAG_USE_{NON_PNFS,PNFS_MDS,PNFS_DS} flags must be set for v4.1 | ||
1139 | * | ||
1140 | * FIXME: we need to unify the clientid namespaces for nfsv4.x | ||
1141 | * and correctly deal with client upgrade/downgrade in EXCHANGE_ID | ||
1142 | * and SET_CLIENTID{,_CONFIRM} | ||
1143 | */ | ||
1144 | static inline int | ||
1145 | match_clientid_establishment(struct nfs4_client *clp, bool use_exchange_id) | ||
1146 | { | 1157 | { |
1147 | bool has_exchange_flags = (clp->cl_exchange_flags != 0); | 1158 | return clp->cl_exchange_flags != 0; |
1148 | return use_exchange_id == has_exchange_flags; | 1159 | } |
1149 | } | ||
1150 | 1160 | ||
1151 | static struct nfs4_client * | 1161 | static struct nfs4_client * |
1152 | find_confirmed_client_by_str(const char *dname, unsigned int hashval, | 1162 | find_confirmed_client_by_str(const char *dname, unsigned int hashval) |
1153 | bool use_exchange_id) | ||
1154 | { | 1163 | { |
1155 | struct nfs4_client *clp; | 1164 | struct nfs4_client *clp; |
1156 | 1165 | ||
1157 | list_for_each_entry(clp, &conf_str_hashtbl[hashval], cl_strhash) { | 1166 | list_for_each_entry(clp, &conf_str_hashtbl[hashval], cl_strhash) { |
1158 | if (same_name(clp->cl_recdir, dname) && | 1167 | if (same_name(clp->cl_recdir, dname)) |
1159 | match_clientid_establishment(clp, use_exchange_id)) | ||
1160 | return clp; | 1168 | return clp; |
1161 | } | 1169 | } |
1162 | return NULL; | 1170 | return NULL; |
1163 | } | 1171 | } |
1164 | 1172 | ||
1165 | static struct nfs4_client * | 1173 | static struct nfs4_client * |
1166 | find_unconfirmed_client_by_str(const char *dname, unsigned int hashval, | 1174 | find_unconfirmed_client_by_str(const char *dname, unsigned int hashval) |
1167 | bool use_exchange_id) | ||
1168 | { | 1175 | { |
1169 | struct nfs4_client *clp; | 1176 | struct nfs4_client *clp; |
1170 | 1177 | ||
1171 | list_for_each_entry(clp, &unconf_str_hashtbl[hashval], cl_strhash) { | 1178 | list_for_each_entry(clp, &unconf_str_hashtbl[hashval], cl_strhash) { |
1172 | if (same_name(clp->cl_recdir, dname) && | 1179 | if (same_name(clp->cl_recdir, dname)) |
1173 | match_clientid_establishment(clp, use_exchange_id)) | ||
1174 | return clp; | 1180 | return clp; |
1175 | } | 1181 | } |
1176 | return NULL; | 1182 | return NULL; |
1177 | } | 1183 | } |
1178 | 1184 | ||
1185 | static void rpc_svcaddr2sockaddr(struct sockaddr *sa, unsigned short family, union svc_addr_u *svcaddr) | ||
1186 | { | ||
1187 | switch (family) { | ||
1188 | case AF_INET: | ||
1189 | ((struct sockaddr_in *)sa)->sin_family = AF_INET; | ||
1190 | ((struct sockaddr_in *)sa)->sin_addr = svcaddr->addr; | ||
1191 | return; | ||
1192 | case AF_INET6: | ||
1193 | ((struct sockaddr_in6 *)sa)->sin6_family = AF_INET6; | ||
1194 | ((struct sockaddr_in6 *)sa)->sin6_addr = svcaddr->addr6; | ||
1195 | return; | ||
1196 | } | ||
1197 | } | ||
1198 | |||
1179 | static void | 1199 | static void |
1180 | gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, u32 scopeid) | 1200 | gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_rqst *rqstp) |
1181 | { | 1201 | { |
1182 | struct nfs4_cb_conn *conn = &clp->cl_cb_conn; | 1202 | struct nfs4_cb_conn *conn = &clp->cl_cb_conn; |
1203 | struct sockaddr *sa = svc_addr(rqstp); | ||
1204 | u32 scopeid = rpc_get_scope_id(sa); | ||
1183 | unsigned short expected_family; | 1205 | unsigned short expected_family; |
1184 | 1206 | ||
1185 | /* Currently, we only support tcp and tcp6 for the callback channel */ | 1207 | /* Currently, we only support tcp and tcp6 for the callback channel */ |
@@ -1205,6 +1227,7 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, u32 scopeid) | |||
1205 | 1227 | ||
1206 | conn->cb_prog = se->se_callback_prog; | 1228 | conn->cb_prog = se->se_callback_prog; |
1207 | conn->cb_ident = se->se_callback_ident; | 1229 | conn->cb_ident = se->se_callback_ident; |
1230 | rpc_svcaddr2sockaddr((struct sockaddr *)&conn->cb_saddr, expected_family, &rqstp->rq_daddr); | ||
1208 | return; | 1231 | return; |
1209 | out_err: | 1232 | out_err: |
1210 | conn->cb_addr.ss_family = AF_UNSPEC; | 1233 | conn->cb_addr.ss_family = AF_UNSPEC; |
@@ -1344,7 +1367,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
1344 | case SP4_NONE: | 1367 | case SP4_NONE: |
1345 | break; | 1368 | break; |
1346 | case SP4_SSV: | 1369 | case SP4_SSV: |
1347 | return nfserr_encr_alg_unsupp; | 1370 | return nfserr_serverfault; |
1348 | default: | 1371 | default: |
1349 | BUG(); /* checked by xdr code */ | 1372 | BUG(); /* checked by xdr code */ |
1350 | case SP4_MACH_CRED: | 1373 | case SP4_MACH_CRED: |
@@ -1361,8 +1384,12 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
1361 | nfs4_lock_state(); | 1384 | nfs4_lock_state(); |
1362 | status = nfs_ok; | 1385 | status = nfs_ok; |
1363 | 1386 | ||
1364 | conf = find_confirmed_client_by_str(dname, strhashval, true); | 1387 | conf = find_confirmed_client_by_str(dname, strhashval); |
1365 | if (conf) { | 1388 | if (conf) { |
1389 | if (!clp_used_exchangeid(conf)) { | ||
1390 | status = nfserr_clid_inuse; /* XXX: ? */ | ||
1391 | goto out; | ||
1392 | } | ||
1366 | if (!same_verf(&verf, &conf->cl_verifier)) { | 1393 | if (!same_verf(&verf, &conf->cl_verifier)) { |
1367 | /* 18.35.4 case 8 */ | 1394 | /* 18.35.4 case 8 */ |
1368 | if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { | 1395 | if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { |
@@ -1403,7 +1430,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
1403 | goto out; | 1430 | goto out; |
1404 | } | 1431 | } |
1405 | 1432 | ||
1406 | unconf = find_unconfirmed_client_by_str(dname, strhashval, true); | 1433 | unconf = find_unconfirmed_client_by_str(dname, strhashval); |
1407 | if (unconf) { | 1434 | if (unconf) { |
1408 | /* | 1435 | /* |
1409 | * Possible retry or client restart. Per 18.35.4 case 4, | 1436 | * Possible retry or client restart. Per 18.35.4 case 4, |
@@ -1560,6 +1587,8 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1560 | status = nfs_ok; | 1587 | status = nfs_ok; |
1561 | memcpy(cr_ses->sessionid.data, new->se_sessionid.data, | 1588 | memcpy(cr_ses->sessionid.data, new->se_sessionid.data, |
1562 | NFS4_MAX_SESSIONID_LEN); | 1589 | NFS4_MAX_SESSIONID_LEN); |
1590 | memcpy(&cr_ses->fore_channel, &new->se_fchannel, | ||
1591 | sizeof(struct nfsd4_channel_attrs)); | ||
1563 | cs_slot->sl_seqid++; | 1592 | cs_slot->sl_seqid++; |
1564 | cr_ses->seqid = cs_slot->sl_seqid; | 1593 | cr_ses->seqid = cs_slot->sl_seqid; |
1565 | 1594 | ||
@@ -1581,6 +1610,45 @@ static bool nfsd4_last_compound_op(struct svc_rqst *rqstp) | |||
1581 | return argp->opcnt == resp->opcnt; | 1610 | return argp->opcnt == resp->opcnt; |
1582 | } | 1611 | } |
1583 | 1612 | ||
1613 | static __be32 nfsd4_map_bcts_dir(u32 *dir) | ||
1614 | { | ||
1615 | switch (*dir) { | ||
1616 | case NFS4_CDFC4_FORE: | ||
1617 | case NFS4_CDFC4_BACK: | ||
1618 | return nfs_ok; | ||
1619 | case NFS4_CDFC4_FORE_OR_BOTH: | ||
1620 | case NFS4_CDFC4_BACK_OR_BOTH: | ||
1621 | *dir = NFS4_CDFC4_BOTH; | ||
1622 | return nfs_ok; | ||
1623 | }; | ||
1624 | return nfserr_inval; | ||
1625 | } | ||
1626 | |||
1627 | __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, | ||
1628 | struct nfsd4_compound_state *cstate, | ||
1629 | struct nfsd4_bind_conn_to_session *bcts) | ||
1630 | { | ||
1631 | __be32 status; | ||
1632 | |||
1633 | if (!nfsd4_last_compound_op(rqstp)) | ||
1634 | return nfserr_not_only_op; | ||
1635 | spin_lock(&client_lock); | ||
1636 | cstate->session = find_in_sessionid_hashtbl(&bcts->sessionid); | ||
1637 | /* Sorta weird: we only need the refcnt'ing because new_conn acquires | ||
1638 | * client_lock iself: */ | ||
1639 | if (cstate->session) { | ||
1640 | nfsd4_get_session(cstate->session); | ||
1641 | atomic_inc(&cstate->session->se_client->cl_refcount); | ||
1642 | } | ||
1643 | spin_unlock(&client_lock); | ||
1644 | if (!cstate->session) | ||
1645 | return nfserr_badsession; | ||
1646 | |||
1647 | status = nfsd4_map_bcts_dir(&bcts->dir); | ||
1648 | nfsd4_new_conn(rqstp, cstate->session, bcts->dir); | ||
1649 | return nfs_ok; | ||
1650 | } | ||
1651 | |||
1584 | static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid) | 1652 | static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid) |
1585 | { | 1653 | { |
1586 | if (!session) | 1654 | if (!session) |
@@ -1619,8 +1687,7 @@ nfsd4_destroy_session(struct svc_rqst *r, | |||
1619 | spin_unlock(&client_lock); | 1687 | spin_unlock(&client_lock); |
1620 | 1688 | ||
1621 | nfs4_lock_state(); | 1689 | nfs4_lock_state(); |
1622 | /* wait for callbacks */ | 1690 | nfsd4_probe_callback_sync(ses->se_client); |
1623 | nfsd4_shutdown_callback(ses->se_client); | ||
1624 | nfs4_unlock_state(); | 1691 | nfs4_unlock_state(); |
1625 | 1692 | ||
1626 | nfsd4_del_conns(ses); | 1693 | nfsd4_del_conns(ses); |
@@ -1733,8 +1800,12 @@ nfsd4_sequence(struct svc_rqst *rqstp, | |||
1733 | out: | 1800 | out: |
1734 | /* Hold a session reference until done processing the compound. */ | 1801 | /* Hold a session reference until done processing the compound. */ |
1735 | if (cstate->session) { | 1802 | if (cstate->session) { |
1803 | struct nfs4_client *clp = session->se_client; | ||
1804 | |||
1736 | nfsd4_get_session(cstate->session); | 1805 | nfsd4_get_session(cstate->session); |
1737 | atomic_inc(&session->se_client->cl_refcount); | 1806 | atomic_inc(&clp->cl_refcount); |
1807 | if (clp->cl_cb_state == NFSD4_CB_DOWN) | ||
1808 | seq->status_flags |= SEQ4_STATUS_CB_PATH_DOWN; | ||
1738 | } | 1809 | } |
1739 | kfree(conn); | 1810 | kfree(conn); |
1740 | spin_unlock(&client_lock); | 1811 | spin_unlock(&client_lock); |
@@ -1775,7 +1846,6 @@ __be32 | |||
1775 | nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 1846 | nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
1776 | struct nfsd4_setclientid *setclid) | 1847 | struct nfsd4_setclientid *setclid) |
1777 | { | 1848 | { |
1778 | struct sockaddr *sa = svc_addr(rqstp); | ||
1779 | struct xdr_netobj clname = { | 1849 | struct xdr_netobj clname = { |
1780 | .len = setclid->se_namelen, | 1850 | .len = setclid->se_namelen, |
1781 | .data = setclid->se_name, | 1851 | .data = setclid->se_name, |
@@ -1801,10 +1871,12 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
1801 | strhashval = clientstr_hashval(dname); | 1871 | strhashval = clientstr_hashval(dname); |
1802 | 1872 | ||
1803 | nfs4_lock_state(); | 1873 | nfs4_lock_state(); |
1804 | conf = find_confirmed_client_by_str(dname, strhashval, false); | 1874 | conf = find_confirmed_client_by_str(dname, strhashval); |
1805 | if (conf) { | 1875 | if (conf) { |
1806 | /* RFC 3530 14.2.33 CASE 0: */ | 1876 | /* RFC 3530 14.2.33 CASE 0: */ |
1807 | status = nfserr_clid_inuse; | 1877 | status = nfserr_clid_inuse; |
1878 | if (clp_used_exchangeid(conf)) | ||
1879 | goto out; | ||
1808 | if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { | 1880 | if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { |
1809 | char addr_str[INET6_ADDRSTRLEN]; | 1881 | char addr_str[INET6_ADDRSTRLEN]; |
1810 | rpc_ntop((struct sockaddr *) &conf->cl_addr, addr_str, | 1882 | rpc_ntop((struct sockaddr *) &conf->cl_addr, addr_str, |
@@ -1819,7 +1891,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
1819 | * has a description of SETCLIENTID request processing consisting | 1891 | * has a description of SETCLIENTID request processing consisting |
1820 | * of 5 bullet points, labeled as CASE0 - CASE4 below. | 1892 | * of 5 bullet points, labeled as CASE0 - CASE4 below. |
1821 | */ | 1893 | */ |
1822 | unconf = find_unconfirmed_client_by_str(dname, strhashval, false); | 1894 | unconf = find_unconfirmed_client_by_str(dname, strhashval); |
1823 | status = nfserr_resource; | 1895 | status = nfserr_resource; |
1824 | if (!conf) { | 1896 | if (!conf) { |
1825 | /* | 1897 | /* |
@@ -1876,7 +1948,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
1876 | * for consistent minorversion use throughout: | 1948 | * for consistent minorversion use throughout: |
1877 | */ | 1949 | */ |
1878 | new->cl_minorversion = 0; | 1950 | new->cl_minorversion = 0; |
1879 | gen_callback(new, setclid, rpc_get_scope_id(sa)); | 1951 | gen_callback(new, setclid, rqstp); |
1880 | add_to_unconfirmed(new, strhashval); | 1952 | add_to_unconfirmed(new, strhashval); |
1881 | setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot; | 1953 | setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot; |
1882 | setclid->se_clientid.cl_id = new->cl_clientid.cl_id; | 1954 | setclid->se_clientid.cl_id = new->cl_clientid.cl_id; |
@@ -1935,7 +2007,6 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | |||
1935 | if (!same_creds(&conf->cl_cred, &unconf->cl_cred)) | 2007 | if (!same_creds(&conf->cl_cred, &unconf->cl_cred)) |
1936 | status = nfserr_clid_inuse; | 2008 | status = nfserr_clid_inuse; |
1937 | else { | 2009 | else { |
1938 | atomic_set(&conf->cl_cb_set, 0); | ||
1939 | nfsd4_change_callback(conf, &unconf->cl_cb_conn); | 2010 | nfsd4_change_callback(conf, &unconf->cl_cb_conn); |
1940 | nfsd4_probe_callback(conf); | 2011 | nfsd4_probe_callback(conf); |
1941 | expire_client(unconf); | 2012 | expire_client(unconf); |
@@ -1964,7 +2035,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | |||
1964 | unsigned int hash = | 2035 | unsigned int hash = |
1965 | clientstr_hashval(unconf->cl_recdir); | 2036 | clientstr_hashval(unconf->cl_recdir); |
1966 | conf = find_confirmed_client_by_str(unconf->cl_recdir, | 2037 | conf = find_confirmed_client_by_str(unconf->cl_recdir, |
1967 | hash, false); | 2038 | hash); |
1968 | if (conf) { | 2039 | if (conf) { |
1969 | nfsd4_remove_clid_dir(conf); | 2040 | nfsd4_remove_clid_dir(conf); |
1970 | expire_client(conf); | 2041 | expire_client(conf); |
@@ -2300,41 +2371,6 @@ void nfsd_break_deleg_cb(struct file_lock *fl) | |||
2300 | nfsd4_cb_recall(dp); | 2371 | nfsd4_cb_recall(dp); |
2301 | } | 2372 | } |
2302 | 2373 | ||
2303 | /* | ||
2304 | * The file_lock is being reapd. | ||
2305 | * | ||
2306 | * Called by locks_free_lock() with lock_flocks() held. | ||
2307 | */ | ||
2308 | static | ||
2309 | void nfsd_release_deleg_cb(struct file_lock *fl) | ||
2310 | { | ||
2311 | struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner; | ||
2312 | |||
2313 | dprintk("NFSD nfsd_release_deleg_cb: fl %p dp %p dl_count %d\n", fl,dp, atomic_read(&dp->dl_count)); | ||
2314 | |||
2315 | if (!(fl->fl_flags & FL_LEASE) || !dp) | ||
2316 | return; | ||
2317 | dp->dl_flock = NULL; | ||
2318 | } | ||
2319 | |||
2320 | /* | ||
2321 | * Called from setlease() with lock_flocks() held | ||
2322 | */ | ||
2323 | static | ||
2324 | int nfsd_same_client_deleg_cb(struct file_lock *onlist, struct file_lock *try) | ||
2325 | { | ||
2326 | struct nfs4_delegation *onlistd = | ||
2327 | (struct nfs4_delegation *)onlist->fl_owner; | ||
2328 | struct nfs4_delegation *tryd = | ||
2329 | (struct nfs4_delegation *)try->fl_owner; | ||
2330 | |||
2331 | if (onlist->fl_lmops != try->fl_lmops) | ||
2332 | return 0; | ||
2333 | |||
2334 | return onlistd->dl_client == tryd->dl_client; | ||
2335 | } | ||
2336 | |||
2337 | |||
2338 | static | 2374 | static |
2339 | int nfsd_change_deleg_cb(struct file_lock **onlist, int arg) | 2375 | int nfsd_change_deleg_cb(struct file_lock **onlist, int arg) |
2340 | { | 2376 | { |
@@ -2346,8 +2382,6 @@ int nfsd_change_deleg_cb(struct file_lock **onlist, int arg) | |||
2346 | 2382 | ||
2347 | static const struct lock_manager_operations nfsd_lease_mng_ops = { | 2383 | static const struct lock_manager_operations nfsd_lease_mng_ops = { |
2348 | .fl_break = nfsd_break_deleg_cb, | 2384 | .fl_break = nfsd_break_deleg_cb, |
2349 | .fl_release_private = nfsd_release_deleg_cb, | ||
2350 | .fl_mylease = nfsd_same_client_deleg_cb, | ||
2351 | .fl_change = nfsd_change_deleg_cb, | 2385 | .fl_change = nfsd_change_deleg_cb, |
2352 | }; | 2386 | }; |
2353 | 2387 | ||
@@ -2514,8 +2548,6 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file | |||
2514 | if (!fp->fi_fds[oflag]) { | 2548 | if (!fp->fi_fds[oflag]) { |
2515 | status = nfsd_open(rqstp, cur_fh, S_IFREG, access, | 2549 | status = nfsd_open(rqstp, cur_fh, S_IFREG, access, |
2516 | &fp->fi_fds[oflag]); | 2550 | &fp->fi_fds[oflag]); |
2517 | if (status == nfserr_dropit) | ||
2518 | status = nfserr_jukebox; | ||
2519 | if (status) | 2551 | if (status) |
2520 | return status; | 2552 | return status; |
2521 | } | 2553 | } |
@@ -2596,6 +2628,19 @@ nfs4_set_claim_prev(struct nfsd4_open *open) | |||
2596 | open->op_stateowner->so_client->cl_firststate = 1; | 2628 | open->op_stateowner->so_client->cl_firststate = 1; |
2597 | } | 2629 | } |
2598 | 2630 | ||
2631 | /* Should we give out recallable state?: */ | ||
2632 | static bool nfsd4_cb_channel_good(struct nfs4_client *clp) | ||
2633 | { | ||
2634 | if (clp->cl_cb_state == NFSD4_CB_UP) | ||
2635 | return true; | ||
2636 | /* | ||
2637 | * In the sessions case, since we don't have to establish a | ||
2638 | * separate connection for callbacks, we assume it's OK | ||
2639 | * until we hear otherwise: | ||
2640 | */ | ||
2641 | return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN; | ||
2642 | } | ||
2643 | |||
2599 | /* | 2644 | /* |
2600 | * Attempt to hand out a delegation. | 2645 | * Attempt to hand out a delegation. |
2601 | */ | 2646 | */ |
@@ -2604,10 +2649,11 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta | |||
2604 | { | 2649 | { |
2605 | struct nfs4_delegation *dp; | 2650 | struct nfs4_delegation *dp; |
2606 | struct nfs4_stateowner *sop = stp->st_stateowner; | 2651 | struct nfs4_stateowner *sop = stp->st_stateowner; |
2607 | int cb_up = atomic_read(&sop->so_client->cl_cb_set); | 2652 | int cb_up; |
2608 | struct file_lock *fl; | 2653 | struct file_lock *fl; |
2609 | int status, flag = 0; | 2654 | int status, flag = 0; |
2610 | 2655 | ||
2656 | cb_up = nfsd4_cb_channel_good(sop->so_client); | ||
2611 | flag = NFS4_OPEN_DELEGATE_NONE; | 2657 | flag = NFS4_OPEN_DELEGATE_NONE; |
2612 | open->op_recall = 0; | 2658 | open->op_recall = 0; |
2613 | switch (open->op_claim_type) { | 2659 | switch (open->op_claim_type) { |
@@ -2655,7 +2701,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta | |||
2655 | dp->dl_flock = fl; | 2701 | dp->dl_flock = fl; |
2656 | 2702 | ||
2657 | /* vfs_setlease checks to see if delegation should be handed out. | 2703 | /* vfs_setlease checks to see if delegation should be handed out. |
2658 | * the lock_manager callbacks fl_mylease and fl_change are used | 2704 | * the lock_manager callback fl_change is used |
2659 | */ | 2705 | */ |
2660 | if ((status = vfs_setlease(fl->fl_file, fl->fl_type, &fl))) { | 2706 | if ((status = vfs_setlease(fl->fl_file, fl->fl_type, &fl))) { |
2661 | dprintk("NFSD: setlease failed [%d], no delegation\n", status); | 2707 | dprintk("NFSD: setlease failed [%d], no delegation\n", status); |
@@ -2794,7 +2840,7 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2794 | renew_client(clp); | 2840 | renew_client(clp); |
2795 | status = nfserr_cb_path_down; | 2841 | status = nfserr_cb_path_down; |
2796 | if (!list_empty(&clp->cl_delegations) | 2842 | if (!list_empty(&clp->cl_delegations) |
2797 | && !atomic_read(&clp->cl_cb_set)) | 2843 | && clp->cl_cb_state != NFSD4_CB_UP) |
2798 | goto out; | 2844 | goto out; |
2799 | status = nfs_ok; | 2845 | status = nfs_ok; |
2800 | out: | 2846 | out: |
@@ -3081,9 +3127,10 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, | |||
3081 | if (status) | 3127 | if (status) |
3082 | goto out; | 3128 | goto out; |
3083 | renew_client(dp->dl_client); | 3129 | renew_client(dp->dl_client); |
3084 | if (filpp) | 3130 | if (filpp) { |
3085 | *filpp = find_readable_file(dp->dl_file); | 3131 | *filpp = find_readable_file(dp->dl_file); |
3086 | BUG_ON(!*filpp); | 3132 | BUG_ON(!*filpp); |
3133 | } | ||
3087 | } else { /* open or lock stateid */ | 3134 | } else { /* open or lock stateid */ |
3088 | stp = find_stateid(stateid, flags); | 3135 | stp = find_stateid(stateid, flags); |
3089 | if (!stp) | 3136 | if (!stp) |
@@ -4107,7 +4154,7 @@ nfs4_has_reclaimed_state(const char *name, bool use_exchange_id) | |||
4107 | unsigned int strhashval = clientstr_hashval(name); | 4154 | unsigned int strhashval = clientstr_hashval(name); |
4108 | struct nfs4_client *clp; | 4155 | struct nfs4_client *clp; |
4109 | 4156 | ||
4110 | clp = find_confirmed_client_by_str(name, strhashval, use_exchange_id); | 4157 | clp = find_confirmed_client_by_str(name, strhashval); |
4111 | return clp ? 1 : 0; | 4158 | return clp ? 1 : 0; |
4112 | } | 4159 | } |
4113 | 4160 | ||