Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=71d67e666e73e3b7e9ef124745ee2e454ac04be8
Commit:     71d67e666e73e3b7e9ef124745ee2e454ac04be8
Parent:     9fe7c712fc955565c32e2f899d4ffeceaf028398
Author:     Stephen Hemminger <[EMAIL PROTECTED]>
AuthorDate: Thu Jan 31 16:45:47 2008 -0800
Committer:  David S. Miller <[EMAIL PROTECTED]>
CommitDate: Thu Jan 31 19:28:23 2008 -0800

    [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 <[EMAIL PROTECTED]>
    Signed-off-by: David S. Miller <[EMAIL PROTECTED]>
---
 include/linux/netlink.h |    2 +-
 net/ipv4/fib_trie.c     |   49 ++++++++++++++++++++++++++++++----------------
 2 files changed, 33 insertions(+), 18 deletions(-)

diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index bd13b6f..fb0713b 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -219,7 +219,7 @@ struct netlink_callback
        int             (*dump)(struct sk_buff * skb, struct netlink_callback 
*cb);
        int             (*done)(struct netlink_callback *cb);
        int             family;
-       long            args[5];
+       long            args[6];
 };
 
 struct netlink_notify
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index cbccafd..35851c9 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)
        return leaf_walk_rcu(p, c);
 }
 
+static struct leaf *trie_leafindex(struct trie *t, int index)
+{
+       struct leaf *l = trie_firstleaf(t);
+
+       while (index-- > 0) {
+               l = trie_nextleaf(l);
+               if (!l)
+                       break;
+       }
+       return l;
+}
+
+
 /*
  * Caller must hold RTNL.
  */
@@ -1863,7 +1876,7 @@ static int fn_trie_dump_fa(t_key key, int plen, struct 
list_head *fah,
        struct fib_alias *fa;
        __be32 xkey = htonl(key);
 
-       s_i = cb->args[4];
+       s_i = cb->args[5];
        i = 0;
 
        /* 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,
                                  plen,
                                  fa->fa_tos,
                                  fa->fa_info, NLM_F_MULTI) < 0) {
-                       cb->args[4] = i;
+                       cb->args[5] = i;
                        return -1;
                }
                i++;
        }
-       cb->args[4] = i;
+       cb->args[5] = i;
        return skb->len;
 }
 
@@ -1900,7 +1913,7 @@ static int fn_trie_dump_leaf(struct leaf *l, struct 
fib_table *tb,
        struct hlist_node *node;
        int i, s_i;
 
-       s_i = cb->args[3];
+       s_i = cb->args[4];
        i = 0;
 
        /* rcu_read_lock is hold by caller */
@@ -1911,19 +1924,19 @@ static int fn_trie_dump_leaf(struct leaf *l, struct 
fib_table *tb,
                }
 
                if (i > s_i)
-                       cb->args[4] = 0;
+                       cb->args[5] = 0;
 
                if (list_empty(&li->falh))
                        continue;
 
                if (fn_trie_dump_fa(l->key, li->plen, &li->falh, tb, skb, cb) < 
0) {
-                       cb->args[3] = i;
+                       cb->args[4] = i;
                        return -1;
                }
                i++;
        }
 
-       cb->args[3] = i;
+       cb->args[4] = i;
        return skb->len;
 }
 
@@ -1933,35 +1946,37 @@ static int fn_trie_dump(struct fib_table *tb, struct 
sk_buff *skb,
        struct leaf *l;
        struct trie *t = (struct trie *) tb->tb_data;
        t_key key = cb->args[2];
+       int count = cb->args[3];
 
        rcu_read_lock();
        /* Dump starting at last key.
         * Note: 0.0.0.0/0 (ie default) is first key.
         */
-       if (!key)
+       if (count == 0)
                l = trie_firstleaf(t);
        else {
+               /* Normally, continue from last key, but if that is missing
+                * fallback to using slow rescan
+                */
                l = fib_find_node(t, key);
-               if (!l) {
-                       /* The table changed during the dump, rather than
-                        * giving partial data, just make application retry.
-                        */
-                       rcu_read_unlock();
-                       return -EBUSY;
-               }
+               if (!l)
+                       l = trie_leafindex(t, count);
        }
 
        while (l) {
                cb->args[2] = l->key;
                if (fn_trie_dump_leaf(l, tb, skb, cb) < 0) {
+                       cb->args[3] = count;
                        rcu_read_unlock();
                        return -1;
                }
 
+               ++count;
                l = trie_nextleaf(l);
-               memset(&cb->args[3], 0,
-                      sizeof(cb->args) - 3*sizeof(cb->args[0]));
+               memset(&cb->args[4], 0,
+                      sizeof(cb->args) - 4*sizeof(cb->args[0]));
        }
+       cb->args[3] = count;
        rcu_read_unlock();
 
        return skb->len;
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to