@@ -221,6 +221,7 @@ static struct tcf_chain *tcf_chain_create(struct tcf_block *block,
221
221
if (!chain )
222
222
return NULL ;
223
223
list_add_tail (& chain -> list , & block -> chain_list );
224
+ mutex_init (& chain -> filter_chain_lock );
224
225
chain -> block = block ;
225
226
chain -> index = chain_index ;
226
227
chain -> refcnt = 1 ;
@@ -280,6 +281,7 @@ static void tcf_chain_destroy(struct tcf_chain *chain, bool free_block)
280
281
{
281
282
struct tcf_block * block = chain -> block ;
282
283
284
+ mutex_destroy (& chain -> filter_chain_lock );
283
285
kfree (chain );
284
286
if (free_block )
285
287
tcf_block_destroy (block );
@@ -443,9 +445,13 @@ static void tcf_chain_put_explicitly_created(struct tcf_chain *chain)
443
445
444
446
static void tcf_chain_flush (struct tcf_chain * chain )
445
447
{
446
- struct tcf_proto * tp = rtnl_dereference ( chain -> filter_chain ) ;
448
+ struct tcf_proto * tp ;
447
449
450
+ mutex_lock (& chain -> filter_chain_lock );
451
+ tp = tcf_chain_dereference (chain -> filter_chain , chain );
448
452
tcf_chain0_head_change (chain , NULL );
453
+ mutex_unlock (& chain -> filter_chain_lock );
454
+
449
455
while (tp ) {
450
456
RCU_INIT_POINTER (chain -> filter_chain , tp -> next );
451
457
tcf_proto_destroy (tp , NULL );
@@ -785,11 +791,29 @@ tcf_chain0_head_change_cb_add(struct tcf_block *block,
785
791
786
792
mutex_lock (& block -> lock );
787
793
chain0 = block -> chain0 .chain ;
788
- if (chain0 && chain0 -> filter_chain )
789
- tcf_chain_head_change_item (item , chain0 -> filter_chain );
790
- list_add (& item -> list , & block -> chain0 .filter_chain_list );
794
+ if (chain0 )
795
+ tcf_chain_hold (chain0 );
796
+ else
797
+ list_add (& item -> list , & block -> chain0 .filter_chain_list );
791
798
mutex_unlock (& block -> lock );
792
799
800
+ if (chain0 ) {
801
+ struct tcf_proto * tp_head ;
802
+
803
+ mutex_lock (& chain0 -> filter_chain_lock );
804
+
805
+ tp_head = tcf_chain_dereference (chain0 -> filter_chain , chain0 );
806
+ if (tp_head )
807
+ tcf_chain_head_change_item (item , tp_head );
808
+
809
+ mutex_lock (& block -> lock );
810
+ list_add (& item -> list , & block -> chain0 .filter_chain_list );
811
+ mutex_unlock (& block -> lock );
812
+
813
+ mutex_unlock (& chain0 -> filter_chain_lock );
814
+ tcf_chain_put (chain0 );
815
+ }
816
+
793
817
return 0 ;
794
818
}
795
819
@@ -1464,9 +1488,10 @@ struct tcf_chain_info {
1464
1488
struct tcf_proto __rcu * next ;
1465
1489
};
1466
1490
1467
- static struct tcf_proto * tcf_chain_tp_prev (struct tcf_chain_info * chain_info )
1491
+ static struct tcf_proto * tcf_chain_tp_prev (struct tcf_chain * chain ,
1492
+ struct tcf_chain_info * chain_info )
1468
1493
{
1469
- return rtnl_dereference (* chain_info -> pprev );
1494
+ return tcf_chain_dereference (* chain_info -> pprev , chain );
1470
1495
}
1471
1496
1472
1497
static void tcf_chain_tp_insert (struct tcf_chain * chain ,
@@ -1475,7 +1500,7 @@ static void tcf_chain_tp_insert(struct tcf_chain *chain,
1475
1500
{
1476
1501
if (* chain_info -> pprev == chain -> filter_chain )
1477
1502
tcf_chain0_head_change (chain , tp );
1478
- RCU_INIT_POINTER (tp -> next , tcf_chain_tp_prev (chain_info ));
1503
+ RCU_INIT_POINTER (tp -> next , tcf_chain_tp_prev (chain , chain_info ));
1479
1504
rcu_assign_pointer (* chain_info -> pprev , tp );
1480
1505
tcf_chain_hold (chain );
1481
1506
}
@@ -1484,7 +1509,7 @@ static void tcf_chain_tp_remove(struct tcf_chain *chain,
1484
1509
struct tcf_chain_info * chain_info ,
1485
1510
struct tcf_proto * tp )
1486
1511
{
1487
- struct tcf_proto * next = rtnl_dereference (chain_info -> next );
1512
+ struct tcf_proto * next = tcf_chain_dereference (chain_info -> next , chain );
1488
1513
1489
1514
if (tp == chain -> filter_chain )
1490
1515
tcf_chain0_head_change (chain , next );
@@ -1502,7 +1527,8 @@ static struct tcf_proto *tcf_chain_tp_find(struct tcf_chain *chain,
1502
1527
1503
1528
/* Check the chain for existence of proto-tcf with this priority */
1504
1529
for (pprev = & chain -> filter_chain ;
1505
- (tp = rtnl_dereference (* pprev )); pprev = & tp -> next ) {
1530
+ (tp = tcf_chain_dereference (* pprev , chain ));
1531
+ pprev = & tp -> next ) {
1506
1532
if (tp -> prio >= prio ) {
1507
1533
if (tp -> prio == prio ) {
1508
1534
if (prio_allocate ||
@@ -1710,12 +1736,13 @@ static int tc_new_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
1710
1736
goto errout ;
1711
1737
}
1712
1738
1739
+ mutex_lock (& chain -> filter_chain_lock );
1713
1740
tp = tcf_chain_tp_find (chain , & chain_info , protocol ,
1714
1741
prio , prio_allocate );
1715
1742
if (IS_ERR (tp )) {
1716
1743
NL_SET_ERR_MSG (extack , "Filter with specified priority/protocol not found" );
1717
1744
err = PTR_ERR (tp );
1718
- goto errout ;
1745
+ goto errout_locked ;
1719
1746
}
1720
1747
1721
1748
if (tp == NULL ) {
@@ -1724,29 +1751,37 @@ static int tc_new_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
1724
1751
if (tca [TCA_KIND ] == NULL || !protocol ) {
1725
1752
NL_SET_ERR_MSG (extack , "Filter kind and protocol must be specified" );
1726
1753
err = - EINVAL ;
1727
- goto errout ;
1754
+ goto errout_locked ;
1728
1755
}
1729
1756
1730
1757
if (!(n -> nlmsg_flags & NLM_F_CREATE )) {
1731
1758
NL_SET_ERR_MSG (extack , "Need both RTM_NEWTFILTER and NLM_F_CREATE to create a new filter" );
1732
1759
err = - ENOENT ;
1733
- goto errout ;
1760
+ goto errout_locked ;
1734
1761
}
1735
1762
1736
1763
if (prio_allocate )
1737
- prio = tcf_auto_prio (tcf_chain_tp_prev (& chain_info ));
1764
+ prio = tcf_auto_prio (tcf_chain_tp_prev (chain ,
1765
+ & chain_info ));
1738
1766
1767
+ mutex_unlock (& chain -> filter_chain_lock );
1739
1768
tp = tcf_proto_create (nla_data (tca [TCA_KIND ]),
1740
1769
protocol , prio , chain , extack );
1741
1770
if (IS_ERR (tp )) {
1742
1771
err = PTR_ERR (tp );
1743
1772
goto errout ;
1744
1773
}
1774
+
1775
+ mutex_lock (& chain -> filter_chain_lock );
1776
+ tcf_chain_tp_insert (chain , & chain_info , tp );
1777
+ mutex_unlock (& chain -> filter_chain_lock );
1745
1778
tp_created = 1 ;
1746
1779
} else if (tca [TCA_KIND ] && nla_strcmp (tca [TCA_KIND ], tp -> ops -> kind )) {
1747
1780
NL_SET_ERR_MSG (extack , "Specified filter kind does not match existing one" );
1748
1781
err = - EINVAL ;
1749
- goto errout ;
1782
+ goto errout_locked ;
1783
+ } else {
1784
+ mutex_unlock (& chain -> filter_chain_lock );
1750
1785
}
1751
1786
1752
1787
fh = tp -> ops -> get (tp , t -> tcm_handle );
@@ -1772,15 +1807,11 @@ static int tc_new_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
1772
1807
err = tp -> ops -> change (net , skb , tp , cl , t -> tcm_handle , tca , & fh ,
1773
1808
n -> nlmsg_flags & NLM_F_CREATE ? TCA_ACT_NOREPLACE : TCA_ACT_REPLACE ,
1774
1809
extack );
1775
- if (err == 0 ) {
1776
- if (tp_created )
1777
- tcf_chain_tp_insert (chain , & chain_info , tp );
1810
+ if (err == 0 )
1778
1811
tfilter_notify (net , skb , n , tp , block , q , parent , fh ,
1779
1812
RTM_NEWTFILTER , false);
1780
- } else {
1781
- if (tp_created )
1782
- tcf_proto_destroy (tp , NULL );
1783
- }
1813
+ else if (tp_created )
1814
+ tcf_proto_destroy (tp , NULL );
1784
1815
1785
1816
errout :
1786
1817
if (chain )
@@ -1790,6 +1821,10 @@ static int tc_new_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
1790
1821
/* Replay the request. */
1791
1822
goto replay ;
1792
1823
return err ;
1824
+
1825
+ errout_locked :
1826
+ mutex_unlock (& chain -> filter_chain_lock );
1827
+ goto errout ;
1793
1828
}
1794
1829
1795
1830
static int tc_del_tfilter (struct sk_buff * skb , struct nlmsghdr * n ,
@@ -1865,31 +1900,34 @@ static int tc_del_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
1865
1900
goto errout ;
1866
1901
}
1867
1902
1903
+ mutex_lock (& chain -> filter_chain_lock );
1868
1904
tp = tcf_chain_tp_find (chain , & chain_info , protocol ,
1869
1905
prio , false);
1870
1906
if (!tp || IS_ERR (tp )) {
1871
1907
NL_SET_ERR_MSG (extack , "Filter with specified priority/protocol not found" );
1872
1908
err = tp ? PTR_ERR (tp ) : - ENOENT ;
1873
- goto errout ;
1909
+ goto errout_locked ;
1874
1910
} else if (tca [TCA_KIND ] && nla_strcmp (tca [TCA_KIND ], tp -> ops -> kind )) {
1875
1911
NL_SET_ERR_MSG (extack , "Specified filter kind does not match existing one" );
1876
1912
err = - EINVAL ;
1913
+ goto errout_locked ;
1914
+ } else if (t -> tcm_handle == 0 ) {
1915
+ tcf_chain_tp_remove (chain , & chain_info , tp );
1916
+ mutex_unlock (& chain -> filter_chain_lock );
1917
+
1918
+ tfilter_notify (net , skb , n , tp , block , q , parent , fh ,
1919
+ RTM_DELTFILTER , false);
1920
+ tcf_proto_destroy (tp , extack );
1921
+ err = 0 ;
1877
1922
goto errout ;
1878
1923
}
1924
+ mutex_unlock (& chain -> filter_chain_lock );
1879
1925
1880
1926
fh = tp -> ops -> get (tp , t -> tcm_handle );
1881
1927
1882
1928
if (!fh ) {
1883
- if (t -> tcm_handle == 0 ) {
1884
- tcf_chain_tp_remove (chain , & chain_info , tp );
1885
- tfilter_notify (net , skb , n , tp , block , q , parent , fh ,
1886
- RTM_DELTFILTER , false);
1887
- tcf_proto_destroy (tp , extack );
1888
- err = 0 ;
1889
- } else {
1890
- NL_SET_ERR_MSG (extack , "Specified filter handle not found" );
1891
- err = - ENOENT ;
1892
- }
1929
+ NL_SET_ERR_MSG (extack , "Specified filter handle not found" );
1930
+ err = - ENOENT ;
1893
1931
} else {
1894
1932
bool last ;
1895
1933
@@ -1899,7 +1937,10 @@ static int tc_del_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
1899
1937
if (err )
1900
1938
goto errout ;
1901
1939
if (last ) {
1940
+ mutex_lock (& chain -> filter_chain_lock );
1902
1941
tcf_chain_tp_remove (chain , & chain_info , tp );
1942
+ mutex_unlock (& chain -> filter_chain_lock );
1943
+
1903
1944
tcf_proto_destroy (tp , extack );
1904
1945
}
1905
1946
}
@@ -1909,6 +1950,10 @@ static int tc_del_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
1909
1950
tcf_chain_put (chain );
1910
1951
tcf_block_release (q , block );
1911
1952
return err ;
1953
+
1954
+ errout_locked :
1955
+ mutex_unlock (& chain -> filter_chain_lock );
1956
+ goto errout ;
1912
1957
}
1913
1958
1914
1959
static int tc_get_tfilter (struct sk_buff * skb , struct nlmsghdr * n ,
@@ -1966,8 +2011,10 @@ static int tc_get_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
1966
2011
goto errout ;
1967
2012
}
1968
2013
2014
+ mutex_lock (& chain -> filter_chain_lock );
1969
2015
tp = tcf_chain_tp_find (chain , & chain_info , protocol ,
1970
2016
prio , false);
2017
+ mutex_unlock (& chain -> filter_chain_lock );
1971
2018
if (!tp || IS_ERR (tp )) {
1972
2019
NL_SET_ERR_MSG (extack , "Filter with specified priority/protocol not found" );
1973
2020
err = tp ? PTR_ERR (tp ) : - ENOENT ;
0 commit comments