aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@vyatta.com>2008-01-31 19:45:47 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-31 22:28:23 -0500
commit71d67e666e73e3b7e9ef124745ee2e454ac04be8 (patch)
treee163b578c98f3c3ac69cb88ca6bf936d6ab4d698
parent9fe7c712fc955565c32e2f899d4ffeceaf028398 (diff)
[IPV4] fib_trie: rescan if key is lost during dump
Normally during a dump the key of the last dumped entry is used for continuation, but since lock is dropped it might be lost. In that case fallback to the old counter based N^2 behaviour. This means the dump will end up skipping some routes which matches what FIB_HASH does. Signed-off-by: Stephen Hemminger <shemminger@vyatta.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/netlink.h2
-rw-r--r--net/ipv4/fib_trie.c49
2 files changed, 33 insertions, 18 deletions
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index bd13b6f4a98e..fb0713b6ffaf 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -219,7 +219,7 @@ struct netlink_callback
219 int (*dump)(struct sk_buff * skb, struct netlink_callback *cb); 219 int (*dump)(struct sk_buff * skb, struct netlink_callback *cb);
220 int (*done)(struct netlink_callback *cb); 220 int (*done)(struct netlink_callback *cb);
221 int family; 221 int family;
222 long args[5]; 222 long args[6];
223}; 223};
224 224
225struct netlink_notify 225struct netlink_notify
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index cbccafde8238..35851c96bdfb 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -1758,6 +1758,19 @@ static struct leaf *trie_nextleaf(struct leaf *l)
1758 return leaf_walk_rcu(p, c); 1758 return leaf_walk_rcu(p, c);
1759} 1759}
1760 1760
1761static struct leaf *trie_leafindex(struct trie *t, int index)
1762{
1763 struct leaf *l = trie_firstleaf(t);
1764
1765 while (index-- > 0) {
1766 l = trie_nextleaf(l);
1767 if (!l)
1768 break;
1769 }
1770 return l;
1771}
1772
1773
1761/* 1774/*
1762 * Caller must hold RTNL. 1775 * Caller must hold RTNL.
1763 */ 1776 */
@@ -1863,7 +1876,7 @@ static int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah,
1863 struct fib_alias *fa; 1876 struct fib_alias *fa;
1864 __be32 xkey = htonl(key); 1877 __be32 xkey = htonl(key);
1865 1878
1866 s_i = cb->args[4]; 1879 s_i = cb->args[5];
1867 i = 0; 1880 i = 0;
1868 1881
1869 /* rcu_read_lock is hold by caller */ 1882 /* rcu_read_lock is hold by caller */
@@ -1884,12 +1897,12 @@ static int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah,
1884 plen, 1897 plen,
1885 fa->fa_tos, 1898 fa->fa_tos,
1886 fa->fa_info, NLM_F_MULTI) < 0) { 1899 fa->fa_info, NLM_F_MULTI) < 0) {
1887 cb->args[4] = i; 1900 cb->args[5] = i;
1888 return -1; 1901 return -1;
1889 } 1902 }
1890 i++; 1903 i++;
1891 } 1904 }
1892 cb->args[4] = i; 1905 cb->args[5] = i;
1893 return skb->len; 1906 return skb->len;
1894} 1907}
1895 1908
@@ -1900,7 +1913,7 @@ static int fn_trie_dump_leaf(struct leaf *l, struct fib_table *tb,
1900 struct hlist_node *node; 1913 struct hlist_node *node;
1901 int i, s_i; 1914 int i, s_i;
1902 1915
1903 s_i = cb->args[3]; 1916 s_i = cb->args[4];
1904 i = 0; 1917 i = 0;
1905 1918
1906 /* rcu_read_lock is hold by caller */ 1919 /* rcu_read_lock is hold by caller */
@@ -1911,19 +1924,19 @@ static int fn_trie_dump_leaf(struct leaf *l, struct fib_table *tb,
1911 } 1924 }
1912 1925
1913 if (i > s_i) 1926 if (i > s_i)
1914 cb->args[4] = 0; 1927 cb->args[5] = 0;
1915 1928
1916 if (list_empty(&li->falh)) 1929 if (list_empty(&li->falh))
1917 continue; 1930 continue;
1918 1931
1919 if (fn_trie_dump_fa(l->key, li->plen, &li->falh, tb, skb, cb) < 0) { 1932 if (fn_trie_dump_fa(l->key, li->plen, &li->falh, tb, skb, cb) < 0) {
1920 cb->args[3] = i; 1933 cb->args[4] = i;
1921 return -1; 1934 return -1;
1922 } 1935 }
1923 i++; 1936 i++;
1924 } 1937 }
1925 1938
1926 cb->args[3] = i; 1939 cb->args[4] = i;
1927 return skb->len; 1940 return skb->len;
1928} 1941}
1929 1942
@@ -1933,35 +1946,37 @@ static int fn_trie_dump(struct fib_table *tb, struct sk_buff *skb,
1933 struct leaf *l; 1946 struct leaf *l;
1934 struct trie *t = (struct trie *) tb->tb_data; 1947 struct trie *t = (struct trie *) tb->tb_data;
1935 t_key key = cb->args[2]; 1948 t_key key = cb->args[2];
1949 int count = cb->args[3];
1936 1950
1937 rcu_read_lock(); 1951 rcu_read_lock();
1938 /* Dump starting at last key. 1952 /* Dump starting at last key.
1939 * Note: 0.0.0.0/0 (ie default) is first key. 1953 * Note: 0.0.0.0/0 (ie default) is first key.
1940 */ 1954 */
1941 if (!key) 1955 if (count == 0)
1942 l = trie_firstleaf(t); 1956 l = trie_firstleaf(t);
1943 else { 1957 else {
1958 /* Normally, continue from last key, but if that is missing
1959 * fallback to using slow rescan
1960 */
1944 l = fib_find_node(t, key); 1961 l = fib_find_node(t, key);
1945 if (!l) { 1962 if (!l)
1946 /* The table changed during the dump, rather than 1963 l = trie_leafindex(t, count);
1947 * giving partial data, just make application retry.
1948 */
1949 rcu_read_unlock();
1950 return -EBUSY;
1951 }
1952 } 1964 }
1953 1965
1954 while (l) { 1966 while (l) {
1955 cb->args[2] = l->key; 1967 cb->args[2] = l->key;
1956 if (fn_trie_dump_leaf(l, tb, skb, cb) < 0) { 1968 if (fn_trie_dump_leaf(l, tb, skb, cb) < 0) {
1969 cb->args[3] = count;
1957 rcu_read_unlock(); 1970 rcu_read_unlock();
1958 return -1; 1971 return -1;
1959 } 1972 }
1960 1973
1974 ++count;
1961 l = trie_nextleaf(l); 1975 l = trie_nextleaf(l);
1962 memset(&cb->args[3], 0, 1976 memset(&cb->args[4], 0,
1963 sizeof(cb->args) - 3*sizeof(cb->args[0])); 1977 sizeof(cb->args) - 4*sizeof(cb->args[0]));
1964 } 1978 }
1979 cb->args[3] = count;
1965 rcu_read_unlock(); 1980 rcu_read_unlock();
1966 1981
1967 return skb->len; 1982 return skb->len;