@@ -125,6 +125,8 @@ static void free_session(struct nfsd4_session *);
125125static const struct nfsd4_callback_ops nfsd4_cb_recall_ops ;
126126static const struct nfsd4_callback_ops nfsd4_cb_notify_lock_ops ;
127127
128+ static struct workqueue_struct * laundry_wq ;
129+
128130static bool is_session_dead (struct nfsd4_session * ses )
129131{
130132 return ses -> se_flags & NFS4_SESSION_DEAD ;
@@ -152,6 +154,7 @@ static __be32 get_client_locked(struct nfs4_client *clp)
152154 if (is_client_expired (clp ))
153155 return nfserr_expired ;
154156 atomic_inc (& clp -> cl_rpc_users );
157+ clp -> cl_state = NFSD4_ACTIVE ;
155158 return nfs_ok ;
156159}
157160
@@ -172,6 +175,7 @@ renew_client_locked(struct nfs4_client *clp)
172175
173176 list_move_tail (& clp -> cl_lru , & nn -> client_lru );
174177 clp -> cl_time = ktime_get_boottime_seconds ();
178+ clp -> cl_state = NFSD4_ACTIVE ;
175179}
176180
177181static void put_client_renew_locked (struct nfs4_client * clp )
@@ -1090,6 +1094,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_file *fp,
10901094 get_clnt_odstate (odstate );
10911095 dp -> dl_type = NFS4_OPEN_DELEGATE_READ ;
10921096 dp -> dl_retries = 1 ;
1097+ dp -> dl_recalled = false;
10931098 nfsd4_init_cb (& dp -> dl_recall , dp -> dl_stid .sc_client ,
10941099 & nfsd4_cb_recall_ops , NFSPROC4_CLNT_CB_RECALL );
10951100 get_nfs4_file (fp );
@@ -2004,6 +2009,8 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name)
20042009 idr_init (& clp -> cl_stateids );
20052010 atomic_set (& clp -> cl_rpc_users , 0 );
20062011 clp -> cl_cb_state = NFSD4_CB_UNKNOWN ;
2012+ clp -> cl_state = NFSD4_ACTIVE ;
2013+ atomic_set (& clp -> cl_delegs_in_recall , 0 );
20072014 INIT_LIST_HEAD (& clp -> cl_idhash );
20082015 INIT_LIST_HEAD (& clp -> cl_openowners );
20092016 INIT_LIST_HEAD (& clp -> cl_delegations );
@@ -4694,9 +4701,18 @@ nfsd_break_deleg_cb(struct file_lock *fl)
46944701 bool ret = false;
46954702 struct nfs4_delegation * dp = (struct nfs4_delegation * )fl -> fl_owner ;
46964703 struct nfs4_file * fp = dp -> dl_stid .sc_file ;
4704+ struct nfs4_client * clp = dp -> dl_stid .sc_client ;
4705+ struct nfsd_net * nn ;
46974706
46984707 trace_nfsd_cb_recall (& dp -> dl_stid );
46994708
4709+ dp -> dl_recalled = true;
4710+ atomic_inc (& clp -> cl_delegs_in_recall );
4711+ if (try_to_expire_client (clp )) {
4712+ nn = net_generic (clp -> net , nfsd_net_id );
4713+ mod_delayed_work (laundry_wq , & nn -> laundromat_work , 0 );
4714+ }
4715+
47004716 /*
47014717 * We don't want the locks code to timeout the lease for us;
47024718 * we'll remove it ourself if a delegation isn't returned
@@ -4739,9 +4755,14 @@ static int
47394755nfsd_change_deleg_cb (struct file_lock * onlist , int arg ,
47404756 struct list_head * dispose )
47414757{
4742- if (arg & F_UNLCK )
4758+ struct nfs4_delegation * dp = (struct nfs4_delegation * )onlist -> fl_owner ;
4759+ struct nfs4_client * clp = dp -> dl_stid .sc_client ;
4760+
4761+ if (arg & F_UNLCK ) {
4762+ if (dp -> dl_recalled )
4763+ atomic_dec (& clp -> cl_delegs_in_recall );
47434764 return lease_modify (onlist , arg , dispose );
4744- else
4765+ } else
47454766 return - EAGAIN ;
47464767}
47474768
@@ -5605,6 +5626,49 @@ static void nfsd4_ssc_expire_umount(struct nfsd_net *nn)
56055626}
56065627#endif
56075628
5629+ /*
5630+ * place holder for now, no check for lock blockers yet
5631+ */
5632+ static bool
5633+ nfs4_anylock_blockers (struct nfs4_client * clp )
5634+ {
5635+ if (atomic_read (& clp -> cl_delegs_in_recall ) ||
5636+ client_has_openowners (clp ) ||
5637+ !list_empty (& clp -> async_copies ))
5638+ return true;
5639+ return false;
5640+ }
5641+
5642+ static void
5643+ nfs4_get_client_reaplist (struct nfsd_net * nn , struct list_head * reaplist ,
5644+ struct laundry_time * lt )
5645+ {
5646+ struct list_head * pos , * next ;
5647+ struct nfs4_client * clp ;
5648+
5649+ INIT_LIST_HEAD (reaplist );
5650+ spin_lock (& nn -> client_lock );
5651+ list_for_each_safe (pos , next , & nn -> client_lru ) {
5652+ clp = list_entry (pos , struct nfs4_client , cl_lru );
5653+ if (clp -> cl_state == NFSD4_EXPIRABLE )
5654+ goto exp_client ;
5655+ if (!state_expired (lt , clp -> cl_time ))
5656+ break ;
5657+ if (!atomic_read (& clp -> cl_rpc_users ))
5658+ clp -> cl_state = NFSD4_COURTESY ;
5659+ if (!client_has_state (clp ) ||
5660+ ktime_get_boottime_seconds () >=
5661+ (clp -> cl_time + NFSD_COURTESY_CLIENT_TIMEOUT ))
5662+ goto exp_client ;
5663+ if (nfs4_anylock_blockers (clp )) {
5664+ exp_client :
5665+ if (!mark_client_expired_locked (clp ))
5666+ list_add (& clp -> cl_lru , reaplist );
5667+ }
5668+ }
5669+ spin_unlock (& nn -> client_lock );
5670+ }
5671+
56085672static time64_t
56095673nfs4_laundromat (struct nfsd_net * nn )
56105674{
@@ -5627,7 +5691,6 @@ nfs4_laundromat(struct nfsd_net *nn)
56275691 goto out ;
56285692 }
56295693 nfsd4_end_grace (nn );
5630- INIT_LIST_HEAD (& reaplist );
56315694
56325695 spin_lock (& nn -> s2s_cp_lock );
56335696 idr_for_each_entry (& nn -> s2s_cp_stateids , cps_t , i ) {
@@ -5637,17 +5700,7 @@ nfs4_laundromat(struct nfsd_net *nn)
56375700 _free_cpntf_state_locked (nn , cps );
56385701 }
56395702 spin_unlock (& nn -> s2s_cp_lock );
5640-
5641- spin_lock (& nn -> client_lock );
5642- list_for_each_safe (pos , next , & nn -> client_lru ) {
5643- clp = list_entry (pos , struct nfs4_client , cl_lru );
5644- if (!state_expired (& lt , clp -> cl_time ))
5645- break ;
5646- if (mark_client_expired_locked (clp ))
5647- continue ;
5648- list_add (& clp -> cl_lru , & reaplist );
5649- }
5650- spin_unlock (& nn -> client_lock );
5703+ nfs4_get_client_reaplist (nn , & reaplist , & lt );
56515704 list_for_each_safe (pos , next , & reaplist ) {
56525705 clp = list_entry (pos , struct nfs4_client , cl_lru );
56535706 trace_nfsd_clid_purged (& clp -> cl_clientid );
@@ -5722,7 +5775,6 @@ nfs4_laundromat(struct nfsd_net *nn)
57225775 return max_t (time64_t , lt .new_timeo , NFSD_LAUNDROMAT_MINTIMEOUT );
57235776}
57245777
5725- static struct workqueue_struct * laundry_wq ;
57265778static void laundromat_main (struct work_struct * );
57275779
57285780static void
0 commit comments