diff options
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r-- | fs/nfsd/nfs4state.c | 1015 |
1 files changed, 595 insertions, 420 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index d0237f872cc4..ac8ed96c4199 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -44,16 +44,11 @@ | |||
44 | #include "xdr4.h" | 44 | #include "xdr4.h" |
45 | #include "vfs.h" | 45 | #include "vfs.h" |
46 | #include "current_stateid.h" | 46 | #include "current_stateid.h" |
47 | #include "fault_inject.h" | ||
48 | 47 | ||
49 | #include "netns.h" | 48 | #include "netns.h" |
50 | 49 | ||
51 | #define NFSDDBG_FACILITY NFSDDBG_PROC | 50 | #define NFSDDBG_FACILITY NFSDDBG_PROC |
52 | 51 | ||
53 | /* Globals */ | ||
54 | time_t nfsd4_lease = 90; /* default lease time */ | ||
55 | time_t nfsd4_grace = 90; | ||
56 | |||
57 | #define all_ones {{~0,~0},~0} | 52 | #define all_ones {{~0,~0},~0} |
58 | static const stateid_t one_stateid = { | 53 | static const stateid_t one_stateid = { |
59 | .si_generation = ~0, | 54 | .si_generation = ~0, |
@@ -176,8 +171,6 @@ static unsigned int ownerstr_hashval(u32 clientid, struct xdr_netobj *ownername) | |||
176 | return ret & OWNER_HASH_MASK; | 171 | return ret & OWNER_HASH_MASK; |
177 | } | 172 | } |
178 | 173 | ||
179 | static struct list_head ownerstr_hashtbl[OWNER_HASH_SIZE]; | ||
180 | |||
181 | /* hash table for nfs4_file */ | 174 | /* hash table for nfs4_file */ |
182 | #define FILE_HASH_BITS 8 | 175 | #define FILE_HASH_BITS 8 |
183 | #define FILE_HASH_SIZE (1 << FILE_HASH_BITS) | 176 | #define FILE_HASH_SIZE (1 << FILE_HASH_BITS) |
@@ -192,7 +185,7 @@ static struct list_head file_hashtbl[FILE_HASH_SIZE]; | |||
192 | 185 | ||
193 | static void __nfs4_file_get_access(struct nfs4_file *fp, int oflag) | 186 | static void __nfs4_file_get_access(struct nfs4_file *fp, int oflag) |
194 | { | 187 | { |
195 | BUG_ON(!(fp->fi_fds[oflag] || fp->fi_fds[O_RDWR])); | 188 | WARN_ON_ONCE(!(fp->fi_fds[oflag] || fp->fi_fds[O_RDWR])); |
196 | atomic_inc(&fp->fi_access[oflag]); | 189 | atomic_inc(&fp->fi_access[oflag]); |
197 | } | 190 | } |
198 | 191 | ||
@@ -251,7 +244,7 @@ static inline int get_new_stid(struct nfs4_stid *stid) | |||
251 | * preallocations that can exist at a time, but the state lock | 244 | * preallocations that can exist at a time, but the state lock |
252 | * prevents anyone from using ours before we get here: | 245 | * prevents anyone from using ours before we get here: |
253 | */ | 246 | */ |
254 | BUG_ON(error); | 247 | WARN_ON_ONCE(error); |
255 | /* | 248 | /* |
256 | * It shouldn't be a problem to reuse an opaque stateid value. | 249 | * It shouldn't be a problem to reuse an opaque stateid value. |
257 | * I don't think it is for 4.1. But with 4.0 I worry that, for | 250 | * I don't think it is for 4.1. But with 4.0 I worry that, for |
@@ -340,7 +333,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct sv | |||
340 | fh_copy_shallow(&dp->dl_fh, ¤t_fh->fh_handle); | 333 | fh_copy_shallow(&dp->dl_fh, ¤t_fh->fh_handle); |
341 | dp->dl_time = 0; | 334 | dp->dl_time = 0; |
342 | atomic_set(&dp->dl_count, 1); | 335 | atomic_set(&dp->dl_count, 1); |
343 | INIT_WORK(&dp->dl_recall.cb_work, nfsd4_do_callback_rpc); | 336 | nfsd4_init_callback(&dp->dl_recall); |
344 | return dp; | 337 | return dp; |
345 | } | 338 | } |
346 | 339 | ||
@@ -390,14 +383,6 @@ unhash_delegation(struct nfs4_delegation *dp) | |||
390 | * SETCLIENTID state | 383 | * SETCLIENTID state |
391 | */ | 384 | */ |
392 | 385 | ||
393 | /* client_lock protects the client lru list and session hash table */ | ||
394 | static DEFINE_SPINLOCK(client_lock); | ||
395 | |||
396 | /* Hash tables for nfs4_clientid state */ | ||
397 | #define CLIENT_HASH_BITS 4 | ||
398 | #define CLIENT_HASH_SIZE (1 << CLIENT_HASH_BITS) | ||
399 | #define CLIENT_HASH_MASK (CLIENT_HASH_SIZE - 1) | ||
400 | |||
401 | static unsigned int clientid_hashval(u32 id) | 386 | static unsigned int clientid_hashval(u32 id) |
402 | { | 387 | { |
403 | return id & CLIENT_HASH_MASK; | 388 | return id & CLIENT_HASH_MASK; |
@@ -409,31 +394,6 @@ static unsigned int clientstr_hashval(const char *name) | |||
409 | } | 394 | } |
410 | 395 | ||
411 | /* | 396 | /* |
412 | * reclaim_str_hashtbl[] holds known client info from previous reset/reboot | ||
413 | * used in reboot/reset lease grace period processing | ||
414 | * | ||
415 | * conf_id_hashtbl[], and conf_str_hashtbl[] hold confirmed | ||
416 | * setclientid_confirmed info. | ||
417 | * | ||
418 | * unconf_str_hastbl[] and unconf_id_hashtbl[] hold unconfirmed | ||
419 | * setclientid info. | ||
420 | * | ||
421 | * client_lru holds client queue ordered by nfs4_client.cl_time | ||
422 | * for lease renewal. | ||
423 | * | ||
424 | * close_lru holds (open) stateowner queue ordered by nfs4_stateowner.so_time | ||
425 | * for last close replay. | ||
426 | */ | ||
427 | static struct list_head reclaim_str_hashtbl[CLIENT_HASH_SIZE]; | ||
428 | static int reclaim_str_hashtbl_size = 0; | ||
429 | static struct list_head conf_id_hashtbl[CLIENT_HASH_SIZE]; | ||
430 | static struct list_head conf_str_hashtbl[CLIENT_HASH_SIZE]; | ||
431 | static struct list_head unconf_str_hashtbl[CLIENT_HASH_SIZE]; | ||
432 | static struct list_head unconf_id_hashtbl[CLIENT_HASH_SIZE]; | ||
433 | static struct list_head client_lru; | ||
434 | static struct list_head close_lru; | ||
435 | |||
436 | /* | ||
437 | * We store the NONE, READ, WRITE, and BOTH bits separately in the | 397 | * We store the NONE, READ, WRITE, and BOTH bits separately in the |
438 | * st_{access,deny}_bmap field of the stateid, in order to track not | 398 | * st_{access,deny}_bmap field of the stateid, in order to track not |
439 | * only what share bits are currently in force, but also what | 399 | * only what share bits are currently in force, but also what |
@@ -526,7 +486,8 @@ static int nfs4_access_to_omode(u32 access) | |||
526 | case NFS4_SHARE_ACCESS_BOTH: | 486 | case NFS4_SHARE_ACCESS_BOTH: |
527 | return O_RDWR; | 487 | return O_RDWR; |
528 | } | 488 | } |
529 | BUG(); | 489 | WARN_ON_ONCE(1); |
490 | return O_RDONLY; | ||
530 | } | 491 | } |
531 | 492 | ||
532 | /* release all access and file references for a given stateid */ | 493 | /* release all access and file references for a given stateid */ |
@@ -652,9 +613,6 @@ static void release_openowner(struct nfs4_openowner *oo) | |||
652 | nfs4_free_openowner(oo); | 613 | nfs4_free_openowner(oo); |
653 | } | 614 | } |
654 | 615 | ||
655 | #define SESSION_HASH_SIZE 512 | ||
656 | static struct list_head sessionid_hashtbl[SESSION_HASH_SIZE]; | ||
657 | |||
658 | static inline int | 616 | static inline int |
659 | hash_sessionid(struct nfs4_sessionid *sessionid) | 617 | hash_sessionid(struct nfs4_sessionid *sessionid) |
660 | { | 618 | { |
@@ -785,9 +743,12 @@ out_free: | |||
785 | return NULL; | 743 | return NULL; |
786 | } | 744 | } |
787 | 745 | ||
788 | static void init_forechannel_attrs(struct nfsd4_channel_attrs *new, struct nfsd4_channel_attrs *req, int numslots, int slotsize) | 746 | static void init_forechannel_attrs(struct nfsd4_channel_attrs *new, |
747 | struct nfsd4_channel_attrs *req, | ||
748 | int numslots, int slotsize, | ||
749 | struct nfsd_net *nn) | ||
789 | { | 750 | { |
790 | u32 maxrpc = nfsd_serv->sv_max_mesg; | 751 | u32 maxrpc = nn->nfsd_serv->sv_max_mesg; |
791 | 752 | ||
792 | new->maxreqs = numslots; | 753 | new->maxreqs = numslots; |
793 | new->maxresp_cached = min_t(u32, req->maxresp_cached, | 754 | new->maxresp_cached = min_t(u32, req->maxresp_cached, |
@@ -906,21 +867,27 @@ static void __free_session(struct nfsd4_session *ses) | |||
906 | static void free_session(struct kref *kref) | 867 | static void free_session(struct kref *kref) |
907 | { | 868 | { |
908 | struct nfsd4_session *ses; | 869 | struct nfsd4_session *ses; |
870 | struct nfsd_net *nn; | ||
909 | 871 | ||
910 | lockdep_assert_held(&client_lock); | ||
911 | ses = container_of(kref, struct nfsd4_session, se_ref); | 872 | ses = container_of(kref, struct nfsd4_session, se_ref); |
873 | nn = net_generic(ses->se_client->net, nfsd_net_id); | ||
874 | |||
875 | lockdep_assert_held(&nn->client_lock); | ||
912 | nfsd4_del_conns(ses); | 876 | nfsd4_del_conns(ses); |
913 | __free_session(ses); | 877 | __free_session(ses); |
914 | } | 878 | } |
915 | 879 | ||
916 | void nfsd4_put_session(struct nfsd4_session *ses) | 880 | void nfsd4_put_session(struct nfsd4_session *ses) |
917 | { | 881 | { |
918 | spin_lock(&client_lock); | 882 | struct nfsd_net *nn = net_generic(ses->se_client->net, nfsd_net_id); |
883 | |||
884 | spin_lock(&nn->client_lock); | ||
919 | nfsd4_put_session_locked(ses); | 885 | nfsd4_put_session_locked(ses); |
920 | spin_unlock(&client_lock); | 886 | spin_unlock(&nn->client_lock); |
921 | } | 887 | } |
922 | 888 | ||
923 | static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fchan) | 889 | static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fchan, |
890 | struct nfsd_net *nn) | ||
924 | { | 891 | { |
925 | struct nfsd4_session *new; | 892 | struct nfsd4_session *new; |
926 | int numslots, slotsize; | 893 | int numslots, slotsize; |
@@ -941,13 +908,14 @@ static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fchan) | |||
941 | nfsd4_put_drc_mem(slotsize, fchan->maxreqs); | 908 | nfsd4_put_drc_mem(slotsize, fchan->maxreqs); |
942 | return NULL; | 909 | return NULL; |
943 | } | 910 | } |
944 | init_forechannel_attrs(&new->se_fchannel, fchan, numslots, slotsize); | 911 | init_forechannel_attrs(&new->se_fchannel, fchan, numslots, slotsize, nn); |
945 | return new; | 912 | return new; |
946 | } | 913 | } |
947 | 914 | ||
948 | static struct nfsd4_session *init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses) | 915 | static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses) |
949 | { | 916 | { |
950 | int idx; | 917 | int idx; |
918 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
951 | 919 | ||
952 | new->se_client = clp; | 920 | new->se_client = clp; |
953 | gen_sessionid(new); | 921 | gen_sessionid(new); |
@@ -957,14 +925,15 @@ static struct nfsd4_session *init_session(struct svc_rqst *rqstp, struct nfsd4_s | |||
957 | new->se_cb_seq_nr = 1; | 925 | new->se_cb_seq_nr = 1; |
958 | new->se_flags = cses->flags; | 926 | new->se_flags = cses->flags; |
959 | new->se_cb_prog = cses->callback_prog; | 927 | new->se_cb_prog = cses->callback_prog; |
928 | new->se_cb_sec = cses->cb_sec; | ||
960 | kref_init(&new->se_ref); | 929 | kref_init(&new->se_ref); |
961 | idx = hash_sessionid(&new->se_sessionid); | 930 | idx = hash_sessionid(&new->se_sessionid); |
962 | spin_lock(&client_lock); | 931 | spin_lock(&nn->client_lock); |
963 | list_add(&new->se_hash, &sessionid_hashtbl[idx]); | 932 | list_add(&new->se_hash, &nn->sessionid_hashtbl[idx]); |
964 | spin_lock(&clp->cl_lock); | 933 | spin_lock(&clp->cl_lock); |
965 | list_add(&new->se_perclnt, &clp->cl_sessions); | 934 | list_add(&new->se_perclnt, &clp->cl_sessions); |
966 | spin_unlock(&clp->cl_lock); | 935 | spin_unlock(&clp->cl_lock); |
967 | spin_unlock(&client_lock); | 936 | spin_unlock(&nn->client_lock); |
968 | 937 | ||
969 | if (cses->flags & SESSION4_BACK_CHAN) { | 938 | if (cses->flags & SESSION4_BACK_CHAN) { |
970 | struct sockaddr *sa = svc_addr(rqstp); | 939 | struct sockaddr *sa = svc_addr(rqstp); |
@@ -978,20 +947,20 @@ static struct nfsd4_session *init_session(struct svc_rqst *rqstp, struct nfsd4_s | |||
978 | rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa); | 947 | rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa); |
979 | clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa); | 948 | clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa); |
980 | } | 949 | } |
981 | return new; | ||
982 | } | 950 | } |
983 | 951 | ||
984 | /* caller must hold client_lock */ | 952 | /* caller must hold client_lock */ |
985 | static struct nfsd4_session * | 953 | static struct nfsd4_session * |
986 | find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid) | 954 | find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net) |
987 | { | 955 | { |
988 | struct nfsd4_session *elem; | 956 | struct nfsd4_session *elem; |
989 | int idx; | 957 | int idx; |
958 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
990 | 959 | ||
991 | dump_sessionid(__func__, sessionid); | 960 | dump_sessionid(__func__, sessionid); |
992 | idx = hash_sessionid(sessionid); | 961 | idx = hash_sessionid(sessionid); |
993 | /* Search in the appropriate list */ | 962 | /* Search in the appropriate list */ |
994 | list_for_each_entry(elem, &sessionid_hashtbl[idx], se_hash) { | 963 | list_for_each_entry(elem, &nn->sessionid_hashtbl[idx], se_hash) { |
995 | if (!memcmp(elem->se_sessionid.data, sessionid->data, | 964 | if (!memcmp(elem->se_sessionid.data, sessionid->data, |
996 | NFS4_MAX_SESSIONID_LEN)) { | 965 | NFS4_MAX_SESSIONID_LEN)) { |
997 | return elem; | 966 | return elem; |
@@ -1016,6 +985,8 @@ unhash_session(struct nfsd4_session *ses) | |||
1016 | static inline void | 985 | static inline void |
1017 | renew_client_locked(struct nfs4_client *clp) | 986 | renew_client_locked(struct nfs4_client *clp) |
1018 | { | 987 | { |
988 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); | ||
989 | |||
1019 | if (is_client_expired(clp)) { | 990 | if (is_client_expired(clp)) { |
1020 | WARN_ON(1); | 991 | WARN_ON(1); |
1021 | printk("%s: client (clientid %08x/%08x) already expired\n", | 992 | printk("%s: client (clientid %08x/%08x) already expired\n", |
@@ -1028,16 +999,18 @@ renew_client_locked(struct nfs4_client *clp) | |||
1028 | dprintk("renewing client (clientid %08x/%08x)\n", | 999 | dprintk("renewing client (clientid %08x/%08x)\n", |
1029 | clp->cl_clientid.cl_boot, | 1000 | clp->cl_clientid.cl_boot, |
1030 | clp->cl_clientid.cl_id); | 1001 | clp->cl_clientid.cl_id); |
1031 | list_move_tail(&clp->cl_lru, &client_lru); | 1002 | list_move_tail(&clp->cl_lru, &nn->client_lru); |
1032 | clp->cl_time = get_seconds(); | 1003 | clp->cl_time = get_seconds(); |
1033 | } | 1004 | } |
1034 | 1005 | ||
1035 | static inline void | 1006 | static inline void |
1036 | renew_client(struct nfs4_client *clp) | 1007 | renew_client(struct nfs4_client *clp) |
1037 | { | 1008 | { |
1038 | spin_lock(&client_lock); | 1009 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); |
1010 | |||
1011 | spin_lock(&nn->client_lock); | ||
1039 | renew_client_locked(clp); | 1012 | renew_client_locked(clp); |
1040 | spin_unlock(&client_lock); | 1013 | spin_unlock(&nn->client_lock); |
1041 | } | 1014 | } |
1042 | 1015 | ||
1043 | /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */ | 1016 | /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */ |
@@ -1075,7 +1048,9 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name) | |||
1075 | static inline void | 1048 | static inline void |
1076 | free_client(struct nfs4_client *clp) | 1049 | free_client(struct nfs4_client *clp) |
1077 | { | 1050 | { |
1078 | lockdep_assert_held(&client_lock); | 1051 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); |
1052 | |||
1053 | lockdep_assert_held(&nn->client_lock); | ||
1079 | while (!list_empty(&clp->cl_sessions)) { | 1054 | while (!list_empty(&clp->cl_sessions)) { |
1080 | struct nfsd4_session *ses; | 1055 | struct nfsd4_session *ses; |
1081 | ses = list_entry(clp->cl_sessions.next, struct nfsd4_session, | 1056 | ses = list_entry(clp->cl_sessions.next, struct nfsd4_session, |
@@ -1092,15 +1067,16 @@ void | |||
1092 | release_session_client(struct nfsd4_session *session) | 1067 | release_session_client(struct nfsd4_session *session) |
1093 | { | 1068 | { |
1094 | struct nfs4_client *clp = session->se_client; | 1069 | struct nfs4_client *clp = session->se_client; |
1070 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); | ||
1095 | 1071 | ||
1096 | if (!atomic_dec_and_lock(&clp->cl_refcount, &client_lock)) | 1072 | if (!atomic_dec_and_lock(&clp->cl_refcount, &nn->client_lock)) |
1097 | return; | 1073 | return; |
1098 | if (is_client_expired(clp)) { | 1074 | if (is_client_expired(clp)) { |
1099 | free_client(clp); | 1075 | free_client(clp); |
1100 | session->se_client = NULL; | 1076 | session->se_client = NULL; |
1101 | } else | 1077 | } else |
1102 | renew_client_locked(clp); | 1078 | renew_client_locked(clp); |
1103 | spin_unlock(&client_lock); | 1079 | spin_unlock(&nn->client_lock); |
1104 | } | 1080 | } |
1105 | 1081 | ||
1106 | /* must be called under the client_lock */ | 1082 | /* must be called under the client_lock */ |
@@ -1123,6 +1099,7 @@ destroy_client(struct nfs4_client *clp) | |||
1123 | struct nfs4_openowner *oo; | 1099 | struct nfs4_openowner *oo; |
1124 | struct nfs4_delegation *dp; | 1100 | struct nfs4_delegation *dp; |
1125 | struct list_head reaplist; | 1101 | struct list_head reaplist; |
1102 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); | ||
1126 | 1103 | ||
1127 | INIT_LIST_HEAD(&reaplist); | 1104 | INIT_LIST_HEAD(&reaplist); |
1128 | spin_lock(&recall_lock); | 1105 | spin_lock(&recall_lock); |
@@ -1144,12 +1121,15 @@ destroy_client(struct nfs4_client *clp) | |||
1144 | if (clp->cl_cb_conn.cb_xprt) | 1121 | if (clp->cl_cb_conn.cb_xprt) |
1145 | svc_xprt_put(clp->cl_cb_conn.cb_xprt); | 1122 | svc_xprt_put(clp->cl_cb_conn.cb_xprt); |
1146 | list_del(&clp->cl_idhash); | 1123 | list_del(&clp->cl_idhash); |
1147 | list_del(&clp->cl_strhash); | 1124 | if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags)) |
1148 | spin_lock(&client_lock); | 1125 | rb_erase(&clp->cl_namenode, &nn->conf_name_tree); |
1126 | else | ||
1127 | rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); | ||
1128 | spin_lock(&nn->client_lock); | ||
1149 | unhash_client_locked(clp); | 1129 | unhash_client_locked(clp); |
1150 | if (atomic_read(&clp->cl_refcount) == 0) | 1130 | if (atomic_read(&clp->cl_refcount) == 0) |
1151 | free_client(clp); | 1131 | free_client(clp); |
1152 | spin_unlock(&client_lock); | 1132 | spin_unlock(&nn->client_lock); |
1153 | } | 1133 | } |
1154 | 1134 | ||
1155 | static void expire_client(struct nfs4_client *clp) | 1135 | static void expire_client(struct nfs4_client *clp) |
@@ -1187,6 +1167,17 @@ static int copy_cred(struct svc_cred *target, struct svc_cred *source) | |||
1187 | return 0; | 1167 | return 0; |
1188 | } | 1168 | } |
1189 | 1169 | ||
1170 | static long long | ||
1171 | compare_blob(const struct xdr_netobj *o1, const struct xdr_netobj *o2) | ||
1172 | { | ||
1173 | long long res; | ||
1174 | |||
1175 | res = o1->len - o2->len; | ||
1176 | if (res) | ||
1177 | return res; | ||
1178 | return (long long)memcmp(o1->data, o2->data, o1->len); | ||
1179 | } | ||
1180 | |||
1190 | static int same_name(const char *n1, const char *n2) | 1181 | static int same_name(const char *n1, const char *n2) |
1191 | { | 1182 | { |
1192 | return 0 == memcmp(n1, n2, HEXDIR_LEN); | 1183 | return 0 == memcmp(n1, n2, HEXDIR_LEN); |
@@ -1247,10 +1238,9 @@ same_creds(struct svc_cred *cr1, struct svc_cred *cr2) | |||
1247 | return 0 == strcmp(cr1->cr_principal, cr2->cr_principal); | 1238 | return 0 == strcmp(cr1->cr_principal, cr2->cr_principal); |
1248 | } | 1239 | } |
1249 | 1240 | ||
1250 | static void gen_clid(struct nfs4_client *clp) | 1241 | static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn) |
1251 | { | 1242 | { |
1252 | static u32 current_clientid = 1; | 1243 | static u32 current_clientid = 1; |
1253 | struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); | ||
1254 | 1244 | ||
1255 | clp->cl_clientid.cl_boot = nn->boot_time; | 1245 | clp->cl_clientid.cl_boot = nn->boot_time; |
1256 | clp->cl_clientid.cl_id = current_clientid++; | 1246 | clp->cl_clientid.cl_id = current_clientid++; |
@@ -1283,12 +1273,14 @@ static struct nfs4_stid *find_stateid_by_type(struct nfs4_client *cl, stateid_t | |||
1283 | return NULL; | 1273 | return NULL; |
1284 | } | 1274 | } |
1285 | 1275 | ||
1286 | static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, | 1276 | static struct nfs4_client *create_client(struct xdr_netobj name, |
1287 | struct svc_rqst *rqstp, nfs4_verifier *verf) | 1277 | struct svc_rqst *rqstp, nfs4_verifier *verf) |
1288 | { | 1278 | { |
1289 | struct nfs4_client *clp; | 1279 | struct nfs4_client *clp; |
1290 | struct sockaddr *sa = svc_addr(rqstp); | 1280 | struct sockaddr *sa = svc_addr(rqstp); |
1291 | int ret; | 1281 | int ret; |
1282 | struct net *net = SVC_NET(rqstp); | ||
1283 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
1292 | 1284 | ||
1293 | clp = alloc_client(name); | 1285 | clp = alloc_client(name); |
1294 | if (clp == NULL) | 1286 | if (clp == NULL) |
@@ -1297,23 +1289,21 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, | |||
1297 | INIT_LIST_HEAD(&clp->cl_sessions); | 1289 | INIT_LIST_HEAD(&clp->cl_sessions); |
1298 | ret = copy_cred(&clp->cl_cred, &rqstp->rq_cred); | 1290 | ret = copy_cred(&clp->cl_cred, &rqstp->rq_cred); |
1299 | if (ret) { | 1291 | if (ret) { |
1300 | spin_lock(&client_lock); | 1292 | spin_lock(&nn->client_lock); |
1301 | free_client(clp); | 1293 | free_client(clp); |
1302 | spin_unlock(&client_lock); | 1294 | spin_unlock(&nn->client_lock); |
1303 | return NULL; | 1295 | return NULL; |
1304 | } | 1296 | } |
1305 | idr_init(&clp->cl_stateids); | 1297 | idr_init(&clp->cl_stateids); |
1306 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); | ||
1307 | atomic_set(&clp->cl_refcount, 0); | 1298 | atomic_set(&clp->cl_refcount, 0); |
1308 | clp->cl_cb_state = NFSD4_CB_UNKNOWN; | 1299 | clp->cl_cb_state = NFSD4_CB_UNKNOWN; |
1309 | INIT_LIST_HEAD(&clp->cl_idhash); | 1300 | INIT_LIST_HEAD(&clp->cl_idhash); |
1310 | INIT_LIST_HEAD(&clp->cl_strhash); | ||
1311 | INIT_LIST_HEAD(&clp->cl_openowners); | 1301 | INIT_LIST_HEAD(&clp->cl_openowners); |
1312 | INIT_LIST_HEAD(&clp->cl_delegations); | 1302 | INIT_LIST_HEAD(&clp->cl_delegations); |
1313 | INIT_LIST_HEAD(&clp->cl_lru); | 1303 | INIT_LIST_HEAD(&clp->cl_lru); |
1314 | INIT_LIST_HEAD(&clp->cl_callbacks); | 1304 | INIT_LIST_HEAD(&clp->cl_callbacks); |
1315 | spin_lock_init(&clp->cl_lock); | 1305 | spin_lock_init(&clp->cl_lock); |
1316 | INIT_WORK(&clp->cl_cb_null.cb_work, nfsd4_do_callback_rpc); | 1306 | nfsd4_init_callback(&clp->cl_cb_null); |
1317 | clp->cl_time = get_seconds(); | 1307 | clp->cl_time = get_seconds(); |
1318 | clear_bit(0, &clp->cl_cb_slot_busy); | 1308 | clear_bit(0, &clp->cl_cb_slot_busy); |
1319 | rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); | 1309 | rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); |
@@ -1321,17 +1311,60 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, | |||
1321 | rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa); | 1311 | rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa); |
1322 | gen_confirm(clp); | 1312 | gen_confirm(clp); |
1323 | clp->cl_cb_session = NULL; | 1313 | clp->cl_cb_session = NULL; |
1314 | clp->net = net; | ||
1324 | return clp; | 1315 | return clp; |
1325 | } | 1316 | } |
1326 | 1317 | ||
1327 | static void | 1318 | static void |
1328 | add_to_unconfirmed(struct nfs4_client *clp, unsigned int strhashval) | 1319 | add_clp_to_name_tree(struct nfs4_client *new_clp, struct rb_root *root) |
1320 | { | ||
1321 | struct rb_node **new = &(root->rb_node), *parent = NULL; | ||
1322 | struct nfs4_client *clp; | ||
1323 | |||
1324 | while (*new) { | ||
1325 | clp = rb_entry(*new, struct nfs4_client, cl_namenode); | ||
1326 | parent = *new; | ||
1327 | |||
1328 | if (compare_blob(&clp->cl_name, &new_clp->cl_name) > 0) | ||
1329 | new = &((*new)->rb_left); | ||
1330 | else | ||
1331 | new = &((*new)->rb_right); | ||
1332 | } | ||
1333 | |||
1334 | rb_link_node(&new_clp->cl_namenode, parent, new); | ||
1335 | rb_insert_color(&new_clp->cl_namenode, root); | ||
1336 | } | ||
1337 | |||
1338 | static struct nfs4_client * | ||
1339 | find_clp_in_name_tree(struct xdr_netobj *name, struct rb_root *root) | ||
1340 | { | ||
1341 | long long cmp; | ||
1342 | struct rb_node *node = root->rb_node; | ||
1343 | struct nfs4_client *clp; | ||
1344 | |||
1345 | while (node) { | ||
1346 | clp = rb_entry(node, struct nfs4_client, cl_namenode); | ||
1347 | cmp = compare_blob(&clp->cl_name, name); | ||
1348 | if (cmp > 0) | ||
1349 | node = node->rb_left; | ||
1350 | else if (cmp < 0) | ||
1351 | node = node->rb_right; | ||
1352 | else | ||
1353 | return clp; | ||
1354 | } | ||
1355 | return NULL; | ||
1356 | } | ||
1357 | |||
1358 | static void | ||
1359 | add_to_unconfirmed(struct nfs4_client *clp) | ||
1329 | { | 1360 | { |
1330 | unsigned int idhashval; | 1361 | unsigned int idhashval; |
1362 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); | ||
1331 | 1363 | ||
1332 | list_add(&clp->cl_strhash, &unconf_str_hashtbl[strhashval]); | 1364 | clear_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); |
1365 | add_clp_to_name_tree(clp, &nn->unconf_name_tree); | ||
1333 | idhashval = clientid_hashval(clp->cl_clientid.cl_id); | 1366 | idhashval = clientid_hashval(clp->cl_clientid.cl_id); |
1334 | list_add(&clp->cl_idhash, &unconf_id_hashtbl[idhashval]); | 1367 | list_add(&clp->cl_idhash, &nn->unconf_id_hashtbl[idhashval]); |
1335 | renew_client(clp); | 1368 | renew_client(clp); |
1336 | } | 1369 | } |
1337 | 1370 | ||
@@ -1339,22 +1372,23 @@ static void | |||
1339 | move_to_confirmed(struct nfs4_client *clp) | 1372 | move_to_confirmed(struct nfs4_client *clp) |
1340 | { | 1373 | { |
1341 | unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id); | 1374 | unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id); |
1342 | unsigned int strhashval; | 1375 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); |
1343 | 1376 | ||
1344 | dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp); | 1377 | dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp); |
1345 | list_move(&clp->cl_idhash, &conf_id_hashtbl[idhashval]); | 1378 | list_move(&clp->cl_idhash, &nn->conf_id_hashtbl[idhashval]); |
1346 | strhashval = clientstr_hashval(clp->cl_recdir); | 1379 | rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); |
1347 | list_move(&clp->cl_strhash, &conf_str_hashtbl[strhashval]); | 1380 | add_clp_to_name_tree(clp, &nn->conf_name_tree); |
1381 | set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); | ||
1348 | renew_client(clp); | 1382 | renew_client(clp); |
1349 | } | 1383 | } |
1350 | 1384 | ||
1351 | static struct nfs4_client * | 1385 | static struct nfs4_client * |
1352 | find_confirmed_client(clientid_t *clid, bool sessions) | 1386 | find_confirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn) |
1353 | { | 1387 | { |
1354 | struct nfs4_client *clp; | 1388 | struct nfs4_client *clp; |
1355 | unsigned int idhashval = clientid_hashval(clid->cl_id); | 1389 | unsigned int idhashval = clientid_hashval(clid->cl_id); |
1356 | 1390 | ||
1357 | list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) { | 1391 | list_for_each_entry(clp, &nn->conf_id_hashtbl[idhashval], cl_idhash) { |
1358 | if (same_clid(&clp->cl_clientid, clid)) { | 1392 | if (same_clid(&clp->cl_clientid, clid)) { |
1359 | if ((bool)clp->cl_minorversion != sessions) | 1393 | if ((bool)clp->cl_minorversion != sessions) |
1360 | return NULL; | 1394 | return NULL; |
@@ -1366,12 +1400,12 @@ find_confirmed_client(clientid_t *clid, bool sessions) | |||
1366 | } | 1400 | } |
1367 | 1401 | ||
1368 | static struct nfs4_client * | 1402 | static struct nfs4_client * |
1369 | find_unconfirmed_client(clientid_t *clid, bool sessions) | 1403 | find_unconfirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn) |
1370 | { | 1404 | { |
1371 | struct nfs4_client *clp; | 1405 | struct nfs4_client *clp; |
1372 | unsigned int idhashval = clientid_hashval(clid->cl_id); | 1406 | unsigned int idhashval = clientid_hashval(clid->cl_id); |
1373 | 1407 | ||
1374 | list_for_each_entry(clp, &unconf_id_hashtbl[idhashval], cl_idhash) { | 1408 | list_for_each_entry(clp, &nn->unconf_id_hashtbl[idhashval], cl_idhash) { |
1375 | if (same_clid(&clp->cl_clientid, clid)) { | 1409 | if (same_clid(&clp->cl_clientid, clid)) { |
1376 | if ((bool)clp->cl_minorversion != sessions) | 1410 | if ((bool)clp->cl_minorversion != sessions) |
1377 | return NULL; | 1411 | return NULL; |
@@ -1387,27 +1421,15 @@ static bool clp_used_exchangeid(struct nfs4_client *clp) | |||
1387 | } | 1421 | } |
1388 | 1422 | ||
1389 | static struct nfs4_client * | 1423 | static struct nfs4_client * |
1390 | find_confirmed_client_by_str(const char *dname, unsigned int hashval) | 1424 | find_confirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn) |
1391 | { | 1425 | { |
1392 | struct nfs4_client *clp; | 1426 | return find_clp_in_name_tree(name, &nn->conf_name_tree); |
1393 | |||
1394 | list_for_each_entry(clp, &conf_str_hashtbl[hashval], cl_strhash) { | ||
1395 | if (same_name(clp->cl_recdir, dname)) | ||
1396 | return clp; | ||
1397 | } | ||
1398 | return NULL; | ||
1399 | } | 1427 | } |
1400 | 1428 | ||
1401 | static struct nfs4_client * | 1429 | static struct nfs4_client * |
1402 | find_unconfirmed_client_by_str(const char *dname, unsigned int hashval) | 1430 | find_unconfirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn) |
1403 | { | 1431 | { |
1404 | struct nfs4_client *clp; | 1432 | return find_clp_in_name_tree(name, &nn->unconf_name_tree); |
1405 | |||
1406 | list_for_each_entry(clp, &unconf_str_hashtbl[hashval], cl_strhash) { | ||
1407 | if (same_name(clp->cl_recdir, dname)) | ||
1408 | return clp; | ||
1409 | } | ||
1410 | return NULL; | ||
1411 | } | 1433 | } |
1412 | 1434 | ||
1413 | static void | 1435 | static void |
@@ -1428,7 +1450,7 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_r | |||
1428 | else | 1450 | else |
1429 | goto out_err; | 1451 | goto out_err; |
1430 | 1452 | ||
1431 | conn->cb_addrlen = rpc_uaddr2sockaddr(&init_net, se->se_callback_addr_val, | 1453 | conn->cb_addrlen = rpc_uaddr2sockaddr(clp->net, se->se_callback_addr_val, |
1432 | se->se_callback_addr_len, | 1454 | se->se_callback_addr_len, |
1433 | (struct sockaddr *)&conn->cb_addr, | 1455 | (struct sockaddr *)&conn->cb_addr, |
1434 | sizeof(conn->cb_addr)); | 1456 | sizeof(conn->cb_addr)); |
@@ -1572,12 +1594,11 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
1572 | { | 1594 | { |
1573 | struct nfs4_client *unconf, *conf, *new; | 1595 | struct nfs4_client *unconf, *conf, *new; |
1574 | __be32 status; | 1596 | __be32 status; |
1575 | unsigned int strhashval; | ||
1576 | char dname[HEXDIR_LEN]; | ||
1577 | char addr_str[INET6_ADDRSTRLEN]; | 1597 | char addr_str[INET6_ADDRSTRLEN]; |
1578 | nfs4_verifier verf = exid->verifier; | 1598 | nfs4_verifier verf = exid->verifier; |
1579 | struct sockaddr *sa = svc_addr(rqstp); | 1599 | struct sockaddr *sa = svc_addr(rqstp); |
1580 | bool update = exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A; | 1600 | bool update = exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A; |
1601 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
1581 | 1602 | ||
1582 | rpc_ntop(sa, addr_str, sizeof(addr_str)); | 1603 | rpc_ntop(sa, addr_str, sizeof(addr_str)); |
1583 | dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " | 1604 | dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " |
@@ -1592,24 +1613,16 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
1592 | switch (exid->spa_how) { | 1613 | switch (exid->spa_how) { |
1593 | case SP4_NONE: | 1614 | case SP4_NONE: |
1594 | break; | 1615 | break; |
1616 | default: /* checked by xdr code */ | ||
1617 | WARN_ON_ONCE(1); | ||
1595 | case SP4_SSV: | 1618 | case SP4_SSV: |
1596 | return nfserr_serverfault; | ||
1597 | default: | ||
1598 | BUG(); /* checked by xdr code */ | ||
1599 | case SP4_MACH_CRED: | 1619 | case SP4_MACH_CRED: |
1600 | return nfserr_serverfault; /* no excuse :-/ */ | 1620 | return nfserr_serverfault; /* no excuse :-/ */ |
1601 | } | 1621 | } |
1602 | 1622 | ||
1603 | status = nfs4_make_rec_clidname(dname, &exid->clname); | ||
1604 | |||
1605 | if (status) | ||
1606 | return status; | ||
1607 | |||
1608 | strhashval = clientstr_hashval(dname); | ||
1609 | |||
1610 | /* Cases below refer to rfc 5661 section 18.35.4: */ | 1623 | /* Cases below refer to rfc 5661 section 18.35.4: */ |
1611 | nfs4_lock_state(); | 1624 | nfs4_lock_state(); |
1612 | conf = find_confirmed_client_by_str(dname, strhashval); | 1625 | conf = find_confirmed_client_by_name(&exid->clname, nn); |
1613 | if (conf) { | 1626 | if (conf) { |
1614 | bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred); | 1627 | bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred); |
1615 | bool verfs_match = same_verf(&verf, &conf->cl_verifier); | 1628 | bool verfs_match = same_verf(&verf, &conf->cl_verifier); |
@@ -1654,21 +1667,21 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
1654 | goto out; | 1667 | goto out; |
1655 | } | 1668 | } |
1656 | 1669 | ||
1657 | unconf = find_unconfirmed_client_by_str(dname, strhashval); | 1670 | unconf = find_unconfirmed_client_by_name(&exid->clname, nn); |
1658 | if (unconf) /* case 4, possible retry or client restart */ | 1671 | if (unconf) /* case 4, possible retry or client restart */ |
1659 | expire_client(unconf); | 1672 | expire_client(unconf); |
1660 | 1673 | ||
1661 | /* case 1 (normal case) */ | 1674 | /* case 1 (normal case) */ |
1662 | out_new: | 1675 | out_new: |
1663 | new = create_client(exid->clname, dname, rqstp, &verf); | 1676 | new = create_client(exid->clname, rqstp, &verf); |
1664 | if (new == NULL) { | 1677 | if (new == NULL) { |
1665 | status = nfserr_jukebox; | 1678 | status = nfserr_jukebox; |
1666 | goto out; | 1679 | goto out; |
1667 | } | 1680 | } |
1668 | new->cl_minorversion = 1; | 1681 | new->cl_minorversion = 1; |
1669 | 1682 | ||
1670 | gen_clid(new); | 1683 | gen_clid(new, nn); |
1671 | add_to_unconfirmed(new, strhashval); | 1684 | add_to_unconfirmed(new); |
1672 | out_copy: | 1685 | out_copy: |
1673 | exid->clientid.cl_boot = new->cl_clientid.cl_boot; | 1686 | exid->clientid.cl_boot = new->cl_clientid.cl_boot; |
1674 | exid->clientid.cl_id = new->cl_clientid.cl_id; | 1687 | exid->clientid.cl_id = new->cl_clientid.cl_id; |
@@ -1761,12 +1774,13 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1761 | struct nfsd4_conn *conn; | 1774 | struct nfsd4_conn *conn; |
1762 | struct nfsd4_clid_slot *cs_slot = NULL; | 1775 | struct nfsd4_clid_slot *cs_slot = NULL; |
1763 | __be32 status = 0; | 1776 | __be32 status = 0; |
1777 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
1764 | 1778 | ||
1765 | if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) | 1779 | if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) |
1766 | return nfserr_inval; | 1780 | return nfserr_inval; |
1767 | if (check_forechannel_attrs(cr_ses->fore_channel)) | 1781 | if (check_forechannel_attrs(cr_ses->fore_channel)) |
1768 | return nfserr_toosmall; | 1782 | return nfserr_toosmall; |
1769 | new = alloc_session(&cr_ses->fore_channel); | 1783 | new = alloc_session(&cr_ses->fore_channel, nn); |
1770 | if (!new) | 1784 | if (!new) |
1771 | return nfserr_jukebox; | 1785 | return nfserr_jukebox; |
1772 | status = nfserr_jukebox; | 1786 | status = nfserr_jukebox; |
@@ -1775,8 +1789,8 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1775 | goto out_free_session; | 1789 | goto out_free_session; |
1776 | 1790 | ||
1777 | nfs4_lock_state(); | 1791 | nfs4_lock_state(); |
1778 | unconf = find_unconfirmed_client(&cr_ses->clientid, true); | 1792 | unconf = find_unconfirmed_client(&cr_ses->clientid, true, nn); |
1779 | conf = find_confirmed_client(&cr_ses->clientid, true); | 1793 | conf = find_confirmed_client(&cr_ses->clientid, true, nn); |
1780 | 1794 | ||
1781 | if (conf) { | 1795 | if (conf) { |
1782 | cs_slot = &conf->cl_cs_slot; | 1796 | cs_slot = &conf->cl_cs_slot; |
@@ -1789,7 +1803,6 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1789 | goto out_free_conn; | 1803 | goto out_free_conn; |
1790 | } | 1804 | } |
1791 | } else if (unconf) { | 1805 | } else if (unconf) { |
1792 | unsigned int hash; | ||
1793 | struct nfs4_client *old; | 1806 | struct nfs4_client *old; |
1794 | if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || | 1807 | if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || |
1795 | !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) { | 1808 | !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) { |
@@ -1803,8 +1816,7 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1803 | status = nfserr_seq_misordered; | 1816 | status = nfserr_seq_misordered; |
1804 | goto out_free_conn; | 1817 | goto out_free_conn; |
1805 | } | 1818 | } |
1806 | hash = clientstr_hashval(unconf->cl_recdir); | 1819 | old = find_confirmed_client_by_name(&unconf->cl_name, nn); |
1807 | old = find_confirmed_client_by_str(unconf->cl_recdir, hash); | ||
1808 | if (old) | 1820 | if (old) |
1809 | expire_client(old); | 1821 | expire_client(old); |
1810 | move_to_confirmed(unconf); | 1822 | move_to_confirmed(unconf); |
@@ -1843,14 +1855,6 @@ out_free_session: | |||
1843 | goto out; | 1855 | goto out; |
1844 | } | 1856 | } |
1845 | 1857 | ||
1846 | static bool nfsd4_last_compound_op(struct svc_rqst *rqstp) | ||
1847 | { | ||
1848 | struct nfsd4_compoundres *resp = rqstp->rq_resp; | ||
1849 | struct nfsd4_compoundargs *argp = rqstp->rq_argp; | ||
1850 | |||
1851 | return argp->opcnt == resp->opcnt; | ||
1852 | } | ||
1853 | |||
1854 | static __be32 nfsd4_map_bcts_dir(u32 *dir) | 1858 | static __be32 nfsd4_map_bcts_dir(u32 *dir) |
1855 | { | 1859 | { |
1856 | switch (*dir) { | 1860 | switch (*dir) { |
@@ -1865,24 +1869,40 @@ static __be32 nfsd4_map_bcts_dir(u32 *dir) | |||
1865 | return nfserr_inval; | 1869 | return nfserr_inval; |
1866 | } | 1870 | } |
1867 | 1871 | ||
1872 | __be32 nfsd4_backchannel_ctl(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_backchannel_ctl *bc) | ||
1873 | { | ||
1874 | struct nfsd4_session *session = cstate->session; | ||
1875 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
1876 | |||
1877 | spin_lock(&nn->client_lock); | ||
1878 | session->se_cb_prog = bc->bc_cb_program; | ||
1879 | session->se_cb_sec = bc->bc_cb_sec; | ||
1880 | spin_unlock(&nn->client_lock); | ||
1881 | |||
1882 | nfsd4_probe_callback(session->se_client); | ||
1883 | |||
1884 | return nfs_ok; | ||
1885 | } | ||
1886 | |||
1868 | __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, | 1887 | __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, |
1869 | struct nfsd4_compound_state *cstate, | 1888 | struct nfsd4_compound_state *cstate, |
1870 | struct nfsd4_bind_conn_to_session *bcts) | 1889 | struct nfsd4_bind_conn_to_session *bcts) |
1871 | { | 1890 | { |
1872 | __be32 status; | 1891 | __be32 status; |
1873 | struct nfsd4_conn *conn; | 1892 | struct nfsd4_conn *conn; |
1893 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
1874 | 1894 | ||
1875 | if (!nfsd4_last_compound_op(rqstp)) | 1895 | if (!nfsd4_last_compound_op(rqstp)) |
1876 | return nfserr_not_only_op; | 1896 | return nfserr_not_only_op; |
1877 | spin_lock(&client_lock); | 1897 | spin_lock(&nn->client_lock); |
1878 | cstate->session = find_in_sessionid_hashtbl(&bcts->sessionid); | 1898 | cstate->session = find_in_sessionid_hashtbl(&bcts->sessionid, SVC_NET(rqstp)); |
1879 | /* Sorta weird: we only need the refcnt'ing because new_conn acquires | 1899 | /* Sorta weird: we only need the refcnt'ing because new_conn acquires |
1880 | * client_lock iself: */ | 1900 | * client_lock iself: */ |
1881 | if (cstate->session) { | 1901 | if (cstate->session) { |
1882 | nfsd4_get_session(cstate->session); | 1902 | nfsd4_get_session(cstate->session); |
1883 | atomic_inc(&cstate->session->se_client->cl_refcount); | 1903 | atomic_inc(&cstate->session->se_client->cl_refcount); |
1884 | } | 1904 | } |
1885 | spin_unlock(&client_lock); | 1905 | spin_unlock(&nn->client_lock); |
1886 | if (!cstate->session) | 1906 | if (!cstate->session) |
1887 | return nfserr_badsession; | 1907 | return nfserr_badsession; |
1888 | 1908 | ||
@@ -1910,6 +1930,7 @@ nfsd4_destroy_session(struct svc_rqst *r, | |||
1910 | { | 1930 | { |
1911 | struct nfsd4_session *ses; | 1931 | struct nfsd4_session *ses; |
1912 | __be32 status = nfserr_badsession; | 1932 | __be32 status = nfserr_badsession; |
1933 | struct nfsd_net *nn = net_generic(SVC_NET(r), nfsd_net_id); | ||
1913 | 1934 | ||
1914 | /* Notes: | 1935 | /* Notes: |
1915 | * - The confirmed nfs4_client->cl_sessionid holds destroyed sessinid | 1936 | * - The confirmed nfs4_client->cl_sessionid holds destroyed sessinid |
@@ -1923,24 +1944,24 @@ nfsd4_destroy_session(struct svc_rqst *r, | |||
1923 | return nfserr_not_only_op; | 1944 | return nfserr_not_only_op; |
1924 | } | 1945 | } |
1925 | dump_sessionid(__func__, &sessionid->sessionid); | 1946 | dump_sessionid(__func__, &sessionid->sessionid); |
1926 | spin_lock(&client_lock); | 1947 | spin_lock(&nn->client_lock); |
1927 | ses = find_in_sessionid_hashtbl(&sessionid->sessionid); | 1948 | ses = find_in_sessionid_hashtbl(&sessionid->sessionid, SVC_NET(r)); |
1928 | if (!ses) { | 1949 | if (!ses) { |
1929 | spin_unlock(&client_lock); | 1950 | spin_unlock(&nn->client_lock); |
1930 | goto out; | 1951 | goto out; |
1931 | } | 1952 | } |
1932 | 1953 | ||
1933 | unhash_session(ses); | 1954 | unhash_session(ses); |
1934 | spin_unlock(&client_lock); | 1955 | spin_unlock(&nn->client_lock); |
1935 | 1956 | ||
1936 | nfs4_lock_state(); | 1957 | nfs4_lock_state(); |
1937 | nfsd4_probe_callback_sync(ses->se_client); | 1958 | nfsd4_probe_callback_sync(ses->se_client); |
1938 | nfs4_unlock_state(); | 1959 | nfs4_unlock_state(); |
1939 | 1960 | ||
1940 | spin_lock(&client_lock); | 1961 | spin_lock(&nn->client_lock); |
1941 | nfsd4_del_conns(ses); | 1962 | nfsd4_del_conns(ses); |
1942 | nfsd4_put_session_locked(ses); | 1963 | nfsd4_put_session_locked(ses); |
1943 | spin_unlock(&client_lock); | 1964 | spin_unlock(&nn->client_lock); |
1944 | status = nfs_ok; | 1965 | status = nfs_ok; |
1945 | out: | 1966 | out: |
1946 | dprintk("%s returns %d\n", __func__, ntohl(status)); | 1967 | dprintk("%s returns %d\n", __func__, ntohl(status)); |
@@ -2006,6 +2027,7 @@ nfsd4_sequence(struct svc_rqst *rqstp, | |||
2006 | struct nfsd4_slot *slot; | 2027 | struct nfsd4_slot *slot; |
2007 | struct nfsd4_conn *conn; | 2028 | struct nfsd4_conn *conn; |
2008 | __be32 status; | 2029 | __be32 status; |
2030 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
2009 | 2031 | ||
2010 | if (resp->opcnt != 1) | 2032 | if (resp->opcnt != 1) |
2011 | return nfserr_sequence_pos; | 2033 | return nfserr_sequence_pos; |
@@ -2018,9 +2040,9 @@ nfsd4_sequence(struct svc_rqst *rqstp, | |||
2018 | if (!conn) | 2040 | if (!conn) |
2019 | return nfserr_jukebox; | 2041 | return nfserr_jukebox; |
2020 | 2042 | ||
2021 | spin_lock(&client_lock); | 2043 | spin_lock(&nn->client_lock); |
2022 | status = nfserr_badsession; | 2044 | status = nfserr_badsession; |
2023 | session = find_in_sessionid_hashtbl(&seq->sessionid); | 2045 | session = find_in_sessionid_hashtbl(&seq->sessionid, SVC_NET(rqstp)); |
2024 | if (!session) | 2046 | if (!session) |
2025 | goto out; | 2047 | goto out; |
2026 | 2048 | ||
@@ -2094,7 +2116,7 @@ out: | |||
2094 | } | 2116 | } |
2095 | } | 2117 | } |
2096 | kfree(conn); | 2118 | kfree(conn); |
2097 | spin_unlock(&client_lock); | 2119 | spin_unlock(&nn->client_lock); |
2098 | dprintk("%s: return %d\n", __func__, ntohl(status)); | 2120 | dprintk("%s: return %d\n", __func__, ntohl(status)); |
2099 | return status; | 2121 | return status; |
2100 | } | 2122 | } |
@@ -2104,10 +2126,11 @@ nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta | |||
2104 | { | 2126 | { |
2105 | struct nfs4_client *conf, *unconf, *clp; | 2127 | struct nfs4_client *conf, *unconf, *clp; |
2106 | __be32 status = 0; | 2128 | __be32 status = 0; |
2129 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
2107 | 2130 | ||
2108 | nfs4_lock_state(); | 2131 | nfs4_lock_state(); |
2109 | unconf = find_unconfirmed_client(&dc->clientid, true); | 2132 | unconf = find_unconfirmed_client(&dc->clientid, true, nn); |
2110 | conf = find_confirmed_client(&dc->clientid, true); | 2133 | conf = find_confirmed_client(&dc->clientid, true, nn); |
2111 | 2134 | ||
2112 | if (conf) { | 2135 | if (conf) { |
2113 | clp = conf; | 2136 | clp = conf; |
@@ -2181,20 +2204,13 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2181 | { | 2204 | { |
2182 | struct xdr_netobj clname = setclid->se_name; | 2205 | struct xdr_netobj clname = setclid->se_name; |
2183 | nfs4_verifier clverifier = setclid->se_verf; | 2206 | nfs4_verifier clverifier = setclid->se_verf; |
2184 | unsigned int strhashval; | ||
2185 | struct nfs4_client *conf, *unconf, *new; | 2207 | struct nfs4_client *conf, *unconf, *new; |
2186 | __be32 status; | 2208 | __be32 status; |
2187 | char dname[HEXDIR_LEN]; | 2209 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); |
2188 | |||
2189 | status = nfs4_make_rec_clidname(dname, &clname); | ||
2190 | if (status) | ||
2191 | return status; | ||
2192 | |||
2193 | strhashval = clientstr_hashval(dname); | ||
2194 | 2210 | ||
2195 | /* Cases below refer to rfc 3530 section 14.2.33: */ | 2211 | /* Cases below refer to rfc 3530 section 14.2.33: */ |
2196 | nfs4_lock_state(); | 2212 | nfs4_lock_state(); |
2197 | conf = find_confirmed_client_by_str(dname, strhashval); | 2213 | conf = find_confirmed_client_by_name(&clname, nn); |
2198 | if (conf) { | 2214 | if (conf) { |
2199 | /* case 0: */ | 2215 | /* case 0: */ |
2200 | status = nfserr_clid_inuse; | 2216 | status = nfserr_clid_inuse; |
@@ -2209,21 +2225,21 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2209 | goto out; | 2225 | goto out; |
2210 | } | 2226 | } |
2211 | } | 2227 | } |
2212 | unconf = find_unconfirmed_client_by_str(dname, strhashval); | 2228 | unconf = find_unconfirmed_client_by_name(&clname, nn); |
2213 | if (unconf) | 2229 | if (unconf) |
2214 | expire_client(unconf); | 2230 | expire_client(unconf); |
2215 | status = nfserr_jukebox; | 2231 | status = nfserr_jukebox; |
2216 | new = create_client(clname, dname, rqstp, &clverifier); | 2232 | new = create_client(clname, rqstp, &clverifier); |
2217 | if (new == NULL) | 2233 | if (new == NULL) |
2218 | goto out; | 2234 | goto out; |
2219 | if (conf && same_verf(&conf->cl_verifier, &clverifier)) | 2235 | if (conf && same_verf(&conf->cl_verifier, &clverifier)) |
2220 | /* case 1: probable callback update */ | 2236 | /* case 1: probable callback update */ |
2221 | copy_clid(new, conf); | 2237 | copy_clid(new, conf); |
2222 | else /* case 4 (new client) or cases 2, 3 (client reboot): */ | 2238 | else /* case 4 (new client) or cases 2, 3 (client reboot): */ |
2223 | gen_clid(new); | 2239 | gen_clid(new, nn); |
2224 | new->cl_minorversion = 0; | 2240 | new->cl_minorversion = 0; |
2225 | gen_callback(new, setclid, rqstp); | 2241 | gen_callback(new, setclid, rqstp); |
2226 | add_to_unconfirmed(new, strhashval); | 2242 | add_to_unconfirmed(new); |
2227 | setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot; | 2243 | setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot; |
2228 | setclid->se_clientid.cl_id = new->cl_clientid.cl_id; | 2244 | setclid->se_clientid.cl_id = new->cl_clientid.cl_id; |
2229 | memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data)); | 2245 | memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data)); |
@@ -2243,14 +2259,14 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | |||
2243 | nfs4_verifier confirm = setclientid_confirm->sc_confirm; | 2259 | nfs4_verifier confirm = setclientid_confirm->sc_confirm; |
2244 | clientid_t * clid = &setclientid_confirm->sc_clientid; | 2260 | clientid_t * clid = &setclientid_confirm->sc_clientid; |
2245 | __be32 status; | 2261 | __be32 status; |
2246 | struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); | 2262 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); |
2247 | 2263 | ||
2248 | if (STALE_CLIENTID(clid, nn)) | 2264 | if (STALE_CLIENTID(clid, nn)) |
2249 | return nfserr_stale_clientid; | 2265 | return nfserr_stale_clientid; |
2250 | nfs4_lock_state(); | 2266 | nfs4_lock_state(); |
2251 | 2267 | ||
2252 | conf = find_confirmed_client(clid, false); | 2268 | conf = find_confirmed_client(clid, false, nn); |
2253 | unconf = find_unconfirmed_client(clid, false); | 2269 | unconf = find_unconfirmed_client(clid, false, nn); |
2254 | /* | 2270 | /* |
2255 | * We try hard to give out unique clientid's, so if we get an | 2271 | * We try hard to give out unique clientid's, so if we get an |
2256 | * attempt to confirm the same clientid with a different cred, | 2272 | * attempt to confirm the same clientid with a different cred, |
@@ -2276,9 +2292,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | |||
2276 | nfsd4_probe_callback(conf); | 2292 | nfsd4_probe_callback(conf); |
2277 | expire_client(unconf); | 2293 | expire_client(unconf); |
2278 | } else { /* case 3: normal case; new or rebooted client */ | 2294 | } else { /* case 3: normal case; new or rebooted client */ |
2279 | unsigned int hash = clientstr_hashval(unconf->cl_recdir); | 2295 | conf = find_confirmed_client_by_name(&unconf->cl_name, nn); |
2280 | |||
2281 | conf = find_confirmed_client_by_str(unconf->cl_recdir, hash); | ||
2282 | if (conf) | 2296 | if (conf) |
2283 | expire_client(conf); | 2297 | expire_client(conf); |
2284 | move_to_confirmed(unconf); | 2298 | move_to_confirmed(unconf); |
@@ -2340,7 +2354,7 @@ nfsd4_init_slabs(void) | |||
2340 | if (openowner_slab == NULL) | 2354 | if (openowner_slab == NULL) |
2341 | goto out_nomem; | 2355 | goto out_nomem; |
2342 | lockowner_slab = kmem_cache_create("nfsd4_lockowners", | 2356 | lockowner_slab = kmem_cache_create("nfsd4_lockowners", |
2343 | sizeof(struct nfs4_openowner), 0, 0, NULL); | 2357 | sizeof(struct nfs4_lockowner), 0, 0, NULL); |
2344 | if (lockowner_slab == NULL) | 2358 | if (lockowner_slab == NULL) |
2345 | goto out_nomem; | 2359 | goto out_nomem; |
2346 | file_slab = kmem_cache_create("nfsd4_files", | 2360 | file_slab = kmem_cache_create("nfsd4_files", |
@@ -2404,7 +2418,9 @@ static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj | |||
2404 | 2418 | ||
2405 | static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval) | 2419 | static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval) |
2406 | { | 2420 | { |
2407 | list_add(&oo->oo_owner.so_strhash, &ownerstr_hashtbl[strhashval]); | 2421 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); |
2422 | |||
2423 | list_add(&oo->oo_owner.so_strhash, &nn->ownerstr_hashtbl[strhashval]); | ||
2408 | list_add(&oo->oo_perclient, &clp->cl_openowners); | 2424 | list_add(&oo->oo_perclient, &clp->cl_openowners); |
2409 | } | 2425 | } |
2410 | 2426 | ||
@@ -2444,11 +2460,13 @@ static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, | |||
2444 | } | 2460 | } |
2445 | 2461 | ||
2446 | static void | 2462 | static void |
2447 | move_to_close_lru(struct nfs4_openowner *oo) | 2463 | move_to_close_lru(struct nfs4_openowner *oo, struct net *net) |
2448 | { | 2464 | { |
2465 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
2466 | |||
2449 | dprintk("NFSD: move_to_close_lru nfs4_openowner %p\n", oo); | 2467 | dprintk("NFSD: move_to_close_lru nfs4_openowner %p\n", oo); |
2450 | 2468 | ||
2451 | list_move_tail(&oo->oo_close_lru, &close_lru); | 2469 | list_move_tail(&oo->oo_close_lru, &nn->close_lru); |
2452 | oo->oo_time = get_seconds(); | 2470 | oo->oo_time = get_seconds(); |
2453 | } | 2471 | } |
2454 | 2472 | ||
@@ -2462,13 +2480,14 @@ same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner, | |||
2462 | } | 2480 | } |
2463 | 2481 | ||
2464 | static struct nfs4_openowner * | 2482 | static struct nfs4_openowner * |
2465 | find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open, bool sessions) | 2483 | find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open, |
2484 | bool sessions, struct nfsd_net *nn) | ||
2466 | { | 2485 | { |
2467 | struct nfs4_stateowner *so; | 2486 | struct nfs4_stateowner *so; |
2468 | struct nfs4_openowner *oo; | 2487 | struct nfs4_openowner *oo; |
2469 | struct nfs4_client *clp; | 2488 | struct nfs4_client *clp; |
2470 | 2489 | ||
2471 | list_for_each_entry(so, &ownerstr_hashtbl[hashval], so_strhash) { | 2490 | list_for_each_entry(so, &nn->ownerstr_hashtbl[hashval], so_strhash) { |
2472 | if (!so->so_is_open_owner) | 2491 | if (!so->so_is_open_owner) |
2473 | continue; | 2492 | continue; |
2474 | if (same_owner_str(so, &open->op_owner, &open->op_clientid)) { | 2493 | if (same_owner_str(so, &open->op_owner, &open->op_clientid)) { |
@@ -2555,9 +2574,14 @@ static void nfsd_break_deleg_cb(struct file_lock *fl) | |||
2555 | struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner; | 2574 | struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner; |
2556 | struct nfs4_delegation *dp; | 2575 | struct nfs4_delegation *dp; |
2557 | 2576 | ||
2558 | BUG_ON(!fp); | 2577 | if (!fp) { |
2559 | /* We assume break_lease is only called once per lease: */ | 2578 | WARN(1, "(%p)->fl_owner NULL\n", fl); |
2560 | BUG_ON(fp->fi_had_conflict); | 2579 | return; |
2580 | } | ||
2581 | if (fp->fi_had_conflict) { | ||
2582 | WARN(1, "duplicate break on %p\n", fp); | ||
2583 | return; | ||
2584 | } | ||
2561 | /* | 2585 | /* |
2562 | * We don't want the locks code to timeout the lease for us; | 2586 | * We don't want the locks code to timeout the lease for us; |
2563 | * we'll remove it ourself if a delegation isn't returned | 2587 | * we'll remove it ourself if a delegation isn't returned |
@@ -2599,14 +2623,13 @@ static __be32 nfsd4_check_seqid(struct nfsd4_compound_state *cstate, struct nfs4 | |||
2599 | 2623 | ||
2600 | __be32 | 2624 | __be32 |
2601 | nfsd4_process_open1(struct nfsd4_compound_state *cstate, | 2625 | nfsd4_process_open1(struct nfsd4_compound_state *cstate, |
2602 | struct nfsd4_open *open) | 2626 | struct nfsd4_open *open, struct nfsd_net *nn) |
2603 | { | 2627 | { |
2604 | clientid_t *clientid = &open->op_clientid; | 2628 | clientid_t *clientid = &open->op_clientid; |
2605 | struct nfs4_client *clp = NULL; | 2629 | struct nfs4_client *clp = NULL; |
2606 | unsigned int strhashval; | 2630 | unsigned int strhashval; |
2607 | struct nfs4_openowner *oo = NULL; | 2631 | struct nfs4_openowner *oo = NULL; |
2608 | __be32 status; | 2632 | __be32 status; |
2609 | struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); | ||
2610 | 2633 | ||
2611 | if (STALE_CLIENTID(&open->op_clientid, nn)) | 2634 | if (STALE_CLIENTID(&open->op_clientid, nn)) |
2612 | return nfserr_stale_clientid; | 2635 | return nfserr_stale_clientid; |
@@ -2619,10 +2642,11 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate, | |||
2619 | return nfserr_jukebox; | 2642 | return nfserr_jukebox; |
2620 | 2643 | ||
2621 | strhashval = ownerstr_hashval(clientid->cl_id, &open->op_owner); | 2644 | strhashval = ownerstr_hashval(clientid->cl_id, &open->op_owner); |
2622 | oo = find_openstateowner_str(strhashval, open, cstate->minorversion); | 2645 | oo = find_openstateowner_str(strhashval, open, cstate->minorversion, nn); |
2623 | open->op_openowner = oo; | 2646 | open->op_openowner = oo; |
2624 | if (!oo) { | 2647 | if (!oo) { |
2625 | clp = find_confirmed_client(clientid, cstate->minorversion); | 2648 | clp = find_confirmed_client(clientid, cstate->minorversion, |
2649 | nn); | ||
2626 | if (clp == NULL) | 2650 | if (clp == NULL) |
2627 | return nfserr_expired; | 2651 | return nfserr_expired; |
2628 | goto new_owner; | 2652 | goto new_owner; |
@@ -2891,7 +2915,7 @@ static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status) | |||
2891 | open->op_why_no_deleg = WND4_CANCELLED; | 2915 | open->op_why_no_deleg = WND4_CANCELLED; |
2892 | break; | 2916 | break; |
2893 | case NFS4_SHARE_WANT_NO_DELEG: | 2917 | case NFS4_SHARE_WANT_NO_DELEG: |
2894 | BUG(); /* not supposed to get here */ | 2918 | WARN_ON_ONCE(1); |
2895 | } | 2919 | } |
2896 | } | 2920 | } |
2897 | } | 2921 | } |
@@ -2959,6 +2983,7 @@ out: | |||
2959 | } | 2983 | } |
2960 | return; | 2984 | return; |
2961 | out_free: | 2985 | out_free: |
2986 | unhash_stid(&dp->dl_stid); | ||
2962 | nfs4_put_delegation(dp); | 2987 | nfs4_put_delegation(dp); |
2963 | out_no_deleg: | 2988 | out_no_deleg: |
2964 | flag = NFS4_OPEN_DELEGATE_NONE; | 2989 | flag = NFS4_OPEN_DELEGATE_NONE; |
@@ -3104,27 +3129,32 @@ void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status) | |||
3104 | free_generic_stateid(open->op_stp); | 3129 | free_generic_stateid(open->op_stp); |
3105 | } | 3130 | } |
3106 | 3131 | ||
3132 | static __be32 lookup_clientid(clientid_t *clid, bool session, struct nfsd_net *nn, struct nfs4_client **clp) | ||
3133 | { | ||
3134 | struct nfs4_client *found; | ||
3135 | |||
3136 | if (STALE_CLIENTID(clid, nn)) | ||
3137 | return nfserr_stale_clientid; | ||
3138 | found = find_confirmed_client(clid, session, nn); | ||
3139 | if (clp) | ||
3140 | *clp = found; | ||
3141 | return found ? nfs_ok : nfserr_expired; | ||
3142 | } | ||
3143 | |||
3107 | __be32 | 3144 | __be32 |
3108 | nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 3145 | nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
3109 | clientid_t *clid) | 3146 | clientid_t *clid) |
3110 | { | 3147 | { |
3111 | struct nfs4_client *clp; | 3148 | struct nfs4_client *clp; |
3112 | __be32 status; | 3149 | __be32 status; |
3113 | struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); | 3150 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); |
3114 | 3151 | ||
3115 | nfs4_lock_state(); | 3152 | nfs4_lock_state(); |
3116 | dprintk("process_renew(%08x/%08x): starting\n", | 3153 | dprintk("process_renew(%08x/%08x): starting\n", |
3117 | clid->cl_boot, clid->cl_id); | 3154 | clid->cl_boot, clid->cl_id); |
3118 | status = nfserr_stale_clientid; | 3155 | status = lookup_clientid(clid, cstate->minorversion, nn, &clp); |
3119 | if (STALE_CLIENTID(clid, nn)) | 3156 | if (status) |
3120 | goto out; | ||
3121 | clp = find_confirmed_client(clid, cstate->minorversion); | ||
3122 | status = nfserr_expired; | ||
3123 | if (clp == NULL) { | ||
3124 | /* We assume the client took too long to RENEW. */ | ||
3125 | dprintk("nfsd4_renew: clientid not found!\n"); | ||
3126 | goto out; | 3157 | goto out; |
3127 | } | ||
3128 | status = nfserr_cb_path_down; | 3158 | status = nfserr_cb_path_down; |
3129 | if (!list_empty(&clp->cl_delegations) | 3159 | if (!list_empty(&clp->cl_delegations) |
3130 | && clp->cl_cb_state != NFSD4_CB_UP) | 3160 | && clp->cl_cb_state != NFSD4_CB_UP) |
@@ -3136,44 +3166,42 @@ out: | |||
3136 | } | 3166 | } |
3137 | 3167 | ||
3138 | static void | 3168 | static void |
3139 | nfsd4_end_grace(struct net *net) | 3169 | nfsd4_end_grace(struct nfsd_net *nn) |
3140 | { | 3170 | { |
3141 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
3142 | |||
3143 | /* do nothing if grace period already ended */ | 3171 | /* do nothing if grace period already ended */ |
3144 | if (nn->grace_ended) | 3172 | if (nn->grace_ended) |
3145 | return; | 3173 | return; |
3146 | 3174 | ||
3147 | dprintk("NFSD: end of grace period\n"); | 3175 | dprintk("NFSD: end of grace period\n"); |
3148 | nn->grace_ended = true; | 3176 | nn->grace_ended = true; |
3149 | nfsd4_record_grace_done(net, nn->boot_time); | 3177 | nfsd4_record_grace_done(nn, nn->boot_time); |
3150 | locks_end_grace(&nn->nfsd4_manager); | 3178 | locks_end_grace(&nn->nfsd4_manager); |
3151 | /* | 3179 | /* |
3152 | * Now that every NFSv4 client has had the chance to recover and | 3180 | * Now that every NFSv4 client has had the chance to recover and |
3153 | * to see the (possibly new, possibly shorter) lease time, we | 3181 | * to see the (possibly new, possibly shorter) lease time, we |
3154 | * can safely set the next grace time to the current lease time: | 3182 | * can safely set the next grace time to the current lease time: |
3155 | */ | 3183 | */ |
3156 | nfsd4_grace = nfsd4_lease; | 3184 | nn->nfsd4_grace = nn->nfsd4_lease; |
3157 | } | 3185 | } |
3158 | 3186 | ||
3159 | static time_t | 3187 | static time_t |
3160 | nfs4_laundromat(void) | 3188 | nfs4_laundromat(struct nfsd_net *nn) |
3161 | { | 3189 | { |
3162 | struct nfs4_client *clp; | 3190 | struct nfs4_client *clp; |
3163 | struct nfs4_openowner *oo; | 3191 | struct nfs4_openowner *oo; |
3164 | struct nfs4_delegation *dp; | 3192 | struct nfs4_delegation *dp; |
3165 | struct list_head *pos, *next, reaplist; | 3193 | struct list_head *pos, *next, reaplist; |
3166 | time_t cutoff = get_seconds() - nfsd4_lease; | 3194 | time_t cutoff = get_seconds() - nn->nfsd4_lease; |
3167 | time_t t, clientid_val = nfsd4_lease; | 3195 | time_t t, clientid_val = nn->nfsd4_lease; |
3168 | time_t u, test_val = nfsd4_lease; | 3196 | time_t u, test_val = nn->nfsd4_lease; |
3169 | 3197 | ||
3170 | nfs4_lock_state(); | 3198 | nfs4_lock_state(); |
3171 | 3199 | ||
3172 | dprintk("NFSD: laundromat service - starting\n"); | 3200 | dprintk("NFSD: laundromat service - starting\n"); |
3173 | nfsd4_end_grace(&init_net); | 3201 | nfsd4_end_grace(nn); |
3174 | INIT_LIST_HEAD(&reaplist); | 3202 | INIT_LIST_HEAD(&reaplist); |
3175 | spin_lock(&client_lock); | 3203 | spin_lock(&nn->client_lock); |
3176 | list_for_each_safe(pos, next, &client_lru) { | 3204 | list_for_each_safe(pos, next, &nn->client_lru) { |
3177 | clp = list_entry(pos, struct nfs4_client, cl_lru); | 3205 | clp = list_entry(pos, struct nfs4_client, cl_lru); |
3178 | if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) { | 3206 | if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) { |
3179 | t = clp->cl_time - cutoff; | 3207 | t = clp->cl_time - cutoff; |
@@ -3189,7 +3217,7 @@ nfs4_laundromat(void) | |||
3189 | unhash_client_locked(clp); | 3217 | unhash_client_locked(clp); |
3190 | list_add(&clp->cl_lru, &reaplist); | 3218 | list_add(&clp->cl_lru, &reaplist); |
3191 | } | 3219 | } |
3192 | spin_unlock(&client_lock); | 3220 | spin_unlock(&nn->client_lock); |
3193 | list_for_each_safe(pos, next, &reaplist) { | 3221 | list_for_each_safe(pos, next, &reaplist) { |
3194 | clp = list_entry(pos, struct nfs4_client, cl_lru); | 3222 | clp = list_entry(pos, struct nfs4_client, cl_lru); |
3195 | dprintk("NFSD: purging unused client (clientid %08x)\n", | 3223 | dprintk("NFSD: purging unused client (clientid %08x)\n", |
@@ -3199,6 +3227,8 @@ nfs4_laundromat(void) | |||
3199 | spin_lock(&recall_lock); | 3227 | spin_lock(&recall_lock); |
3200 | list_for_each_safe(pos, next, &del_recall_lru) { | 3228 | list_for_each_safe(pos, next, &del_recall_lru) { |
3201 | dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); | 3229 | dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); |
3230 | if (net_generic(dp->dl_stid.sc_client->net, nfsd_net_id) != nn) | ||
3231 | continue; | ||
3202 | if (time_after((unsigned long)dp->dl_time, (unsigned long)cutoff)) { | 3232 | if (time_after((unsigned long)dp->dl_time, (unsigned long)cutoff)) { |
3203 | u = dp->dl_time - cutoff; | 3233 | u = dp->dl_time - cutoff; |
3204 | if (test_val > u) | 3234 | if (test_val > u) |
@@ -3212,8 +3242,8 @@ nfs4_laundromat(void) | |||
3212 | dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); | 3242 | dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); |
3213 | unhash_delegation(dp); | 3243 | unhash_delegation(dp); |
3214 | } | 3244 | } |
3215 | test_val = nfsd4_lease; | 3245 | test_val = nn->nfsd4_lease; |
3216 | list_for_each_safe(pos, next, &close_lru) { | 3246 | list_for_each_safe(pos, next, &nn->close_lru) { |
3217 | oo = container_of(pos, struct nfs4_openowner, oo_close_lru); | 3247 | oo = container_of(pos, struct nfs4_openowner, oo_close_lru); |
3218 | if (time_after((unsigned long)oo->oo_time, (unsigned long)cutoff)) { | 3248 | if (time_after((unsigned long)oo->oo_time, (unsigned long)cutoff)) { |
3219 | u = oo->oo_time - cutoff; | 3249 | u = oo->oo_time - cutoff; |
@@ -3231,16 +3261,19 @@ nfs4_laundromat(void) | |||
3231 | 3261 | ||
3232 | static struct workqueue_struct *laundry_wq; | 3262 | static struct workqueue_struct *laundry_wq; |
3233 | static void laundromat_main(struct work_struct *); | 3263 | static void laundromat_main(struct work_struct *); |
3234 | static DECLARE_DELAYED_WORK(laundromat_work, laundromat_main); | ||
3235 | 3264 | ||
3236 | static void | 3265 | static void |
3237 | laundromat_main(struct work_struct *not_used) | 3266 | laundromat_main(struct work_struct *laundry) |
3238 | { | 3267 | { |
3239 | time_t t; | 3268 | time_t t; |
3269 | struct delayed_work *dwork = container_of(laundry, struct delayed_work, | ||
3270 | work); | ||
3271 | struct nfsd_net *nn = container_of(dwork, struct nfsd_net, | ||
3272 | laundromat_work); | ||
3240 | 3273 | ||
3241 | t = nfs4_laundromat(); | 3274 | t = nfs4_laundromat(nn); |
3242 | dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t); | 3275 | dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t); |
3243 | queue_delayed_work(laundry_wq, &laundromat_work, t*HZ); | 3276 | queue_delayed_work(laundry_wq, &nn->laundromat_work, t*HZ); |
3244 | } | 3277 | } |
3245 | 3278 | ||
3246 | static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_ol_stateid *stp) | 3279 | static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_ol_stateid *stp) |
@@ -3385,16 +3418,17 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid) | |||
3385 | return nfs_ok; | 3418 | return nfs_ok; |
3386 | } | 3419 | } |
3387 | 3420 | ||
3388 | static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, struct nfs4_stid **s, bool sessions) | 3421 | static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, |
3422 | struct nfs4_stid **s, bool sessions, | ||
3423 | struct nfsd_net *nn) | ||
3389 | { | 3424 | { |
3390 | struct nfs4_client *cl; | 3425 | struct nfs4_client *cl; |
3391 | struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); | ||
3392 | 3426 | ||
3393 | if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) | 3427 | if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) |
3394 | return nfserr_bad_stateid; | 3428 | return nfserr_bad_stateid; |
3395 | if (STALE_STATEID(stateid, nn)) | 3429 | if (STALE_STATEID(stateid, nn)) |
3396 | return nfserr_stale_stateid; | 3430 | return nfserr_stale_stateid; |
3397 | cl = find_confirmed_client(&stateid->si_opaque.so_clid, sessions); | 3431 | cl = find_confirmed_client(&stateid->si_opaque.so_clid, sessions, nn); |
3398 | if (!cl) | 3432 | if (!cl) |
3399 | return nfserr_expired; | 3433 | return nfserr_expired; |
3400 | *s = find_stateid_by_type(cl, stateid, typemask); | 3434 | *s = find_stateid_by_type(cl, stateid, typemask); |
@@ -3416,6 +3450,7 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate, | |||
3416 | struct nfs4_delegation *dp = NULL; | 3450 | struct nfs4_delegation *dp = NULL; |
3417 | struct svc_fh *current_fh = &cstate->current_fh; | 3451 | struct svc_fh *current_fh = &cstate->current_fh; |
3418 | struct inode *ino = current_fh->fh_dentry->d_inode; | 3452 | struct inode *ino = current_fh->fh_dentry->d_inode; |
3453 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
3419 | __be32 status; | 3454 | __be32 status; |
3420 | 3455 | ||
3421 | if (filpp) | 3456 | if (filpp) |
@@ -3427,7 +3462,8 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate, | |||
3427 | if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) | 3462 | if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) |
3428 | return check_special_stateids(net, current_fh, stateid, flags); | 3463 | return check_special_stateids(net, current_fh, stateid, flags); |
3429 | 3464 | ||
3430 | status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, &s, cstate->minorversion); | 3465 | status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, |
3466 | &s, cstate->minorversion, nn); | ||
3431 | if (status) | 3467 | if (status) |
3432 | return status; | 3468 | return status; |
3433 | status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate)); | 3469 | status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate)); |
@@ -3441,7 +3477,11 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate, | |||
3441 | goto out; | 3477 | goto out; |
3442 | if (filpp) { | 3478 | if (filpp) { |
3443 | *filpp = dp->dl_file->fi_deleg_file; | 3479 | *filpp = dp->dl_file->fi_deleg_file; |
3444 | BUG_ON(!*filpp); | 3480 | if (!*filpp) { |
3481 | WARN_ON_ONCE(1); | ||
3482 | status = nfserr_serverfault; | ||
3483 | goto out; | ||
3484 | } | ||
3445 | } | 3485 | } |
3446 | break; | 3486 | break; |
3447 | case NFS4_OPEN_STID: | 3487 | case NFS4_OPEN_STID: |
@@ -3568,7 +3608,8 @@ static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_ | |||
3568 | static __be32 | 3608 | static __be32 |
3569 | nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, | 3609 | nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, |
3570 | stateid_t *stateid, char typemask, | 3610 | stateid_t *stateid, char typemask, |
3571 | struct nfs4_ol_stateid **stpp) | 3611 | struct nfs4_ol_stateid **stpp, |
3612 | struct nfsd_net *nn) | ||
3572 | { | 3613 | { |
3573 | __be32 status; | 3614 | __be32 status; |
3574 | struct nfs4_stid *s; | 3615 | struct nfs4_stid *s; |
@@ -3577,7 +3618,8 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, | |||
3577 | seqid, STATEID_VAL(stateid)); | 3618 | seqid, STATEID_VAL(stateid)); |
3578 | 3619 | ||
3579 | *stpp = NULL; | 3620 | *stpp = NULL; |
3580 | status = nfsd4_lookup_stateid(stateid, typemask, &s, cstate->minorversion); | 3621 | status = nfsd4_lookup_stateid(stateid, typemask, &s, |
3622 | cstate->minorversion, nn); | ||
3581 | if (status) | 3623 | if (status) |
3582 | return status; | 3624 | return status; |
3583 | *stpp = openlockstateid(s); | 3625 | *stpp = openlockstateid(s); |
@@ -3586,13 +3628,14 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, | |||
3586 | return nfs4_seqid_op_checks(cstate, stateid, seqid, *stpp); | 3628 | return nfs4_seqid_op_checks(cstate, stateid, seqid, *stpp); |
3587 | } | 3629 | } |
3588 | 3630 | ||
3589 | static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, stateid_t *stateid, struct nfs4_ol_stateid **stpp) | 3631 | static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, |
3632 | stateid_t *stateid, struct nfs4_ol_stateid **stpp, struct nfsd_net *nn) | ||
3590 | { | 3633 | { |
3591 | __be32 status; | 3634 | __be32 status; |
3592 | struct nfs4_openowner *oo; | 3635 | struct nfs4_openowner *oo; |
3593 | 3636 | ||
3594 | status = nfs4_preprocess_seqid_op(cstate, seqid, stateid, | 3637 | status = nfs4_preprocess_seqid_op(cstate, seqid, stateid, |
3595 | NFS4_OPEN_STID, stpp); | 3638 | NFS4_OPEN_STID, stpp, nn); |
3596 | if (status) | 3639 | if (status) |
3597 | return status; | 3640 | return status; |
3598 | oo = openowner((*stpp)->st_stateowner); | 3641 | oo = openowner((*stpp)->st_stateowner); |
@@ -3608,6 +3651,7 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3608 | __be32 status; | 3651 | __be32 status; |
3609 | struct nfs4_openowner *oo; | 3652 | struct nfs4_openowner *oo; |
3610 | struct nfs4_ol_stateid *stp; | 3653 | struct nfs4_ol_stateid *stp; |
3654 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
3611 | 3655 | ||
3612 | dprintk("NFSD: nfsd4_open_confirm on file %.*s\n", | 3656 | dprintk("NFSD: nfsd4_open_confirm on file %.*s\n", |
3613 | (int)cstate->current_fh.fh_dentry->d_name.len, | 3657 | (int)cstate->current_fh.fh_dentry->d_name.len, |
@@ -3621,7 +3665,7 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3621 | 3665 | ||
3622 | status = nfs4_preprocess_seqid_op(cstate, | 3666 | status = nfs4_preprocess_seqid_op(cstate, |
3623 | oc->oc_seqid, &oc->oc_req_stateid, | 3667 | oc->oc_seqid, &oc->oc_req_stateid, |
3624 | NFS4_OPEN_STID, &stp); | 3668 | NFS4_OPEN_STID, &stp, nn); |
3625 | if (status) | 3669 | if (status) |
3626 | goto out; | 3670 | goto out; |
3627 | oo = openowner(stp->st_stateowner); | 3671 | oo = openowner(stp->st_stateowner); |
@@ -3664,7 +3708,7 @@ static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_ac | |||
3664 | case NFS4_SHARE_ACCESS_BOTH: | 3708 | case NFS4_SHARE_ACCESS_BOTH: |
3665 | break; | 3709 | break; |
3666 | default: | 3710 | default: |
3667 | BUG(); | 3711 | WARN_ON_ONCE(1); |
3668 | } | 3712 | } |
3669 | } | 3713 | } |
3670 | 3714 | ||
@@ -3685,6 +3729,7 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, | |||
3685 | { | 3729 | { |
3686 | __be32 status; | 3730 | __be32 status; |
3687 | struct nfs4_ol_stateid *stp; | 3731 | struct nfs4_ol_stateid *stp; |
3732 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
3688 | 3733 | ||
3689 | dprintk("NFSD: nfsd4_open_downgrade on file %.*s\n", | 3734 | dprintk("NFSD: nfsd4_open_downgrade on file %.*s\n", |
3690 | (int)cstate->current_fh.fh_dentry->d_name.len, | 3735 | (int)cstate->current_fh.fh_dentry->d_name.len, |
@@ -3697,7 +3742,7 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, | |||
3697 | 3742 | ||
3698 | nfs4_lock_state(); | 3743 | nfs4_lock_state(); |
3699 | status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid, | 3744 | status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid, |
3700 | &od->od_stateid, &stp); | 3745 | &od->od_stateid, &stp, nn); |
3701 | if (status) | 3746 | if (status) |
3702 | goto out; | 3747 | goto out; |
3703 | status = nfserr_inval; | 3748 | status = nfserr_inval; |
@@ -3760,6 +3805,8 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3760 | __be32 status; | 3805 | __be32 status; |
3761 | struct nfs4_openowner *oo; | 3806 | struct nfs4_openowner *oo; |
3762 | struct nfs4_ol_stateid *stp; | 3807 | struct nfs4_ol_stateid *stp; |
3808 | struct net *net = SVC_NET(rqstp); | ||
3809 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
3763 | 3810 | ||
3764 | dprintk("NFSD: nfsd4_close on file %.*s\n", | 3811 | dprintk("NFSD: nfsd4_close on file %.*s\n", |
3765 | (int)cstate->current_fh.fh_dentry->d_name.len, | 3812 | (int)cstate->current_fh.fh_dentry->d_name.len, |
@@ -3769,7 +3816,7 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3769 | status = nfs4_preprocess_seqid_op(cstate, close->cl_seqid, | 3816 | status = nfs4_preprocess_seqid_op(cstate, close->cl_seqid, |
3770 | &close->cl_stateid, | 3817 | &close->cl_stateid, |
3771 | NFS4_OPEN_STID|NFS4_CLOSED_STID, | 3818 | NFS4_OPEN_STID|NFS4_CLOSED_STID, |
3772 | &stp); | 3819 | &stp, nn); |
3773 | if (status) | 3820 | if (status) |
3774 | goto out; | 3821 | goto out; |
3775 | oo = openowner(stp->st_stateowner); | 3822 | oo = openowner(stp->st_stateowner); |
@@ -3791,7 +3838,7 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3791 | * little while to handle CLOSE replay. | 3838 | * little while to handle CLOSE replay. |
3792 | */ | 3839 | */ |
3793 | if (list_empty(&oo->oo_owner.so_stateids)) | 3840 | if (list_empty(&oo->oo_owner.so_stateids)) |
3794 | move_to_close_lru(oo); | 3841 | move_to_close_lru(oo, SVC_NET(rqstp)); |
3795 | } | 3842 | } |
3796 | } | 3843 | } |
3797 | out: | 3844 | out: |
@@ -3807,15 +3854,15 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3807 | struct nfs4_delegation *dp; | 3854 | struct nfs4_delegation *dp; |
3808 | stateid_t *stateid = &dr->dr_stateid; | 3855 | stateid_t *stateid = &dr->dr_stateid; |
3809 | struct nfs4_stid *s; | 3856 | struct nfs4_stid *s; |
3810 | struct inode *inode; | ||
3811 | __be32 status; | 3857 | __be32 status; |
3858 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
3812 | 3859 | ||
3813 | if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) | 3860 | if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) |
3814 | return status; | 3861 | return status; |
3815 | inode = cstate->current_fh.fh_dentry->d_inode; | ||
3816 | 3862 | ||
3817 | nfs4_lock_state(); | 3863 | nfs4_lock_state(); |
3818 | status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID, &s, cstate->minorversion); | 3864 | status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID, &s, |
3865 | cstate->minorversion, nn); | ||
3819 | if (status) | 3866 | if (status) |
3820 | goto out; | 3867 | goto out; |
3821 | dp = delegstateid(s); | 3868 | dp = delegstateid(s); |
@@ -3833,8 +3880,6 @@ out: | |||
3833 | 3880 | ||
3834 | #define LOFF_OVERFLOW(start, len) ((u64)(len) > ~(u64)(start)) | 3881 | #define LOFF_OVERFLOW(start, len) ((u64)(len) > ~(u64)(start)) |
3835 | 3882 | ||
3836 | #define LOCKOWNER_INO_HASH_BITS 8 | ||
3837 | #define LOCKOWNER_INO_HASH_SIZE (1 << LOCKOWNER_INO_HASH_BITS) | ||
3838 | #define LOCKOWNER_INO_HASH_MASK (LOCKOWNER_INO_HASH_SIZE - 1) | 3883 | #define LOCKOWNER_INO_HASH_MASK (LOCKOWNER_INO_HASH_SIZE - 1) |
3839 | 3884 | ||
3840 | static inline u64 | 3885 | static inline u64 |
@@ -3852,7 +3897,7 @@ last_byte_offset(u64 start, u64 len) | |||
3852 | { | 3897 | { |
3853 | u64 end; | 3898 | u64 end; |
3854 | 3899 | ||
3855 | BUG_ON(!len); | 3900 | WARN_ON_ONCE(!len); |
3856 | end = start + len; | 3901 | end = start + len; |
3857 | return end > start ? end - 1: NFS4_MAX_UINT64; | 3902 | return end > start ? end - 1: NFS4_MAX_UINT64; |
3858 | } | 3903 | } |
@@ -3864,8 +3909,6 @@ static unsigned int lockowner_ino_hashval(struct inode *inode, u32 cl_id, struct | |||
3864 | & LOCKOWNER_INO_HASH_MASK; | 3909 | & LOCKOWNER_INO_HASH_MASK; |
3865 | } | 3910 | } |
3866 | 3911 | ||
3867 | static struct list_head lockowner_ino_hashtbl[LOCKOWNER_INO_HASH_SIZE]; | ||
3868 | |||
3869 | /* | 3912 | /* |
3870 | * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that | 3913 | * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that |
3871 | * we can't properly handle lock requests that go beyond the (2^63 - 1)-th | 3914 | * we can't properly handle lock requests that go beyond the (2^63 - 1)-th |
@@ -3931,12 +3974,12 @@ static bool same_lockowner_ino(struct nfs4_lockowner *lo, struct inode *inode, c | |||
3931 | 3974 | ||
3932 | static struct nfs4_lockowner * | 3975 | static struct nfs4_lockowner * |
3933 | find_lockowner_str(struct inode *inode, clientid_t *clid, | 3976 | find_lockowner_str(struct inode *inode, clientid_t *clid, |
3934 | struct xdr_netobj *owner) | 3977 | struct xdr_netobj *owner, struct nfsd_net *nn) |
3935 | { | 3978 | { |
3936 | unsigned int hashval = lockowner_ino_hashval(inode, clid->cl_id, owner); | 3979 | unsigned int hashval = lockowner_ino_hashval(inode, clid->cl_id, owner); |
3937 | struct nfs4_lockowner *lo; | 3980 | struct nfs4_lockowner *lo; |
3938 | 3981 | ||
3939 | list_for_each_entry(lo, &lockowner_ino_hashtbl[hashval], lo_owner_ino_hash) { | 3982 | list_for_each_entry(lo, &nn->lockowner_ino_hashtbl[hashval], lo_owner_ino_hash) { |
3940 | if (same_lockowner_ino(lo, inode, clid, owner)) | 3983 | if (same_lockowner_ino(lo, inode, clid, owner)) |
3941 | return lo; | 3984 | return lo; |
3942 | } | 3985 | } |
@@ -3948,9 +3991,10 @@ static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, s | |||
3948 | struct inode *inode = open_stp->st_file->fi_inode; | 3991 | struct inode *inode = open_stp->st_file->fi_inode; |
3949 | unsigned int inohash = lockowner_ino_hashval(inode, | 3992 | unsigned int inohash = lockowner_ino_hashval(inode, |
3950 | clp->cl_clientid.cl_id, &lo->lo_owner.so_owner); | 3993 | clp->cl_clientid.cl_id, &lo->lo_owner.so_owner); |
3994 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); | ||
3951 | 3995 | ||
3952 | list_add(&lo->lo_owner.so_strhash, &ownerstr_hashtbl[strhashval]); | 3996 | list_add(&lo->lo_owner.so_strhash, &nn->ownerstr_hashtbl[strhashval]); |
3953 | list_add(&lo->lo_owner_ino_hash, &lockowner_ino_hashtbl[inohash]); | 3997 | list_add(&lo->lo_owner_ino_hash, &nn->lockowner_ino_hashtbl[inohash]); |
3954 | list_add(&lo->lo_perstateid, &open_stp->st_lockowners); | 3998 | list_add(&lo->lo_perstateid, &open_stp->st_lockowners); |
3955 | } | 3999 | } |
3956 | 4000 | ||
@@ -4024,8 +4068,10 @@ static __be32 lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, s | |||
4024 | struct nfs4_client *cl = oo->oo_owner.so_client; | 4068 | struct nfs4_client *cl = oo->oo_owner.so_client; |
4025 | struct nfs4_lockowner *lo; | 4069 | struct nfs4_lockowner *lo; |
4026 | unsigned int strhashval; | 4070 | unsigned int strhashval; |
4071 | struct nfsd_net *nn = net_generic(cl->net, nfsd_net_id); | ||
4027 | 4072 | ||
4028 | lo = find_lockowner_str(fi->fi_inode, &cl->cl_clientid, &lock->v.new.owner); | 4073 | lo = find_lockowner_str(fi->fi_inode, &cl->cl_clientid, |
4074 | &lock->v.new.owner, nn); | ||
4029 | if (lo) { | 4075 | if (lo) { |
4030 | if (!cstate->minorversion) | 4076 | if (!cstate->minorversion) |
4031 | return nfserr_bad_seqid; | 4077 | return nfserr_bad_seqid; |
@@ -4065,7 +4111,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4065 | bool new_state = false; | 4111 | bool new_state = false; |
4066 | int lkflg; | 4112 | int lkflg; |
4067 | int err; | 4113 | int err; |
4068 | struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); | 4114 | struct net *net = SVC_NET(rqstp); |
4115 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
4069 | 4116 | ||
4070 | dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", | 4117 | dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", |
4071 | (long long) lock->lk_offset, | 4118 | (long long) lock->lk_offset, |
@@ -4099,7 +4146,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4099 | status = nfs4_preprocess_confirmed_seqid_op(cstate, | 4146 | status = nfs4_preprocess_confirmed_seqid_op(cstate, |
4100 | lock->lk_new_open_seqid, | 4147 | lock->lk_new_open_seqid, |
4101 | &lock->lk_new_open_stateid, | 4148 | &lock->lk_new_open_stateid, |
4102 | &open_stp); | 4149 | &open_stp, nn); |
4103 | if (status) | 4150 | if (status) |
4104 | goto out; | 4151 | goto out; |
4105 | open_sop = openowner(open_stp->st_stateowner); | 4152 | open_sop = openowner(open_stp->st_stateowner); |
@@ -4113,7 +4160,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4113 | status = nfs4_preprocess_seqid_op(cstate, | 4160 | status = nfs4_preprocess_seqid_op(cstate, |
4114 | lock->lk_old_lock_seqid, | 4161 | lock->lk_old_lock_seqid, |
4115 | &lock->lk_old_lock_stateid, | 4162 | &lock->lk_old_lock_stateid, |
4116 | NFS4_LOCK_STID, &lock_stp); | 4163 | NFS4_LOCK_STID, &lock_stp, nn); |
4117 | if (status) | 4164 | if (status) |
4118 | goto out; | 4165 | goto out; |
4119 | lock_sop = lockowner(lock_stp->st_stateowner); | 4166 | lock_sop = lockowner(lock_stp->st_stateowner); |
@@ -4124,10 +4171,10 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4124 | goto out; | 4171 | goto out; |
4125 | 4172 | ||
4126 | status = nfserr_grace; | 4173 | status = nfserr_grace; |
4127 | if (locks_in_grace(SVC_NET(rqstp)) && !lock->lk_reclaim) | 4174 | if (locks_in_grace(net) && !lock->lk_reclaim) |
4128 | goto out; | 4175 | goto out; |
4129 | status = nfserr_no_grace; | 4176 | status = nfserr_no_grace; |
4130 | if (!locks_in_grace(SVC_NET(rqstp)) && lock->lk_reclaim) | 4177 | if (!locks_in_grace(net) && lock->lk_reclaim) |
4131 | goto out; | 4178 | goto out; |
4132 | 4179 | ||
4133 | file_lock = locks_alloc_lock(); | 4180 | file_lock = locks_alloc_lock(); |
@@ -4238,7 +4285,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4238 | struct file_lock *file_lock = NULL; | 4285 | struct file_lock *file_lock = NULL; |
4239 | struct nfs4_lockowner *lo; | 4286 | struct nfs4_lockowner *lo; |
4240 | __be32 status; | 4287 | __be32 status; |
4241 | struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); | 4288 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); |
4242 | 4289 | ||
4243 | if (locks_in_grace(SVC_NET(rqstp))) | 4290 | if (locks_in_grace(SVC_NET(rqstp))) |
4244 | return nfserr_grace; | 4291 | return nfserr_grace; |
@@ -4248,9 +4295,11 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4248 | 4295 | ||
4249 | nfs4_lock_state(); | 4296 | nfs4_lock_state(); |
4250 | 4297 | ||
4251 | status = nfserr_stale_clientid; | 4298 | if (!nfsd4_has_session(cstate)) { |
4252 | if (!nfsd4_has_session(cstate) && STALE_CLIENTID(&lockt->lt_clientid, nn)) | 4299 | status = lookup_clientid(&lockt->lt_clientid, false, nn, NULL); |
4253 | goto out; | 4300 | if (status) |
4301 | goto out; | ||
4302 | } | ||
4254 | 4303 | ||
4255 | if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) | 4304 | if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) |
4256 | goto out; | 4305 | goto out; |
@@ -4278,7 +4327,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4278 | goto out; | 4327 | goto out; |
4279 | } | 4328 | } |
4280 | 4329 | ||
4281 | lo = find_lockowner_str(inode, &lockt->lt_clientid, &lockt->lt_owner); | 4330 | lo = find_lockowner_str(inode, &lockt->lt_clientid, &lockt->lt_owner, nn); |
4282 | if (lo) | 4331 | if (lo) |
4283 | file_lock->fl_owner = (fl_owner_t)lo; | 4332 | file_lock->fl_owner = (fl_owner_t)lo; |
4284 | file_lock->fl_pid = current->tgid; | 4333 | file_lock->fl_pid = current->tgid; |
@@ -4313,7 +4362,8 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4313 | struct file_lock *file_lock = NULL; | 4362 | struct file_lock *file_lock = NULL; |
4314 | __be32 status; | 4363 | __be32 status; |
4315 | int err; | 4364 | int err; |
4316 | 4365 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | |
4366 | |||
4317 | dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n", | 4367 | dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n", |
4318 | (long long) locku->lu_offset, | 4368 | (long long) locku->lu_offset, |
4319 | (long long) locku->lu_length); | 4369 | (long long) locku->lu_length); |
@@ -4324,7 +4374,8 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4324 | nfs4_lock_state(); | 4374 | nfs4_lock_state(); |
4325 | 4375 | ||
4326 | status = nfs4_preprocess_seqid_op(cstate, locku->lu_seqid, | 4376 | status = nfs4_preprocess_seqid_op(cstate, locku->lu_seqid, |
4327 | &locku->lu_stateid, NFS4_LOCK_STID, &stp); | 4377 | &locku->lu_stateid, NFS4_LOCK_STID, |
4378 | &stp, nn); | ||
4328 | if (status) | 4379 | if (status) |
4329 | goto out; | 4380 | goto out; |
4330 | filp = find_any_file(stp->st_file); | 4381 | filp = find_any_file(stp->st_file); |
@@ -4414,23 +4465,21 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, | |||
4414 | struct list_head matches; | 4465 | struct list_head matches; |
4415 | unsigned int hashval = ownerstr_hashval(clid->cl_id, owner); | 4466 | unsigned int hashval = ownerstr_hashval(clid->cl_id, owner); |
4416 | __be32 status; | 4467 | __be32 status; |
4417 | struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); | 4468 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); |
4418 | 4469 | ||
4419 | dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", | 4470 | dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", |
4420 | clid->cl_boot, clid->cl_id); | 4471 | clid->cl_boot, clid->cl_id); |
4421 | 4472 | ||
4422 | /* XXX check for lease expiration */ | ||
4423 | |||
4424 | status = nfserr_stale_clientid; | ||
4425 | if (STALE_CLIENTID(clid, nn)) | ||
4426 | return status; | ||
4427 | |||
4428 | nfs4_lock_state(); | 4473 | nfs4_lock_state(); |
4429 | 4474 | ||
4475 | status = lookup_clientid(clid, cstate->minorversion, nn, NULL); | ||
4476 | if (status) | ||
4477 | goto out; | ||
4478 | |||
4430 | status = nfserr_locks_held; | 4479 | status = nfserr_locks_held; |
4431 | INIT_LIST_HEAD(&matches); | 4480 | INIT_LIST_HEAD(&matches); |
4432 | 4481 | ||
4433 | list_for_each_entry(sop, &ownerstr_hashtbl[hashval], so_strhash) { | 4482 | list_for_each_entry(sop, &nn->ownerstr_hashtbl[hashval], so_strhash) { |
4434 | if (sop->so_is_open_owner) | 4483 | if (sop->so_is_open_owner) |
4435 | continue; | 4484 | continue; |
4436 | if (!same_owner_str(sop, owner, clid)) | 4485 | if (!same_owner_str(sop, owner, clid)) |
@@ -4466,73 +4515,74 @@ alloc_reclaim(void) | |||
4466 | return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL); | 4515 | return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL); |
4467 | } | 4516 | } |
4468 | 4517 | ||
4469 | int | 4518 | bool |
4470 | nfs4_has_reclaimed_state(const char *name, bool use_exchange_id) | 4519 | nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn) |
4471 | { | 4520 | { |
4472 | unsigned int strhashval = clientstr_hashval(name); | 4521 | struct nfs4_client_reclaim *crp; |
4473 | struct nfs4_client *clp; | ||
4474 | 4522 | ||
4475 | clp = find_confirmed_client_by_str(name, strhashval); | 4523 | crp = nfsd4_find_reclaim_client(name, nn); |
4476 | if (!clp) | 4524 | return (crp && crp->cr_clp); |
4477 | return 0; | ||
4478 | return test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); | ||
4479 | } | 4525 | } |
4480 | 4526 | ||
4481 | /* | 4527 | /* |
4482 | * failure => all reset bets are off, nfserr_no_grace... | 4528 | * failure => all reset bets are off, nfserr_no_grace... |
4483 | */ | 4529 | */ |
4484 | int | 4530 | struct nfs4_client_reclaim * |
4485 | nfs4_client_to_reclaim(const char *name) | 4531 | nfs4_client_to_reclaim(const char *name, struct nfsd_net *nn) |
4486 | { | 4532 | { |
4487 | unsigned int strhashval; | 4533 | unsigned int strhashval; |
4488 | struct nfs4_client_reclaim *crp = NULL; | 4534 | struct nfs4_client_reclaim *crp; |
4489 | 4535 | ||
4490 | dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", HEXDIR_LEN, name); | 4536 | dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", HEXDIR_LEN, name); |
4491 | crp = alloc_reclaim(); | 4537 | crp = alloc_reclaim(); |
4492 | if (!crp) | 4538 | if (crp) { |
4493 | return 0; | 4539 | strhashval = clientstr_hashval(name); |
4494 | strhashval = clientstr_hashval(name); | 4540 | INIT_LIST_HEAD(&crp->cr_strhash); |
4495 | INIT_LIST_HEAD(&crp->cr_strhash); | 4541 | list_add(&crp->cr_strhash, &nn->reclaim_str_hashtbl[strhashval]); |
4496 | list_add(&crp->cr_strhash, &reclaim_str_hashtbl[strhashval]); | 4542 | memcpy(crp->cr_recdir, name, HEXDIR_LEN); |
4497 | memcpy(crp->cr_recdir, name, HEXDIR_LEN); | 4543 | crp->cr_clp = NULL; |
4498 | reclaim_str_hashtbl_size++; | 4544 | nn->reclaim_str_hashtbl_size++; |
4499 | return 1; | 4545 | } |
4546 | return crp; | ||
4547 | } | ||
4548 | |||
4549 | void | ||
4550 | nfs4_remove_reclaim_record(struct nfs4_client_reclaim *crp, struct nfsd_net *nn) | ||
4551 | { | ||
4552 | list_del(&crp->cr_strhash); | ||
4553 | kfree(crp); | ||
4554 | nn->reclaim_str_hashtbl_size--; | ||
4500 | } | 4555 | } |
4501 | 4556 | ||
4502 | void | 4557 | void |
4503 | nfs4_release_reclaim(void) | 4558 | nfs4_release_reclaim(struct nfsd_net *nn) |
4504 | { | 4559 | { |
4505 | struct nfs4_client_reclaim *crp = NULL; | 4560 | struct nfs4_client_reclaim *crp = NULL; |
4506 | int i; | 4561 | int i; |
4507 | 4562 | ||
4508 | for (i = 0; i < CLIENT_HASH_SIZE; i++) { | 4563 | for (i = 0; i < CLIENT_HASH_SIZE; i++) { |
4509 | while (!list_empty(&reclaim_str_hashtbl[i])) { | 4564 | while (!list_empty(&nn->reclaim_str_hashtbl[i])) { |
4510 | crp = list_entry(reclaim_str_hashtbl[i].next, | 4565 | crp = list_entry(nn->reclaim_str_hashtbl[i].next, |
4511 | struct nfs4_client_reclaim, cr_strhash); | 4566 | struct nfs4_client_reclaim, cr_strhash); |
4512 | list_del(&crp->cr_strhash); | 4567 | nfs4_remove_reclaim_record(crp, nn); |
4513 | kfree(crp); | ||
4514 | reclaim_str_hashtbl_size--; | ||
4515 | } | 4568 | } |
4516 | } | 4569 | } |
4517 | BUG_ON(reclaim_str_hashtbl_size); | 4570 | WARN_ON_ONCE(nn->reclaim_str_hashtbl_size); |
4518 | } | 4571 | } |
4519 | 4572 | ||
4520 | /* | 4573 | /* |
4521 | * called from OPEN, CLAIM_PREVIOUS with a new clientid. */ | 4574 | * called from OPEN, CLAIM_PREVIOUS with a new clientid. */ |
4522 | struct nfs4_client_reclaim * | 4575 | struct nfs4_client_reclaim * |
4523 | nfsd4_find_reclaim_client(struct nfs4_client *clp) | 4576 | nfsd4_find_reclaim_client(const char *recdir, struct nfsd_net *nn) |
4524 | { | 4577 | { |
4525 | unsigned int strhashval; | 4578 | unsigned int strhashval; |
4526 | struct nfs4_client_reclaim *crp = NULL; | 4579 | struct nfs4_client_reclaim *crp = NULL; |
4527 | 4580 | ||
4528 | dprintk("NFSD: nfs4_find_reclaim_client for %.*s with recdir %s\n", | 4581 | dprintk("NFSD: nfs4_find_reclaim_client for recdir %s\n", recdir); |
4529 | clp->cl_name.len, clp->cl_name.data, | ||
4530 | clp->cl_recdir); | ||
4531 | 4582 | ||
4532 | /* find clp->cl_name in reclaim_str_hashtbl */ | 4583 | strhashval = clientstr_hashval(recdir); |
4533 | strhashval = clientstr_hashval(clp->cl_recdir); | 4584 | list_for_each_entry(crp, &nn->reclaim_str_hashtbl[strhashval], cr_strhash) { |
4534 | list_for_each_entry(crp, &reclaim_str_hashtbl[strhashval], cr_strhash) { | 4585 | if (same_name(crp->cr_recdir, recdir)) { |
4535 | if (same_name(crp->cr_recdir, clp->cl_recdir)) { | ||
4536 | return crp; | 4586 | return crp; |
4537 | } | 4587 | } |
4538 | } | 4588 | } |
@@ -4543,12 +4593,12 @@ nfsd4_find_reclaim_client(struct nfs4_client *clp) | |||
4543 | * Called from OPEN. Look for clientid in reclaim list. | 4593 | * Called from OPEN. Look for clientid in reclaim list. |
4544 | */ | 4594 | */ |
4545 | __be32 | 4595 | __be32 |
4546 | nfs4_check_open_reclaim(clientid_t *clid, bool sessions) | 4596 | nfs4_check_open_reclaim(clientid_t *clid, bool sessions, struct nfsd_net *nn) |
4547 | { | 4597 | { |
4548 | struct nfs4_client *clp; | 4598 | struct nfs4_client *clp; |
4549 | 4599 | ||
4550 | /* find clientid in conf_id_hashtbl */ | 4600 | /* find clientid in conf_id_hashtbl */ |
4551 | clp = find_confirmed_client(clid, sessions); | 4601 | clp = find_confirmed_client(clid, sessions, nn); |
4552 | if (clp == NULL) | 4602 | if (clp == NULL) |
4553 | return nfserr_reclaim_bad; | 4603 | return nfserr_reclaim_bad; |
4554 | 4604 | ||
@@ -4557,124 +4607,177 @@ nfs4_check_open_reclaim(clientid_t *clid, bool sessions) | |||
4557 | 4607 | ||
4558 | #ifdef CONFIG_NFSD_FAULT_INJECTION | 4608 | #ifdef CONFIG_NFSD_FAULT_INJECTION |
4559 | 4609 | ||
4560 | void nfsd_forget_clients(u64 num) | 4610 | u64 nfsd_forget_client(struct nfs4_client *clp, u64 max) |
4561 | { | 4611 | { |
4562 | struct nfs4_client *clp, *next; | 4612 | expire_client(clp); |
4563 | int count = 0; | 4613 | return 1; |
4564 | |||
4565 | nfs4_lock_state(); | ||
4566 | list_for_each_entry_safe(clp, next, &client_lru, cl_lru) { | ||
4567 | expire_client(clp); | ||
4568 | if (++count == num) | ||
4569 | break; | ||
4570 | } | ||
4571 | nfs4_unlock_state(); | ||
4572 | |||
4573 | printk(KERN_INFO "NFSD: Forgot %d clients", count); | ||
4574 | } | 4614 | } |
4575 | 4615 | ||
4576 | static void release_lockowner_sop(struct nfs4_stateowner *sop) | 4616 | u64 nfsd_print_client(struct nfs4_client *clp, u64 num) |
4577 | { | 4617 | { |
4578 | release_lockowner(lockowner(sop)); | 4618 | char buf[INET6_ADDRSTRLEN]; |
4619 | rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf)); | ||
4620 | printk(KERN_INFO "NFS Client: %s\n", buf); | ||
4621 | return 1; | ||
4579 | } | 4622 | } |
4580 | 4623 | ||
4581 | static void release_openowner_sop(struct nfs4_stateowner *sop) | 4624 | static void nfsd_print_count(struct nfs4_client *clp, unsigned int count, |
4625 | const char *type) | ||
4582 | { | 4626 | { |
4583 | release_openowner(openowner(sop)); | 4627 | char buf[INET6_ADDRSTRLEN]; |
4628 | rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf)); | ||
4629 | printk(KERN_INFO "NFS Client: %s has %u %s\n", buf, count, type); | ||
4584 | } | 4630 | } |
4585 | 4631 | ||
4586 | static int nfsd_release_n_owners(u64 num, bool is_open_owner, | 4632 | static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max, void (*func)(struct nfs4_lockowner *)) |
4587 | void (*release_sop)(struct nfs4_stateowner *)) | ||
4588 | { | 4633 | { |
4589 | int i, count = 0; | 4634 | struct nfs4_openowner *oop; |
4590 | struct nfs4_stateowner *sop, *next; | 4635 | struct nfs4_lockowner *lop, *lo_next; |
4636 | struct nfs4_ol_stateid *stp, *st_next; | ||
4637 | u64 count = 0; | ||
4591 | 4638 | ||
4592 | for (i = 0; i < OWNER_HASH_SIZE; i++) { | 4639 | list_for_each_entry(oop, &clp->cl_openowners, oo_perclient) { |
4593 | list_for_each_entry_safe(sop, next, &ownerstr_hashtbl[i], so_strhash) { | 4640 | list_for_each_entry_safe(stp, st_next, &oop->oo_owner.so_stateids, st_perstateowner) { |
4594 | if (sop->so_is_open_owner != is_open_owner) | 4641 | list_for_each_entry_safe(lop, lo_next, &stp->st_lockowners, lo_perstateid) { |
4595 | continue; | 4642 | if (func) |
4596 | release_sop(sop); | 4643 | func(lop); |
4597 | if (++count == num) | 4644 | if (++count == max) |
4598 | return count; | 4645 | return count; |
4646 | } | ||
4599 | } | 4647 | } |
4600 | } | 4648 | } |
4649 | |||
4601 | return count; | 4650 | return count; |
4602 | } | 4651 | } |
4603 | 4652 | ||
4604 | void nfsd_forget_locks(u64 num) | 4653 | u64 nfsd_forget_client_locks(struct nfs4_client *clp, u64 max) |
4605 | { | 4654 | { |
4606 | int count; | 4655 | return nfsd_foreach_client_lock(clp, max, release_lockowner); |
4607 | 4656 | } | |
4608 | nfs4_lock_state(); | ||
4609 | count = nfsd_release_n_owners(num, false, release_lockowner_sop); | ||
4610 | nfs4_unlock_state(); | ||
4611 | 4657 | ||
4612 | printk(KERN_INFO "NFSD: Forgot %d locks", count); | 4658 | u64 nfsd_print_client_locks(struct nfs4_client *clp, u64 max) |
4659 | { | ||
4660 | u64 count = nfsd_foreach_client_lock(clp, max, NULL); | ||
4661 | nfsd_print_count(clp, count, "locked files"); | ||
4662 | return count; | ||
4613 | } | 4663 | } |
4614 | 4664 | ||
4615 | void nfsd_forget_openowners(u64 num) | 4665 | static u64 nfsd_foreach_client_open(struct nfs4_client *clp, u64 max, void (*func)(struct nfs4_openowner *)) |
4616 | { | 4666 | { |
4617 | int count; | 4667 | struct nfs4_openowner *oop, *next; |
4668 | u64 count = 0; | ||
4618 | 4669 | ||
4619 | nfs4_lock_state(); | 4670 | list_for_each_entry_safe(oop, next, &clp->cl_openowners, oo_perclient) { |
4620 | count = nfsd_release_n_owners(num, true, release_openowner_sop); | 4671 | if (func) |
4621 | nfs4_unlock_state(); | 4672 | func(oop); |
4673 | if (++count == max) | ||
4674 | break; | ||
4675 | } | ||
4622 | 4676 | ||
4623 | printk(KERN_INFO "NFSD: Forgot %d open owners", count); | 4677 | return count; |
4624 | } | 4678 | } |
4625 | 4679 | ||
4626 | static int nfsd_process_n_delegations(u64 num, struct list_head *list) | 4680 | u64 nfsd_forget_client_openowners(struct nfs4_client *clp, u64 max) |
4627 | { | 4681 | { |
4628 | int i, count = 0; | 4682 | return nfsd_foreach_client_open(clp, max, release_openowner); |
4629 | struct nfs4_file *fp, *fnext; | 4683 | } |
4630 | struct nfs4_delegation *dp, *dnext; | ||
4631 | 4684 | ||
4632 | for (i = 0; i < FILE_HASH_SIZE; i++) { | 4685 | u64 nfsd_print_client_openowners(struct nfs4_client *clp, u64 max) |
4633 | list_for_each_entry_safe(fp, fnext, &file_hashtbl[i], fi_hash) { | 4686 | { |
4634 | list_for_each_entry_safe(dp, dnext, &fp->fi_delegations, dl_perfile) { | 4687 | u64 count = nfsd_foreach_client_open(clp, max, NULL); |
4635 | list_move(&dp->dl_recall_lru, list); | 4688 | nfsd_print_count(clp, count, "open files"); |
4636 | if (++count == num) | 4689 | return count; |
4637 | return count; | 4690 | } |
4638 | } | 4691 | |
4639 | } | 4692 | static u64 nfsd_find_all_delegations(struct nfs4_client *clp, u64 max, |
4640 | } | 4693 | struct list_head *victims) |
4694 | { | ||
4695 | struct nfs4_delegation *dp, *next; | ||
4696 | u64 count = 0; | ||
4641 | 4697 | ||
4698 | list_for_each_entry_safe(dp, next, &clp->cl_delegations, dl_perclnt) { | ||
4699 | if (victims) | ||
4700 | list_move(&dp->dl_recall_lru, victims); | ||
4701 | if (++count == max) | ||
4702 | break; | ||
4703 | } | ||
4642 | return count; | 4704 | return count; |
4643 | } | 4705 | } |
4644 | 4706 | ||
4645 | void nfsd_forget_delegations(u64 num) | 4707 | u64 nfsd_forget_client_delegations(struct nfs4_client *clp, u64 max) |
4646 | { | 4708 | { |
4647 | unsigned int count; | 4709 | struct nfs4_delegation *dp, *next; |
4648 | LIST_HEAD(victims); | 4710 | LIST_HEAD(victims); |
4649 | struct nfs4_delegation *dp, *dnext; | 4711 | u64 count; |
4650 | 4712 | ||
4651 | spin_lock(&recall_lock); | 4713 | spin_lock(&recall_lock); |
4652 | count = nfsd_process_n_delegations(num, &victims); | 4714 | count = nfsd_find_all_delegations(clp, max, &victims); |
4653 | spin_unlock(&recall_lock); | 4715 | spin_unlock(&recall_lock); |
4654 | 4716 | ||
4655 | nfs4_lock_state(); | 4717 | list_for_each_entry_safe(dp, next, &victims, dl_recall_lru) |
4656 | list_for_each_entry_safe(dp, dnext, &victims, dl_recall_lru) | ||
4657 | unhash_delegation(dp); | 4718 | unhash_delegation(dp); |
4658 | nfs4_unlock_state(); | ||
4659 | 4719 | ||
4660 | printk(KERN_INFO "NFSD: Forgot %d delegations", count); | 4720 | return count; |
4661 | } | 4721 | } |
4662 | 4722 | ||
4663 | void nfsd_recall_delegations(u64 num) | 4723 | u64 nfsd_recall_client_delegations(struct nfs4_client *clp, u64 max) |
4664 | { | 4724 | { |
4665 | unsigned int count; | 4725 | struct nfs4_delegation *dp, *next; |
4666 | LIST_HEAD(victims); | 4726 | LIST_HEAD(victims); |
4667 | struct nfs4_delegation *dp, *dnext; | 4727 | u64 count; |
4668 | 4728 | ||
4669 | spin_lock(&recall_lock); | 4729 | spin_lock(&recall_lock); |
4670 | count = nfsd_process_n_delegations(num, &victims); | 4730 | count = nfsd_find_all_delegations(clp, max, &victims); |
4671 | list_for_each_entry_safe(dp, dnext, &victims, dl_recall_lru) { | 4731 | list_for_each_entry_safe(dp, next, &victims, dl_recall_lru) |
4672 | list_del(&dp->dl_recall_lru); | ||
4673 | nfsd_break_one_deleg(dp); | 4732 | nfsd_break_one_deleg(dp); |
4674 | } | ||
4675 | spin_unlock(&recall_lock); | 4733 | spin_unlock(&recall_lock); |
4676 | 4734 | ||
4677 | printk(KERN_INFO "NFSD: Recalled %d delegations", count); | 4735 | return count; |
4736 | } | ||
4737 | |||
4738 | u64 nfsd_print_client_delegations(struct nfs4_client *clp, u64 max) | ||
4739 | { | ||
4740 | u64 count = 0; | ||
4741 | |||
4742 | spin_lock(&recall_lock); | ||
4743 | count = nfsd_find_all_delegations(clp, max, NULL); | ||
4744 | spin_unlock(&recall_lock); | ||
4745 | |||
4746 | nfsd_print_count(clp, count, "delegations"); | ||
4747 | return count; | ||
4748 | } | ||
4749 | |||
4750 | u64 nfsd_for_n_state(u64 max, u64 (*func)(struct nfs4_client *, u64)) | ||
4751 | { | ||
4752 | struct nfs4_client *clp, *next; | ||
4753 | u64 count = 0; | ||
4754 | struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, nfsd_net_id); | ||
4755 | |||
4756 | if (!nfsd_netns_ready(nn)) | ||
4757 | return 0; | ||
4758 | |||
4759 | list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) { | ||
4760 | count += func(clp, max - count); | ||
4761 | if ((max != 0) && (count >= max)) | ||
4762 | break; | ||
4763 | } | ||
4764 | |||
4765 | return count; | ||
4766 | } | ||
4767 | |||
4768 | struct nfs4_client *nfsd_find_client(struct sockaddr_storage *addr, size_t addr_size) | ||
4769 | { | ||
4770 | struct nfs4_client *clp; | ||
4771 | struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, nfsd_net_id); | ||
4772 | |||
4773 | if (!nfsd_netns_ready(nn)) | ||
4774 | return NULL; | ||
4775 | |||
4776 | list_for_each_entry(clp, &nn->client_lru, cl_lru) { | ||
4777 | if (memcmp(&clp->cl_addr, addr, addr_size) == 0) | ||
4778 | return clp; | ||
4779 | } | ||
4780 | return NULL; | ||
4678 | } | 4781 | } |
4679 | 4782 | ||
4680 | #endif /* CONFIG_NFSD_FAULT_INJECTION */ | 4783 | #endif /* CONFIG_NFSD_FAULT_INJECTION */ |
@@ -4686,27 +4789,10 @@ nfs4_state_init(void) | |||
4686 | { | 4789 | { |
4687 | int i; | 4790 | int i; |
4688 | 4791 | ||
4689 | for (i = 0; i < CLIENT_HASH_SIZE; i++) { | ||
4690 | INIT_LIST_HEAD(&conf_id_hashtbl[i]); | ||
4691 | INIT_LIST_HEAD(&conf_str_hashtbl[i]); | ||
4692 | INIT_LIST_HEAD(&unconf_str_hashtbl[i]); | ||
4693 | INIT_LIST_HEAD(&unconf_id_hashtbl[i]); | ||
4694 | INIT_LIST_HEAD(&reclaim_str_hashtbl[i]); | ||
4695 | } | ||
4696 | for (i = 0; i < SESSION_HASH_SIZE; i++) | ||
4697 | INIT_LIST_HEAD(&sessionid_hashtbl[i]); | ||
4698 | for (i = 0; i < FILE_HASH_SIZE; i++) { | 4792 | for (i = 0; i < FILE_HASH_SIZE; i++) { |
4699 | INIT_LIST_HEAD(&file_hashtbl[i]); | 4793 | INIT_LIST_HEAD(&file_hashtbl[i]); |
4700 | } | 4794 | } |
4701 | for (i = 0; i < OWNER_HASH_SIZE; i++) { | ||
4702 | INIT_LIST_HEAD(&ownerstr_hashtbl[i]); | ||
4703 | } | ||
4704 | for (i = 0; i < LOCKOWNER_INO_HASH_SIZE; i++) | ||
4705 | INIT_LIST_HEAD(&lockowner_ino_hashtbl[i]); | ||
4706 | INIT_LIST_HEAD(&close_lru); | ||
4707 | INIT_LIST_HEAD(&client_lru); | ||
4708 | INIT_LIST_HEAD(&del_recall_lru); | 4795 | INIT_LIST_HEAD(&del_recall_lru); |
4709 | reclaim_str_hashtbl_size = 0; | ||
4710 | } | 4796 | } |
4711 | 4797 | ||
4712 | /* | 4798 | /* |
@@ -4730,12 +4816,100 @@ set_max_delegations(void) | |||
4730 | max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT); | 4816 | max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT); |
4731 | } | 4817 | } |
4732 | 4818 | ||
4733 | /* initialization to perform when the nfsd service is started: */ | 4819 | static int nfs4_state_create_net(struct net *net) |
4820 | { | ||
4821 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
4822 | int i; | ||
4823 | |||
4824 | nn->conf_id_hashtbl = kmalloc(sizeof(struct list_head) * | ||
4825 | CLIENT_HASH_SIZE, GFP_KERNEL); | ||
4826 | if (!nn->conf_id_hashtbl) | ||
4827 | goto err; | ||
4828 | nn->unconf_id_hashtbl = kmalloc(sizeof(struct list_head) * | ||
4829 | CLIENT_HASH_SIZE, GFP_KERNEL); | ||
4830 | if (!nn->unconf_id_hashtbl) | ||
4831 | goto err_unconf_id; | ||
4832 | nn->ownerstr_hashtbl = kmalloc(sizeof(struct list_head) * | ||
4833 | OWNER_HASH_SIZE, GFP_KERNEL); | ||
4834 | if (!nn->ownerstr_hashtbl) | ||
4835 | goto err_ownerstr; | ||
4836 | nn->lockowner_ino_hashtbl = kmalloc(sizeof(struct list_head) * | ||
4837 | LOCKOWNER_INO_HASH_SIZE, GFP_KERNEL); | ||
4838 | if (!nn->lockowner_ino_hashtbl) | ||
4839 | goto err_lockowner_ino; | ||
4840 | nn->sessionid_hashtbl = kmalloc(sizeof(struct list_head) * | ||
4841 | SESSION_HASH_SIZE, GFP_KERNEL); | ||
4842 | if (!nn->sessionid_hashtbl) | ||
4843 | goto err_sessionid; | ||
4844 | |||
4845 | for (i = 0; i < CLIENT_HASH_SIZE; i++) { | ||
4846 | INIT_LIST_HEAD(&nn->conf_id_hashtbl[i]); | ||
4847 | INIT_LIST_HEAD(&nn->unconf_id_hashtbl[i]); | ||
4848 | } | ||
4849 | for (i = 0; i < OWNER_HASH_SIZE; i++) | ||
4850 | INIT_LIST_HEAD(&nn->ownerstr_hashtbl[i]); | ||
4851 | for (i = 0; i < LOCKOWNER_INO_HASH_SIZE; i++) | ||
4852 | INIT_LIST_HEAD(&nn->lockowner_ino_hashtbl[i]); | ||
4853 | for (i = 0; i < SESSION_HASH_SIZE; i++) | ||
4854 | INIT_LIST_HEAD(&nn->sessionid_hashtbl[i]); | ||
4855 | nn->conf_name_tree = RB_ROOT; | ||
4856 | nn->unconf_name_tree = RB_ROOT; | ||
4857 | INIT_LIST_HEAD(&nn->client_lru); | ||
4858 | INIT_LIST_HEAD(&nn->close_lru); | ||
4859 | spin_lock_init(&nn->client_lock); | ||
4860 | |||
4861 | INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main); | ||
4862 | get_net(net); | ||
4863 | |||
4864 | return 0; | ||
4865 | |||
4866 | err_sessionid: | ||
4867 | kfree(nn->lockowner_ino_hashtbl); | ||
4868 | err_lockowner_ino: | ||
4869 | kfree(nn->ownerstr_hashtbl); | ||
4870 | err_ownerstr: | ||
4871 | kfree(nn->unconf_id_hashtbl); | ||
4872 | err_unconf_id: | ||
4873 | kfree(nn->conf_id_hashtbl); | ||
4874 | err: | ||
4875 | return -ENOMEM; | ||
4876 | } | ||
4877 | |||
4878 | static void | ||
4879 | nfs4_state_destroy_net(struct net *net) | ||
4880 | { | ||
4881 | int i; | ||
4882 | struct nfs4_client *clp = NULL; | ||
4883 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
4884 | struct rb_node *node, *tmp; | ||
4885 | |||
4886 | for (i = 0; i < CLIENT_HASH_SIZE; i++) { | ||
4887 | while (!list_empty(&nn->conf_id_hashtbl[i])) { | ||
4888 | clp = list_entry(nn->conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); | ||
4889 | destroy_client(clp); | ||
4890 | } | ||
4891 | } | ||
4892 | |||
4893 | node = rb_first(&nn->unconf_name_tree); | ||
4894 | while (node != NULL) { | ||
4895 | tmp = node; | ||
4896 | node = rb_next(tmp); | ||
4897 | clp = rb_entry(tmp, struct nfs4_client, cl_namenode); | ||
4898 | rb_erase(tmp, &nn->unconf_name_tree); | ||
4899 | destroy_client(clp); | ||
4900 | } | ||
4901 | |||
4902 | kfree(nn->sessionid_hashtbl); | ||
4903 | kfree(nn->lockowner_ino_hashtbl); | ||
4904 | kfree(nn->ownerstr_hashtbl); | ||
4905 | kfree(nn->unconf_id_hashtbl); | ||
4906 | kfree(nn->conf_id_hashtbl); | ||
4907 | put_net(net); | ||
4908 | } | ||
4734 | 4909 | ||
4735 | int | 4910 | int |
4736 | nfs4_state_start(void) | 4911 | nfs4_state_start_net(struct net *net) |
4737 | { | 4912 | { |
4738 | struct net *net = &init_net; | ||
4739 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | 4913 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
4740 | int ret; | 4914 | int ret; |
4741 | 4915 | ||
@@ -4746,18 +4920,32 @@ nfs4_state_start(void) | |||
4746 | * to that instead and then do most of the rest of this on a per-net | 4920 | * to that instead and then do most of the rest of this on a per-net |
4747 | * basis. | 4921 | * basis. |
4748 | */ | 4922 | */ |
4749 | get_net(net); | 4923 | if (net != &init_net) |
4924 | return -EINVAL; | ||
4925 | |||
4926 | ret = nfs4_state_create_net(net); | ||
4927 | if (ret) | ||
4928 | return ret; | ||
4750 | nfsd4_client_tracking_init(net); | 4929 | nfsd4_client_tracking_init(net); |
4751 | nn->boot_time = get_seconds(); | 4930 | nn->boot_time = get_seconds(); |
4752 | locks_start_grace(net, &nn->nfsd4_manager); | 4931 | locks_start_grace(net, &nn->nfsd4_manager); |
4753 | nn->grace_ended = false; | 4932 | nn->grace_ended = false; |
4754 | printk(KERN_INFO "NFSD: starting %ld-second grace period\n", | 4933 | printk(KERN_INFO "NFSD: starting %ld-second grace period (net %p)\n", |
4755 | nfsd4_grace); | 4934 | nn->nfsd4_grace, net); |
4935 | queue_delayed_work(laundry_wq, &nn->laundromat_work, nn->nfsd4_grace * HZ); | ||
4936 | return 0; | ||
4937 | } | ||
4938 | |||
4939 | /* initialization to perform when the nfsd service is started: */ | ||
4940 | |||
4941 | int | ||
4942 | nfs4_state_start(void) | ||
4943 | { | ||
4944 | int ret; | ||
4945 | |||
4756 | ret = set_callback_cred(); | 4946 | ret = set_callback_cred(); |
4757 | if (ret) { | 4947 | if (ret) |
4758 | ret = -ENOMEM; | 4948 | return -ENOMEM; |
4759 | goto out_recovery; | ||
4760 | } | ||
4761 | laundry_wq = create_singlethread_workqueue("nfsd4"); | 4949 | laundry_wq = create_singlethread_workqueue("nfsd4"); |
4762 | if (laundry_wq == NULL) { | 4950 | if (laundry_wq == NULL) { |
4763 | ret = -ENOMEM; | 4951 | ret = -ENOMEM; |
@@ -4766,39 +4954,34 @@ nfs4_state_start(void) | |||
4766 | ret = nfsd4_create_callback_queue(); | 4954 | ret = nfsd4_create_callback_queue(); |
4767 | if (ret) | 4955 | if (ret) |
4768 | goto out_free_laundry; | 4956 | goto out_free_laundry; |
4769 | queue_delayed_work(laundry_wq, &laundromat_work, nfsd4_grace * HZ); | 4957 | |
4770 | set_max_delegations(); | 4958 | set_max_delegations(); |
4959 | |||
4771 | return 0; | 4960 | return 0; |
4961 | |||
4772 | out_free_laundry: | 4962 | out_free_laundry: |
4773 | destroy_workqueue(laundry_wq); | 4963 | destroy_workqueue(laundry_wq); |
4774 | out_recovery: | 4964 | out_recovery: |
4775 | nfsd4_client_tracking_exit(net); | ||
4776 | put_net(net); | ||
4777 | return ret; | 4965 | return ret; |
4778 | } | 4966 | } |
4779 | 4967 | ||
4780 | static void | 4968 | /* should be called with the state lock held */ |
4781 | __nfs4_state_shutdown(void) | 4969 | void |
4970 | nfs4_state_shutdown_net(struct net *net) | ||
4782 | { | 4971 | { |
4783 | int i; | ||
4784 | struct nfs4_client *clp = NULL; | ||
4785 | struct nfs4_delegation *dp = NULL; | 4972 | struct nfs4_delegation *dp = NULL; |
4786 | struct list_head *pos, *next, reaplist; | 4973 | struct list_head *pos, *next, reaplist; |
4974 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
4975 | |||
4976 | cancel_delayed_work_sync(&nn->laundromat_work); | ||
4977 | locks_end_grace(&nn->nfsd4_manager); | ||
4787 | 4978 | ||
4788 | for (i = 0; i < CLIENT_HASH_SIZE; i++) { | ||
4789 | while (!list_empty(&conf_id_hashtbl[i])) { | ||
4790 | clp = list_entry(conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); | ||
4791 | destroy_client(clp); | ||
4792 | } | ||
4793 | while (!list_empty(&unconf_str_hashtbl[i])) { | ||
4794 | clp = list_entry(unconf_str_hashtbl[i].next, struct nfs4_client, cl_strhash); | ||
4795 | destroy_client(clp); | ||
4796 | } | ||
4797 | } | ||
4798 | INIT_LIST_HEAD(&reaplist); | 4979 | INIT_LIST_HEAD(&reaplist); |
4799 | spin_lock(&recall_lock); | 4980 | spin_lock(&recall_lock); |
4800 | list_for_each_safe(pos, next, &del_recall_lru) { | 4981 | list_for_each_safe(pos, next, &del_recall_lru) { |
4801 | dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); | 4982 | dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); |
4983 | if (dp->dl_stid.sc_client->net != net) | ||
4984 | continue; | ||
4802 | list_move(&dp->dl_recall_lru, &reaplist); | 4985 | list_move(&dp->dl_recall_lru, &reaplist); |
4803 | } | 4986 | } |
4804 | spin_unlock(&recall_lock); | 4987 | spin_unlock(&recall_lock); |
@@ -4807,22 +4990,14 @@ __nfs4_state_shutdown(void) | |||
4807 | unhash_delegation(dp); | 4990 | unhash_delegation(dp); |
4808 | } | 4991 | } |
4809 | 4992 | ||
4810 | nfsd4_client_tracking_exit(&init_net); | 4993 | nfsd4_client_tracking_exit(net); |
4811 | put_net(&init_net); | 4994 | nfs4_state_destroy_net(net); |
4812 | } | 4995 | } |
4813 | 4996 | ||
4814 | void | 4997 | void |
4815 | nfs4_state_shutdown(void) | 4998 | nfs4_state_shutdown(void) |
4816 | { | 4999 | { |
4817 | struct net *net = &init_net; | ||
4818 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
4819 | |||
4820 | cancel_delayed_work_sync(&laundromat_work); | ||
4821 | destroy_workqueue(laundry_wq); | 5000 | destroy_workqueue(laundry_wq); |
4822 | locks_end_grace(&nn->nfsd4_manager); | ||
4823 | nfs4_lock_state(); | ||
4824 | __nfs4_state_shutdown(); | ||
4825 | nfs4_unlock_state(); | ||
4826 | nfsd4_destroy_callback_queue(); | 5001 | nfsd4_destroy_callback_queue(); |
4827 | } | 5002 | } |
4828 | 5003 | ||