@@ -578,35 +578,45 @@ __nf_tables_chain_type_lookup(const struct nlattr *nla, u8 family)
578
578
return NULL ;
579
579
}
580
580
581
- /*
582
- * Loading a module requires dropping mutex that guards the transaction.
583
- * A different client might race to start a new transaction meanwhile. Zap the
584
- * list of pending transaction and then restore it once the mutex is grabbed
585
- * again. Users of this function return EAGAIN which implicitly triggers the
586
- * transaction abort path to clean up the list of pending transactions.
587
- */
581
+ struct nft_module_request {
582
+ struct list_head list ;
583
+ char module [MODULE_NAME_LEN ];
584
+ bool done ;
585
+ };
586
+
588
587
#ifdef CONFIG_MODULES
589
- static void nft_request_module (struct net * net , const char * fmt , ...)
588
+ static int nft_request_module (struct net * net , const char * fmt , ...)
590
589
{
591
590
char module_name [MODULE_NAME_LEN ];
592
- LIST_HEAD ( commit_list ) ;
591
+ struct nft_module_request * req ;
593
592
va_list args ;
594
593
int ret ;
595
594
596
- list_splice_init (& net -> nft .commit_list , & commit_list );
597
-
598
595
va_start (args , fmt );
599
596
ret = vsnprintf (module_name , MODULE_NAME_LEN , fmt , args );
600
597
va_end (args );
601
598
if (ret >= MODULE_NAME_LEN )
602
- return ;
599
+ return 0 ;
603
600
604
- mutex_unlock (& net -> nft .commit_mutex );
605
- request_module ("%s" , module_name );
606
- mutex_lock (& net -> nft .commit_mutex );
601
+ list_for_each_entry (req , & net -> nft .module_list , list ) {
602
+ if (!strcmp (req -> module , module_name )) {
603
+ if (req -> done )
604
+ return 0 ;
607
605
608
- WARN_ON_ONCE (!list_empty (& net -> nft .commit_list ));
609
- list_splice (& commit_list , & net -> nft .commit_list );
606
+ /* A request to load this module already exists. */
607
+ return - EAGAIN ;
608
+ }
609
+ }
610
+
611
+ req = kmalloc (sizeof (* req ), GFP_KERNEL );
612
+ if (!req )
613
+ return - ENOMEM ;
614
+
615
+ req -> done = false;
616
+ strlcpy (req -> module , module_name , MODULE_NAME_LEN );
617
+ list_add_tail (& req -> list , & net -> nft .module_list );
618
+
619
+ return - EAGAIN ;
610
620
}
611
621
#endif
612
622
@@ -630,10 +640,9 @@ nf_tables_chain_type_lookup(struct net *net, const struct nlattr *nla,
630
640
lockdep_nfnl_nft_mutex_not_held ();
631
641
#ifdef CONFIG_MODULES
632
642
if (autoload ) {
633
- nft_request_module (net , "nft-chain-%u-%.*s" , family ,
634
- nla_len (nla ), (const char * )nla_data (nla ));
635
- type = __nf_tables_chain_type_lookup (nla , family );
636
- if (type != NULL )
643
+ if (nft_request_module (net , "nft-chain-%u-%.*s" , family ,
644
+ nla_len (nla ),
645
+ (const char * )nla_data (nla )) == - EAGAIN )
637
646
return ERR_PTR (- EAGAIN );
638
647
}
639
648
#endif
@@ -2341,9 +2350,8 @@ static const struct nft_expr_type *__nft_expr_type_get(u8 family,
2341
2350
static int nft_expr_type_request_module (struct net * net , u8 family ,
2342
2351
struct nlattr * nla )
2343
2352
{
2344
- nft_request_module (net , "nft-expr-%u-%.*s" , family ,
2345
- nla_len (nla ), (char * )nla_data (nla ));
2346
- if (__nft_expr_type_get (family , nla ))
2353
+ if (nft_request_module (net , "nft-expr-%u-%.*s" , family ,
2354
+ nla_len (nla ), (char * )nla_data (nla )) == - EAGAIN )
2347
2355
return - EAGAIN ;
2348
2356
2349
2357
return 0 ;
@@ -2369,9 +2377,9 @@ static const struct nft_expr_type *nft_expr_type_get(struct net *net,
2369
2377
if (nft_expr_type_request_module (net , family , nla ) == - EAGAIN )
2370
2378
return ERR_PTR (- EAGAIN );
2371
2379
2372
- nft_request_module (net , "nft-expr-%.*s" ,
2373
- nla_len ( nla ), ( char * ) nla_data (nla ));
2374
- if ( __nft_expr_type_get ( family , nla ))
2380
+ if ( nft_request_module (net , "nft-expr-%.*s" ,
2381
+ nla_len (nla ),
2382
+ ( char * ) nla_data ( nla )) == - EAGAIN )
2375
2383
return ERR_PTR (- EAGAIN );
2376
2384
}
2377
2385
#endif
@@ -2462,9 +2470,10 @@ static int nf_tables_expr_parse(const struct nft_ctx *ctx,
2462
2470
err = PTR_ERR (ops );
2463
2471
#ifdef CONFIG_MODULES
2464
2472
if (err == - EAGAIN )
2465
- nft_expr_type_request_module (ctx -> net ,
2466
- ctx -> family ,
2467
- tb [NFTA_EXPR_NAME ]);
2473
+ if (nft_expr_type_request_module (ctx -> net ,
2474
+ ctx -> family ,
2475
+ tb [NFTA_EXPR_NAME ]) != - EAGAIN )
2476
+ err = - ENOENT ;
2468
2477
#endif
2469
2478
goto err1 ;
2470
2479
}
@@ -3301,8 +3310,7 @@ nft_select_set_ops(const struct nft_ctx *ctx,
3301
3310
lockdep_nfnl_nft_mutex_not_held ();
3302
3311
#ifdef CONFIG_MODULES
3303
3312
if (list_empty (& nf_tables_set_types )) {
3304
- nft_request_module (ctx -> net , "nft-set" );
3305
- if (!list_empty (& nf_tables_set_types ))
3313
+ if (nft_request_module (ctx -> net , "nft-set" ) == - EAGAIN )
3306
3314
return ERR_PTR (- EAGAIN );
3307
3315
}
3308
3316
#endif
@@ -5428,8 +5436,7 @@ nft_obj_type_get(struct net *net, u32 objtype)
5428
5436
lockdep_nfnl_nft_mutex_not_held ();
5429
5437
#ifdef CONFIG_MODULES
5430
5438
if (type == NULL ) {
5431
- nft_request_module (net , "nft-obj-%u" , objtype );
5432
- if (__nft_obj_type_get (objtype ))
5439
+ if (nft_request_module (net , "nft-obj-%u" , objtype ) == - EAGAIN )
5433
5440
return ERR_PTR (- EAGAIN );
5434
5441
}
5435
5442
#endif
@@ -6002,8 +6009,7 @@ nft_flowtable_type_get(struct net *net, u8 family)
6002
6009
lockdep_nfnl_nft_mutex_not_held ();
6003
6010
#ifdef CONFIG_MODULES
6004
6011
if (type == NULL ) {
6005
- nft_request_module (net , "nf-flowtable-%u" , family );
6006
- if (__nft_flowtable_type_get (family ))
6012
+ if (nft_request_module (net , "nf-flowtable-%u" , family ) == - EAGAIN )
6007
6013
return ERR_PTR (- EAGAIN );
6008
6014
}
6009
6015
#endif
@@ -7005,6 +7011,18 @@ static void nft_chain_del(struct nft_chain *chain)
7005
7011
list_del_rcu (& chain -> list );
7006
7012
}
7007
7013
7014
+ static void nf_tables_module_autoload_cleanup (struct net * net )
7015
+ {
7016
+ struct nft_module_request * req , * next ;
7017
+
7018
+ WARN_ON_ONCE (!list_empty (& net -> nft .commit_list ));
7019
+ list_for_each_entry_safe (req , next , & net -> nft .module_list , list ) {
7020
+ WARN_ON_ONCE (!req -> done );
7021
+ list_del (& req -> list );
7022
+ kfree (req );
7023
+ }
7024
+ }
7025
+
7008
7026
static void nf_tables_commit_release (struct net * net )
7009
7027
{
7010
7028
struct nft_trans * trans ;
@@ -7017,6 +7035,7 @@ static void nf_tables_commit_release(struct net *net)
7017
7035
* to prevent expensive synchronize_rcu() in commit phase.
7018
7036
*/
7019
7037
if (list_empty (& net -> nft .commit_list )) {
7038
+ nf_tables_module_autoload_cleanup (net );
7020
7039
mutex_unlock (& net -> nft .commit_mutex );
7021
7040
return ;
7022
7041
}
@@ -7031,6 +7050,7 @@ static void nf_tables_commit_release(struct net *net)
7031
7050
list_splice_tail_init (& net -> nft .commit_list , & nf_tables_destroy_list );
7032
7051
spin_unlock (& nf_tables_destroy_list_lock );
7033
7052
7053
+ nf_tables_module_autoload_cleanup (net );
7034
7054
mutex_unlock (& net -> nft .commit_mutex );
7035
7055
7036
7056
schedule_work (& trans_destroy_work );
@@ -7222,6 +7242,26 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
7222
7242
return 0 ;
7223
7243
}
7224
7244
7245
+ static void nf_tables_module_autoload (struct net * net )
7246
+ {
7247
+ struct nft_module_request * req , * next ;
7248
+ LIST_HEAD (module_list );
7249
+
7250
+ list_splice_init (& net -> nft .module_list , & module_list );
7251
+ mutex_unlock (& net -> nft .commit_mutex );
7252
+ list_for_each_entry_safe (req , next , & module_list , list ) {
7253
+ if (req -> done ) {
7254
+ list_del (& req -> list );
7255
+ kfree (req );
7256
+ } else {
7257
+ request_module ("%s" , req -> module );
7258
+ req -> done = true;
7259
+ }
7260
+ }
7261
+ mutex_lock (& net -> nft .commit_mutex );
7262
+ list_splice (& module_list , & net -> nft .module_list );
7263
+ }
7264
+
7225
7265
static void nf_tables_abort_release (struct nft_trans * trans )
7226
7266
{
7227
7267
switch (trans -> msg_type ) {
@@ -7251,7 +7291,7 @@ static void nf_tables_abort_release(struct nft_trans *trans)
7251
7291
kfree (trans );
7252
7292
}
7253
7293
7254
- static int __nf_tables_abort (struct net * net )
7294
+ static int __nf_tables_abort (struct net * net , bool autoload )
7255
7295
{
7256
7296
struct nft_trans * trans , * next ;
7257
7297
struct nft_trans_elem * te ;
@@ -7373,6 +7413,11 @@ static int __nf_tables_abort(struct net *net)
7373
7413
nf_tables_abort_release (trans );
7374
7414
}
7375
7415
7416
+ if (autoload )
7417
+ nf_tables_module_autoload (net );
7418
+ else
7419
+ nf_tables_module_autoload_cleanup (net );
7420
+
7376
7421
return 0 ;
7377
7422
}
7378
7423
@@ -7381,9 +7426,9 @@ static void nf_tables_cleanup(struct net *net)
7381
7426
nft_validate_state_update (net , NFT_VALIDATE_SKIP );
7382
7427
}
7383
7428
7384
- static int nf_tables_abort (struct net * net , struct sk_buff * skb )
7429
+ static int nf_tables_abort (struct net * net , struct sk_buff * skb , bool autoload )
7385
7430
{
7386
- int ret = __nf_tables_abort (net );
7431
+ int ret = __nf_tables_abort (net , autoload );
7387
7432
7388
7433
mutex_unlock (& net -> nft .commit_mutex );
7389
7434
@@ -7978,6 +8023,7 @@ static int __net_init nf_tables_init_net(struct net *net)
7978
8023
{
7979
8024
INIT_LIST_HEAD (& net -> nft .tables );
7980
8025
INIT_LIST_HEAD (& net -> nft .commit_list );
8026
+ INIT_LIST_HEAD (& net -> nft .module_list );
7981
8027
mutex_init (& net -> nft .commit_mutex );
7982
8028
net -> nft .base_seq = 1 ;
7983
8029
net -> nft .validate_state = NFT_VALIDATE_SKIP ;
@@ -7989,7 +8035,7 @@ static void __net_exit nf_tables_exit_net(struct net *net)
7989
8035
{
7990
8036
mutex_lock (& net -> nft .commit_mutex );
7991
8037
if (!list_empty (& net -> nft .commit_list ))
7992
- __nf_tables_abort (net );
8038
+ __nf_tables_abort (net , false );
7993
8039
__nft_release_tables (net );
7994
8040
mutex_unlock (& net -> nft .commit_mutex );
7995
8041
WARN_ON_ONCE (!list_empty (& net -> nft .tables ));
0 commit comments