3636 * second map contains a reference to the entry in the first map.
3737 */
3838
39+ static struct workqueue_struct * nfsd_export_wq ;
40+
3941#define EXPKEY_HASHBITS 8
4042#define EXPKEY_HASHMAX (1 << EXPKEY_HASHBITS)
4143#define EXPKEY_HASHMASK (EXPKEY_HASHMAX -1)
4244
43- static void expkey_put (struct kref * ref )
45+ static void expkey_release (struct work_struct * work )
4446{
45- struct svc_expkey * key = container_of (ref , struct svc_expkey , h .ref );
47+ struct svc_expkey * key = container_of (to_rcu_work (work ),
48+ struct svc_expkey , ek_rwork );
4649
4750 if (test_bit (CACHE_VALID , & key -> h .flags ) &&
4851 !test_bit (CACHE_NEGATIVE , & key -> h .flags ))
4952 path_put (& key -> ek_path );
5053 auth_domain_put (key -> ek_client );
51- kfree_rcu (key , ek_rcu );
54+ kfree (key );
55+ }
56+
57+ static void expkey_put (struct kref * ref )
58+ {
59+ struct svc_expkey * key = container_of (ref , struct svc_expkey , h .ref );
60+
61+ INIT_RCU_WORK (& key -> ek_rwork , expkey_release );
62+ queue_rcu_work (nfsd_export_wq , & key -> ek_rwork );
5263}
5364
5465static int expkey_upcall (struct cache_detail * cd , struct cache_head * h )
@@ -353,11 +364,13 @@ static void export_stats_destroy(struct export_stats *stats)
353364 EXP_STATS_COUNTERS_NUM );
354365}
355366
356- static void svc_export_release (struct rcu_head * rcu_head )
367+ static void svc_export_release (struct work_struct * work )
357368{
358- struct svc_export * exp = container_of (rcu_head , struct svc_export ,
359- ex_rcu );
369+ struct svc_export * exp = container_of (to_rcu_work ( work ) ,
370+ struct svc_export , ex_rwork );
360371
372+ path_put (& exp -> ex_path );
373+ auth_domain_put (exp -> ex_client );
361374 nfsd4_fslocs_free (& exp -> ex_fslocs );
362375 export_stats_destroy (exp -> ex_stats );
363376 kfree (exp -> ex_stats );
@@ -369,9 +382,8 @@ static void svc_export_put(struct kref *ref)
369382{
370383 struct svc_export * exp = container_of (ref , struct svc_export , h .ref );
371384
372- path_put (& exp -> ex_path );
373- auth_domain_put (exp -> ex_client );
374- call_rcu (& exp -> ex_rcu , svc_export_release );
385+ INIT_RCU_WORK (& exp -> ex_rwork , svc_export_release );
386+ queue_rcu_work (nfsd_export_wq , & exp -> ex_rwork );
375387}
376388
377389static int svc_export_upcall (struct cache_detail * cd , struct cache_head * h )
@@ -1479,6 +1491,36 @@ const struct seq_operations nfs_exports_op = {
14791491 .show = e_show ,
14801492};
14811493
1494+ /**
1495+ * nfsd_export_wq_init - allocate the export release workqueue
1496+ *
1497+ * Called once at module load. The workqueue runs deferred svc_export and
1498+ * svc_expkey release work scheduled by queue_rcu_work() in the cache put
1499+ * callbacks.
1500+ *
1501+ * Return values:
1502+ * %0: workqueue allocated
1503+ * %-ENOMEM: allocation failed
1504+ */
1505+ int nfsd_export_wq_init (void )
1506+ {
1507+ nfsd_export_wq = alloc_workqueue ("nfsd_export" , WQ_UNBOUND , 0 );
1508+ if (!nfsd_export_wq )
1509+ return - ENOMEM ;
1510+ return 0 ;
1511+ }
1512+
1513+ /**
1514+ * nfsd_export_wq_shutdown - drain and free the export release workqueue
1515+ *
1516+ * Called once at module unload. Per-namespace teardown in
1517+ * nfsd_export_shutdown() has already drained all deferred work.
1518+ */
1519+ void nfsd_export_wq_shutdown (void )
1520+ {
1521+ destroy_workqueue (nfsd_export_wq );
1522+ }
1523+
14821524/*
14831525 * Initialize the exports module.
14841526 */
@@ -1540,6 +1582,9 @@ nfsd_export_shutdown(struct net *net)
15401582
15411583 cache_unregister_net (nn -> svc_expkey_cache , net );
15421584 cache_unregister_net (nn -> svc_export_cache , net );
1585+ /* Drain deferred export and expkey release work. */
1586+ rcu_barrier ();
1587+ flush_workqueue (nfsd_export_wq );
15431588 cache_destroy_net (nn -> svc_expkey_cache , net );
15441589 cache_destroy_net (nn -> svc_export_cache , net );
15451590 svcauth_unix_purge (net );
0 commit comments