29
29
#include <linux/socket.h>
30
30
#include <linux/sockios.h>
31
31
#include <linux/jiffies.h>
32
- #include <linux/times.h>
33
32
#include <linux/net.h>
34
33
#include <linux/in.h>
35
34
#include <linux/in6.h>
42
41
#include <linux/slab.h>
43
42
#include <linux/pkt_sched.h>
44
43
#include <net/mld.h>
44
+ #include <linux/workqueue.h>
45
45
46
46
#include <linux/netfilter.h>
47
47
#include <linux/netfilter_ipv6.h>
@@ -67,14 +67,13 @@ static int __mld2_query_bugs[] __attribute__((__unused__)) = {
67
67
BUILD_BUG_ON_ZERO (offsetof(struct mld2_grec , grec_mca ) % 4 )
68
68
};
69
69
70
+ static struct workqueue_struct * mld_wq ;
70
71
static struct in6_addr mld2_all_mcr = MLD2_ALL_MCR_INIT ;
71
72
72
73
static void igmp6_join_group (struct ifmcaddr6 * ma );
73
74
static void igmp6_leave_group (struct ifmcaddr6 * ma );
74
- static void igmp6_timer_handler (struct timer_list * t );
75
+ static void mld_mca_work (struct work_struct * work );
75
76
76
- static void mld_gq_timer_expire (struct timer_list * t );
77
- static void mld_ifc_timer_expire (struct timer_list * t );
78
77
static void mld_ifc_event (struct inet6_dev * idev );
79
78
static void mld_add_delrec (struct inet6_dev * idev , struct ifmcaddr6 * pmc );
80
79
static void mld_del_delrec (struct inet6_dev * idev , struct ifmcaddr6 * pmc );
@@ -713,7 +712,7 @@ static void igmp6_group_dropped(struct ifmcaddr6 *mc)
713
712
igmp6_leave_group (mc );
714
713
715
714
spin_lock_bh (& mc -> mca_lock );
716
- if (del_timer (& mc -> mca_timer ))
715
+ if (cancel_delayed_work (& mc -> mca_work ))
717
716
refcount_dec (& mc -> mca_refcnt );
718
717
spin_unlock_bh (& mc -> mca_lock );
719
718
}
@@ -854,7 +853,7 @@ static struct ifmcaddr6 *mca_alloc(struct inet6_dev *idev,
854
853
if (!mc )
855
854
return NULL ;
856
855
857
- timer_setup (& mc -> mca_timer , igmp6_timer_handler , 0 );
856
+ INIT_DELAYED_WORK (& mc -> mca_work , mld_mca_work );
858
857
859
858
mc -> mca_addr = * addr ;
860
859
mc -> idev = idev ; /* reference taken by caller */
@@ -1027,48 +1026,48 @@ bool ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group,
1027
1026
return rv ;
1028
1027
}
1029
1028
1030
- static void mld_gq_start_timer (struct inet6_dev * idev )
1029
+ static void mld_gq_start_work (struct inet6_dev * idev )
1031
1030
{
1032
1031
unsigned long tv = prandom_u32 () % idev -> mc_maxdelay ;
1033
1032
1034
1033
idev -> mc_gq_running = 1 ;
1035
- if (!mod_timer ( & idev -> mc_gq_timer , jiffies + tv + 2 ))
1034
+ if (!mod_delayed_work ( mld_wq , & idev -> mc_gq_work , tv + 2 ))
1036
1035
in6_dev_hold (idev );
1037
1036
}
1038
1037
1039
- static void mld_gq_stop_timer (struct inet6_dev * idev )
1038
+ static void mld_gq_stop_work (struct inet6_dev * idev )
1040
1039
{
1041
1040
idev -> mc_gq_running = 0 ;
1042
- if (del_timer (& idev -> mc_gq_timer ))
1041
+ if (cancel_delayed_work (& idev -> mc_gq_work ))
1043
1042
__in6_dev_put (idev );
1044
1043
}
1045
1044
1046
- static void mld_ifc_start_timer (struct inet6_dev * idev , unsigned long delay )
1045
+ static void mld_ifc_start_work (struct inet6_dev * idev , unsigned long delay )
1047
1046
{
1048
1047
unsigned long tv = prandom_u32 () % delay ;
1049
1048
1050
- if (!mod_timer ( & idev -> mc_ifc_timer , jiffies + tv + 2 ))
1049
+ if (!mod_delayed_work ( mld_wq , & idev -> mc_ifc_work , tv + 2 ))
1051
1050
in6_dev_hold (idev );
1052
1051
}
1053
1052
1054
- static void mld_ifc_stop_timer (struct inet6_dev * idev )
1053
+ static void mld_ifc_stop_work (struct inet6_dev * idev )
1055
1054
{
1056
1055
idev -> mc_ifc_count = 0 ;
1057
- if (del_timer (& idev -> mc_ifc_timer ))
1056
+ if (cancel_delayed_work (& idev -> mc_ifc_work ))
1058
1057
__in6_dev_put (idev );
1059
1058
}
1060
1059
1061
- static void mld_dad_start_timer (struct inet6_dev * idev , unsigned long delay )
1060
+ static void mld_dad_start_work (struct inet6_dev * idev , unsigned long delay )
1062
1061
{
1063
1062
unsigned long tv = prandom_u32 () % delay ;
1064
1063
1065
- if (!mod_timer ( & idev -> mc_dad_timer , jiffies + tv + 2 ))
1064
+ if (!mod_delayed_work ( mld_wq , & idev -> mc_dad_work , tv + 2 ))
1066
1065
in6_dev_hold (idev );
1067
1066
}
1068
1067
1069
- static void mld_dad_stop_timer (struct inet6_dev * idev )
1068
+ static void mld_dad_stop_work (struct inet6_dev * idev )
1070
1069
{
1071
- if (del_timer (& idev -> mc_dad_timer ))
1070
+ if (cancel_delayed_work (& idev -> mc_dad_work ))
1072
1071
__in6_dev_put (idev );
1073
1072
}
1074
1073
@@ -1080,21 +1079,20 @@ static void igmp6_group_queried(struct ifmcaddr6 *ma, unsigned long resptime)
1080
1079
{
1081
1080
unsigned long delay = resptime ;
1082
1081
1083
- /* Do not start timer for these addresses */
1082
+ /* Do not start work for these addresses */
1084
1083
if (ipv6_addr_is_ll_all_nodes (& ma -> mca_addr ) ||
1085
1084
IPV6_ADDR_MC_SCOPE (& ma -> mca_addr ) < IPV6_ADDR_SCOPE_LINKLOCAL )
1086
1085
return ;
1087
1086
1088
- if (del_timer (& ma -> mca_timer )) {
1087
+ if (cancel_delayed_work (& ma -> mca_work )) {
1089
1088
refcount_dec (& ma -> mca_refcnt );
1090
- delay = ma -> mca_timer .expires - jiffies ;
1089
+ delay = ma -> mca_work . timer .expires - jiffies ;
1091
1090
}
1092
1091
1093
1092
if (delay >= resptime )
1094
1093
delay = prandom_u32 () % resptime ;
1095
1094
1096
- ma -> mca_timer .expires = jiffies + delay ;
1097
- if (!mod_timer (& ma -> mca_timer , jiffies + delay ))
1095
+ if (!mod_delayed_work (mld_wq , & ma -> mca_work , delay ))
1098
1096
refcount_inc (& ma -> mca_refcnt );
1099
1097
ma -> mca_flags |= MAF_TIMER_RUNNING ;
1100
1098
}
@@ -1305,10 +1303,10 @@ static int mld_process_v1(struct inet6_dev *idev, struct mld_msg *mld,
1305
1303
if (v1_query )
1306
1304
mld_set_v1_mode (idev );
1307
1305
1308
- /* cancel MLDv2 report timer */
1309
- mld_gq_stop_timer (idev );
1310
- /* cancel the interface change timer */
1311
- mld_ifc_stop_timer (idev );
1306
+ /* cancel MLDv2 report work */
1307
+ mld_gq_stop_work (idev );
1308
+ /* cancel the interface change work */
1309
+ mld_ifc_stop_work (idev );
1312
1310
/* clear deleted report items */
1313
1311
mld_clear_delrec (idev );
1314
1312
@@ -1398,7 +1396,7 @@ int igmp6_event_query(struct sk_buff *skb)
1398
1396
if (mlh2 -> mld2q_nsrcs )
1399
1397
return - EINVAL ; /* no sources allowed */
1400
1398
1401
- mld_gq_start_timer (idev );
1399
+ mld_gq_start_work (idev );
1402
1400
return 0 ;
1403
1401
}
1404
1402
/* mark sources to include, if group & source-specific */
@@ -1482,14 +1480,14 @@ int igmp6_event_report(struct sk_buff *skb)
1482
1480
return - ENODEV ;
1483
1481
1484
1482
/*
1485
- * Cancel the timer for this group
1483
+ * Cancel the work for this group
1486
1484
*/
1487
1485
1488
1486
read_lock_bh (& idev -> lock );
1489
1487
for (ma = idev -> mc_list ; ma ; ma = ma -> next ) {
1490
1488
if (ipv6_addr_equal (& ma -> mca_addr , & mld -> mld_mca )) {
1491
1489
spin_lock (& ma -> mca_lock );
1492
- if (del_timer (& ma -> mca_timer ))
1490
+ if (cancel_delayed_work (& ma -> mca_work ))
1493
1491
refcount_dec (& ma -> mca_refcnt );
1494
1492
ma -> mca_flags &= ~(MAF_LAST_REPORTER |MAF_TIMER_RUNNING );
1495
1493
spin_unlock (& ma -> mca_lock );
@@ -2103,21 +2101,23 @@ void ipv6_mc_dad_complete(struct inet6_dev *idev)
2103
2101
mld_send_initial_cr (idev );
2104
2102
idev -> mc_dad_count -- ;
2105
2103
if (idev -> mc_dad_count )
2106
- mld_dad_start_timer (idev ,
2107
- unsolicited_report_interval (idev ));
2104
+ mld_dad_start_work (idev ,
2105
+ unsolicited_report_interval (idev ));
2108
2106
}
2109
2107
}
2110
2108
2111
- static void mld_dad_timer_expire (struct timer_list * t )
2109
+ static void mld_dad_work (struct work_struct * work )
2112
2110
{
2113
- struct inet6_dev * idev = from_timer (idev , t , mc_dad_timer );
2111
+ struct inet6_dev * idev = container_of (to_delayed_work (work ),
2112
+ struct inet6_dev ,
2113
+ mc_dad_work );
2114
2114
2115
2115
mld_send_initial_cr (idev );
2116
2116
if (idev -> mc_dad_count ) {
2117
2117
idev -> mc_dad_count -- ;
2118
2118
if (idev -> mc_dad_count )
2119
- mld_dad_start_timer (idev ,
2120
- unsolicited_report_interval (idev ));
2119
+ mld_dad_start_work (idev ,
2120
+ unsolicited_report_interval (idev ));
2121
2121
}
2122
2122
in6_dev_put (idev );
2123
2123
}
@@ -2416,12 +2416,12 @@ static void igmp6_join_group(struct ifmcaddr6 *ma)
2416
2416
delay = prandom_u32 () % unsolicited_report_interval (ma -> idev );
2417
2417
2418
2418
spin_lock_bh (& ma -> mca_lock );
2419
- if (del_timer (& ma -> mca_timer )) {
2419
+ if (cancel_delayed_work (& ma -> mca_work )) {
2420
2420
refcount_dec (& ma -> mca_refcnt );
2421
- delay = ma -> mca_timer .expires - jiffies ;
2421
+ delay = ma -> mca_work . timer .expires - jiffies ;
2422
2422
}
2423
2423
2424
- if (!mod_timer ( & ma -> mca_timer , jiffies + delay ))
2424
+ if (!mod_delayed_work ( mld_wq , & ma -> mca_work , delay ))
2425
2425
refcount_inc (& ma -> mca_refcnt );
2426
2426
ma -> mca_flags |= MAF_TIMER_RUNNING | MAF_LAST_REPORTER ;
2427
2427
spin_unlock_bh (& ma -> mca_lock );
@@ -2458,25 +2458,29 @@ static void igmp6_leave_group(struct ifmcaddr6 *ma)
2458
2458
}
2459
2459
}
2460
2460
2461
- static void mld_gq_timer_expire (struct timer_list * t )
2461
+ static void mld_gq_work (struct work_struct * work )
2462
2462
{
2463
- struct inet6_dev * idev = from_timer (idev , t , mc_gq_timer );
2463
+ struct inet6_dev * idev = container_of (to_delayed_work (work ),
2464
+ struct inet6_dev ,
2465
+ mc_gq_work );
2464
2466
2465
2467
idev -> mc_gq_running = 0 ;
2466
2468
mld_send_report (idev , NULL );
2467
2469
in6_dev_put (idev );
2468
2470
}
2469
2471
2470
- static void mld_ifc_timer_expire (struct timer_list * t )
2472
+ static void mld_ifc_work (struct work_struct * work )
2471
2473
{
2472
- struct inet6_dev * idev = from_timer (idev , t , mc_ifc_timer );
2474
+ struct inet6_dev * idev = container_of (to_delayed_work (work ),
2475
+ struct inet6_dev ,
2476
+ mc_ifc_work );
2473
2477
2474
2478
mld_send_cr (idev );
2475
2479
if (idev -> mc_ifc_count ) {
2476
2480
idev -> mc_ifc_count -- ;
2477
2481
if (idev -> mc_ifc_count )
2478
- mld_ifc_start_timer (idev ,
2479
- unsolicited_report_interval (idev ));
2482
+ mld_ifc_start_work (idev ,
2483
+ unsolicited_report_interval (idev ));
2480
2484
}
2481
2485
in6_dev_put (idev );
2482
2486
}
@@ -2486,22 +2490,23 @@ static void mld_ifc_event(struct inet6_dev *idev)
2486
2490
if (mld_in_v1_mode (idev ))
2487
2491
return ;
2488
2492
idev -> mc_ifc_count = idev -> mc_qrv ;
2489
- mld_ifc_start_timer (idev , 1 );
2493
+ mld_ifc_start_work (idev , 1 );
2490
2494
}
2491
2495
2492
- static void igmp6_timer_handler (struct timer_list * t )
2496
+ static void mld_mca_work (struct work_struct * work )
2493
2497
{
2494
- struct ifmcaddr6 * ma = from_timer (ma , t , mca_timer );
2498
+ struct ifmcaddr6 * ma = container_of (to_delayed_work (work ),
2499
+ struct ifmcaddr6 , mca_work );
2495
2500
2496
2501
if (mld_in_v1_mode (ma -> idev ))
2497
2502
igmp6_send (& ma -> mca_addr , ma -> idev -> dev , ICMPV6_MGM_REPORT );
2498
2503
else
2499
2504
mld_send_report (ma -> idev , ma );
2500
2505
2501
- spin_lock (& ma -> mca_lock );
2506
+ spin_lock_bh (& ma -> mca_lock );
2502
2507
ma -> mca_flags |= MAF_LAST_REPORTER ;
2503
2508
ma -> mca_flags &= ~MAF_TIMER_RUNNING ;
2504
- spin_unlock (& ma -> mca_lock );
2509
+ spin_unlock_bh (& ma -> mca_lock );
2505
2510
ma_put (ma );
2506
2511
}
2507
2512
@@ -2537,12 +2542,12 @@ void ipv6_mc_down(struct inet6_dev *idev)
2537
2542
for (i = idev -> mc_list ; i ; i = i -> next )
2538
2543
igmp6_group_dropped (i );
2539
2544
2540
- /* Should stop timer after group drop. or we will
2541
- * start timer again in mld_ifc_event()
2545
+ /* Should stop work after group drop. or we will
2546
+ * start work again in mld_ifc_event()
2542
2547
*/
2543
- mld_ifc_stop_timer (idev );
2544
- mld_gq_stop_timer (idev );
2545
- mld_dad_stop_timer (idev );
2548
+ mld_ifc_stop_work (idev );
2549
+ mld_gq_stop_work (idev );
2550
+ mld_dad_stop_work (idev );
2546
2551
read_unlock_bh (& idev -> lock );
2547
2552
}
2548
2553
@@ -2579,11 +2584,11 @@ void ipv6_mc_init_dev(struct inet6_dev *idev)
2579
2584
write_lock_bh (& idev -> lock );
2580
2585
spin_lock_init (& idev -> mc_lock );
2581
2586
idev -> mc_gq_running = 0 ;
2582
- timer_setup (& idev -> mc_gq_timer , mld_gq_timer_expire , 0 );
2587
+ INIT_DELAYED_WORK (& idev -> mc_gq_work , mld_gq_work );
2583
2588
idev -> mc_tomb = NULL ;
2584
2589
idev -> mc_ifc_count = 0 ;
2585
- timer_setup (& idev -> mc_ifc_timer , mld_ifc_timer_expire , 0 );
2586
- timer_setup (& idev -> mc_dad_timer , mld_dad_timer_expire , 0 );
2590
+ INIT_DELAYED_WORK (& idev -> mc_ifc_work , mld_ifc_work );
2591
+ INIT_DELAYED_WORK (& idev -> mc_dad_work , mld_dad_work );
2587
2592
ipv6_mc_reset (idev );
2588
2593
write_unlock_bh (& idev -> lock );
2589
2594
}
@@ -2596,7 +2601,7 @@ void ipv6_mc_destroy_dev(struct inet6_dev *idev)
2596
2601
{
2597
2602
struct ifmcaddr6 * i ;
2598
2603
2599
- /* Deactivate timers */
2604
+ /* Deactivate works */
2600
2605
ipv6_mc_down (idev );
2601
2606
mld_clear_delrec (idev );
2602
2607
@@ -2763,7 +2768,7 @@ static int igmp6_mc_seq_show(struct seq_file *seq, void *v)
2763
2768
& im -> mca_addr ,
2764
2769
im -> mca_users , im -> mca_flags ,
2765
2770
(im -> mca_flags & MAF_TIMER_RUNNING ) ?
2766
- jiffies_to_clock_t (im -> mca_timer . expires - jiffies ) : 0 );
2771
+ jiffies_to_clock_t (im -> mca_work . timer . expires - jiffies ) : 0 );
2767
2772
return 0 ;
2768
2773
}
2769
2774
@@ -3002,7 +3007,19 @@ static struct pernet_operations igmp6_net_ops = {
3002
3007
3003
3008
int __init igmp6_init (void )
3004
3009
{
3005
- return register_pernet_subsys (& igmp6_net_ops );
3010
+ int err ;
3011
+
3012
+ err = register_pernet_subsys (& igmp6_net_ops );
3013
+ if (err )
3014
+ return err ;
3015
+
3016
+ mld_wq = create_workqueue ("mld" );
3017
+ if (!mld_wq ) {
3018
+ unregister_pernet_subsys (& igmp6_net_ops );
3019
+ return - ENOMEM ;
3020
+ }
3021
+
3022
+ return err ;
3006
3023
}
3007
3024
3008
3025
int __init igmp6_late_init (void )
@@ -3013,6 +3030,7 @@ int __init igmp6_late_init(void)
3013
3030
void igmp6_cleanup (void )
3014
3031
{
3015
3032
unregister_pernet_subsys (& igmp6_net_ops );
3033
+ destroy_workqueue (mld_wq );
3016
3034
}
3017
3035
3018
3036
void igmp6_late_cleanup (void )
0 commit comments