Loading net/sched/cls_fw.c +77 −34 Original line number Diff line number Diff line Loading @@ -33,17 +33,20 @@ struct fw_head { u32 mask; struct fw_filter *ht[HTSIZE]; struct fw_filter __rcu *ht[HTSIZE]; struct rcu_head rcu; }; struct fw_filter { struct fw_filter *next; struct fw_filter __rcu *next; u32 id; struct tcf_result res; #ifdef CONFIG_NET_CLS_IND int ifindex; #endif /* CONFIG_NET_CLS_IND */ struct tcf_exts exts; struct tcf_proto *tp; struct rcu_head rcu; }; static u32 fw_hash(u32 handle) Loading @@ -56,14 +59,16 @@ static u32 fw_hash(u32 handle) static int fw_classify(struct sk_buff *skb, const struct tcf_proto *tp, struct tcf_result *res) { struct fw_head *head = tp->root; struct fw_head *head = rcu_dereference_bh(tp->root); struct fw_filter *f; int r; u32 id = skb->mark; if (head != NULL) { id &= head->mask; for (f = head->ht[fw_hash(id)]; f; f = f->next) { for (f = rcu_dereference_bh(head->ht[fw_hash(id)]); f; f = rcu_dereference_bh(f->next)) { if (f->id == id) { *res = f->res; #ifdef CONFIG_NET_CLS_IND Loading Loading @@ -92,13 +97,14 @@ static int fw_classify(struct sk_buff *skb, const struct tcf_proto *tp, static unsigned long fw_get(struct tcf_proto *tp, u32 handle) { struct fw_head *head = tp->root; struct fw_head *head = rtnl_dereference(tp->root); struct fw_filter *f; if (head == NULL) return 0; for (f = head->ht[fw_hash(handle)]; f; f = f->next) { f = rtnl_dereference(head->ht[fw_hash(handle)]); for (; f; f = rtnl_dereference(f->next)) { if (f->id == handle) return (unsigned long)f; } Loading @@ -114,8 +120,11 @@ static int fw_init(struct tcf_proto *tp) return 0; } static void fw_delete_filter(struct tcf_proto *tp, struct fw_filter *f) static void fw_delete_filter(struct rcu_head *head) { struct fw_filter *f = container_of(head, struct fw_filter, rcu); struct tcf_proto *tp = f->tp; tcf_unbind_filter(tp, &f->res); tcf_exts_destroy(tp, &f->exts); kfree(f); Loading @@ -123,7 +132,7 @@ static void fw_delete_filter(struct tcf_proto *tp, struct fw_filter *f) static void fw_destroy(struct tcf_proto *tp) { struct fw_head *head = tp->root; struct fw_head *head = rtnl_dereference(tp->root); struct fw_filter *f; int h; Loading @@ -131,29 +140,33 @@ static void fw_destroy(struct tcf_proto *tp) return; for (h = 0; h < HTSIZE; h++) { while ((f = head->ht[h]) != NULL) { head->ht[h] = f->next; fw_delete_filter(tp, f); while ((f = rtnl_dereference(head->ht[h])) != NULL) { RCU_INIT_POINTER(head->ht[h], rtnl_dereference(f->next)); call_rcu(&f->rcu, fw_delete_filter); } } kfree(head); RCU_INIT_POINTER(tp->root, NULL); kfree_rcu(head, rcu); } static int fw_delete(struct tcf_proto *tp, unsigned long arg) { struct fw_head *head = tp->root; struct fw_head *head = rtnl_dereference(tp->root); struct fw_filter *f = (struct fw_filter *)arg; struct fw_filter **fp; struct fw_filter __rcu **fp; struct fw_filter *pfp; if (head == NULL || f == NULL) goto out; for (fp = &head->ht[fw_hash(f->id)]; *fp; fp = &(*fp)->next) { if (*fp == f) { tcf_tree_lock(tp); *fp = f->next; tcf_tree_unlock(tp); fw_delete_filter(tp, f); fp = &head->ht[fw_hash(f->id)]; for (pfp = rtnl_dereference(*fp); pfp; fp = &pfp->next, pfp = rtnl_dereference(*fp)) { if (pfp == f) { RCU_INIT_POINTER(*fp, rtnl_dereference(f->next)); call_rcu(&f->rcu, fw_delete_filter); return 0; } } Loading @@ -171,7 +184,7 @@ static int fw_change_attrs(struct net *net, struct tcf_proto *tp, struct fw_filter *f, struct nlattr **tb, struct nlattr **tca, unsigned long base, bool ovr) { struct fw_head *head = tp->root; struct fw_head *head = rtnl_dereference(tp->root); struct tcf_exts e; u32 mask; int err; Loading Loading @@ -220,7 +233,7 @@ static int fw_change(struct net *net, struct sk_buff *in_skb, struct nlattr **tca, unsigned long *arg, bool ovr) { struct fw_head *head = tp->root; struct fw_head *head = rtnl_dereference(tp->root); struct fw_filter *f = (struct fw_filter *) *arg; struct nlattr *opt = tca[TCA_OPTIONS]; struct nlattr *tb[TCA_FW_MAX + 1]; Loading @@ -233,10 +246,42 @@ static int fw_change(struct net *net, struct sk_buff *in_skb, if (err < 0) return err; if (f != NULL) { if (f) { struct fw_filter *pfp, *fnew; struct fw_filter __rcu **fp; if (f->id != handle && handle) return -EINVAL; return fw_change_attrs(net, tp, f, tb, tca, base, ovr); fnew = kzalloc(sizeof(struct fw_filter), GFP_KERNEL); if (!fnew) return -ENOBUFS; fnew->id = f->id; fnew->res = f->res; #ifdef CONFIG_NET_CLS_IND fnew->ifindex = f->ifindex; #endif /* CONFIG_NET_CLS_IND */ fnew->tp = f->tp; err = fw_change_attrs(net, tp, fnew, tb, tca, base, ovr); if (err < 0) { kfree(fnew); return err; } fp = &head->ht[fw_hash(fnew->id)]; for (pfp = rtnl_dereference(*fp); pfp; fp = &pfp->next, pfp = rtnl_dereference(*fp)) if (pfp == f) break; RCU_INIT_POINTER(fnew->next, rtnl_dereference(pfp->next)); rcu_assign_pointer(*fp, fnew); call_rcu(&f->rcu, fw_delete_filter); *arg = (unsigned long)fnew; return err; } if (!handle) Loading @@ -252,9 +297,7 @@ static int fw_change(struct net *net, struct sk_buff *in_skb, return -ENOBUFS; head->mask = mask; tcf_tree_lock(tp); tp->root = head; tcf_tree_unlock(tp); rcu_assign_pointer(tp->root, head); } f = kzalloc(sizeof(struct fw_filter), GFP_KERNEL); Loading @@ -263,15 +306,14 @@ static int fw_change(struct net *net, struct sk_buff *in_skb, tcf_exts_init(&f->exts, TCA_FW_ACT, TCA_FW_POLICE); f->id = handle; f->tp = tp; err = fw_change_attrs(net, tp, f, tb, tca, base, ovr); if (err < 0) goto errout; f->next = head->ht[fw_hash(handle)]; tcf_tree_lock(tp); head->ht[fw_hash(handle)] = f; tcf_tree_unlock(tp); RCU_INIT_POINTER(f->next, head->ht[fw_hash(handle)]); rcu_assign_pointer(head->ht[fw_hash(handle)], f); *arg = (unsigned long)f; return 0; Loading @@ -283,7 +325,7 @@ static int fw_change(struct net *net, struct sk_buff *in_skb, static void fw_walk(struct tcf_proto *tp, struct tcf_walker *arg) { struct fw_head *head = tp->root; struct fw_head *head = rtnl_dereference(tp->root); int h; if (head == NULL) Loading @@ -295,7 +337,8 @@ static void fw_walk(struct tcf_proto *tp, struct tcf_walker *arg) for (h = 0; h < HTSIZE; h++) { struct fw_filter *f; for (f = head->ht[h]; f; f = f->next) { for (f = rtnl_dereference(head->ht[h]); f; f = rtnl_dereference(f->next)) { if (arg->count < arg->skip) { arg->count++; continue; Loading @@ -312,7 +355,7 @@ static void fw_walk(struct tcf_proto *tp, struct tcf_walker *arg) static int fw_dump(struct net *net, struct tcf_proto *tp, unsigned long fh, struct sk_buff *skb, struct tcmsg *t) { struct fw_head *head = tp->root; struct fw_head *head = rtnl_dereference(tp->root); struct fw_filter *f = (struct fw_filter *)fh; unsigned char *b = skb_tail_pointer(skb); struct nlattr *nest; Loading Loading
net/sched/cls_fw.c +77 −34 Original line number Diff line number Diff line Loading @@ -33,17 +33,20 @@ struct fw_head { u32 mask; struct fw_filter *ht[HTSIZE]; struct fw_filter __rcu *ht[HTSIZE]; struct rcu_head rcu; }; struct fw_filter { struct fw_filter *next; struct fw_filter __rcu *next; u32 id; struct tcf_result res; #ifdef CONFIG_NET_CLS_IND int ifindex; #endif /* CONFIG_NET_CLS_IND */ struct tcf_exts exts; struct tcf_proto *tp; struct rcu_head rcu; }; static u32 fw_hash(u32 handle) Loading @@ -56,14 +59,16 @@ static u32 fw_hash(u32 handle) static int fw_classify(struct sk_buff *skb, const struct tcf_proto *tp, struct tcf_result *res) { struct fw_head *head = tp->root; struct fw_head *head = rcu_dereference_bh(tp->root); struct fw_filter *f; int r; u32 id = skb->mark; if (head != NULL) { id &= head->mask; for (f = head->ht[fw_hash(id)]; f; f = f->next) { for (f = rcu_dereference_bh(head->ht[fw_hash(id)]); f; f = rcu_dereference_bh(f->next)) { if (f->id == id) { *res = f->res; #ifdef CONFIG_NET_CLS_IND Loading Loading @@ -92,13 +97,14 @@ static int fw_classify(struct sk_buff *skb, const struct tcf_proto *tp, static unsigned long fw_get(struct tcf_proto *tp, u32 handle) { struct fw_head *head = tp->root; struct fw_head *head = rtnl_dereference(tp->root); struct fw_filter *f; if (head == NULL) return 0; for (f = head->ht[fw_hash(handle)]; f; f = f->next) { f = rtnl_dereference(head->ht[fw_hash(handle)]); for (; f; f = rtnl_dereference(f->next)) { if (f->id == handle) return (unsigned long)f; } Loading @@ -114,8 +120,11 @@ static int fw_init(struct tcf_proto *tp) return 0; } static void fw_delete_filter(struct tcf_proto *tp, struct fw_filter *f) static void fw_delete_filter(struct rcu_head *head) { struct fw_filter *f = container_of(head, struct fw_filter, rcu); struct tcf_proto *tp = f->tp; tcf_unbind_filter(tp, &f->res); tcf_exts_destroy(tp, &f->exts); kfree(f); Loading @@ -123,7 +132,7 @@ static void fw_delete_filter(struct tcf_proto *tp, struct fw_filter *f) static void fw_destroy(struct tcf_proto *tp) { struct fw_head *head = tp->root; struct fw_head *head = rtnl_dereference(tp->root); struct fw_filter *f; int h; Loading @@ -131,29 +140,33 @@ static void fw_destroy(struct tcf_proto *tp) return; for (h = 0; h < HTSIZE; h++) { while ((f = head->ht[h]) != NULL) { head->ht[h] = f->next; fw_delete_filter(tp, f); while ((f = rtnl_dereference(head->ht[h])) != NULL) { RCU_INIT_POINTER(head->ht[h], rtnl_dereference(f->next)); call_rcu(&f->rcu, fw_delete_filter); } } kfree(head); RCU_INIT_POINTER(tp->root, NULL); kfree_rcu(head, rcu); } static int fw_delete(struct tcf_proto *tp, unsigned long arg) { struct fw_head *head = tp->root; struct fw_head *head = rtnl_dereference(tp->root); struct fw_filter *f = (struct fw_filter *)arg; struct fw_filter **fp; struct fw_filter __rcu **fp; struct fw_filter *pfp; if (head == NULL || f == NULL) goto out; for (fp = &head->ht[fw_hash(f->id)]; *fp; fp = &(*fp)->next) { if (*fp == f) { tcf_tree_lock(tp); *fp = f->next; tcf_tree_unlock(tp); fw_delete_filter(tp, f); fp = &head->ht[fw_hash(f->id)]; for (pfp = rtnl_dereference(*fp); pfp; fp = &pfp->next, pfp = rtnl_dereference(*fp)) { if (pfp == f) { RCU_INIT_POINTER(*fp, rtnl_dereference(f->next)); call_rcu(&f->rcu, fw_delete_filter); return 0; } } Loading @@ -171,7 +184,7 @@ static int fw_change_attrs(struct net *net, struct tcf_proto *tp, struct fw_filter *f, struct nlattr **tb, struct nlattr **tca, unsigned long base, bool ovr) { struct fw_head *head = tp->root; struct fw_head *head = rtnl_dereference(tp->root); struct tcf_exts e; u32 mask; int err; Loading Loading @@ -220,7 +233,7 @@ static int fw_change(struct net *net, struct sk_buff *in_skb, struct nlattr **tca, unsigned long *arg, bool ovr) { struct fw_head *head = tp->root; struct fw_head *head = rtnl_dereference(tp->root); struct fw_filter *f = (struct fw_filter *) *arg; struct nlattr *opt = tca[TCA_OPTIONS]; struct nlattr *tb[TCA_FW_MAX + 1]; Loading @@ -233,10 +246,42 @@ static int fw_change(struct net *net, struct sk_buff *in_skb, if (err < 0) return err; if (f != NULL) { if (f) { struct fw_filter *pfp, *fnew; struct fw_filter __rcu **fp; if (f->id != handle && handle) return -EINVAL; return fw_change_attrs(net, tp, f, tb, tca, base, ovr); fnew = kzalloc(sizeof(struct fw_filter), GFP_KERNEL); if (!fnew) return -ENOBUFS; fnew->id = f->id; fnew->res = f->res; #ifdef CONFIG_NET_CLS_IND fnew->ifindex = f->ifindex; #endif /* CONFIG_NET_CLS_IND */ fnew->tp = f->tp; err = fw_change_attrs(net, tp, fnew, tb, tca, base, ovr); if (err < 0) { kfree(fnew); return err; } fp = &head->ht[fw_hash(fnew->id)]; for (pfp = rtnl_dereference(*fp); pfp; fp = &pfp->next, pfp = rtnl_dereference(*fp)) if (pfp == f) break; RCU_INIT_POINTER(fnew->next, rtnl_dereference(pfp->next)); rcu_assign_pointer(*fp, fnew); call_rcu(&f->rcu, fw_delete_filter); *arg = (unsigned long)fnew; return err; } if (!handle) Loading @@ -252,9 +297,7 @@ static int fw_change(struct net *net, struct sk_buff *in_skb, return -ENOBUFS; head->mask = mask; tcf_tree_lock(tp); tp->root = head; tcf_tree_unlock(tp); rcu_assign_pointer(tp->root, head); } f = kzalloc(sizeof(struct fw_filter), GFP_KERNEL); Loading @@ -263,15 +306,14 @@ static int fw_change(struct net *net, struct sk_buff *in_skb, tcf_exts_init(&f->exts, TCA_FW_ACT, TCA_FW_POLICE); f->id = handle; f->tp = tp; err = fw_change_attrs(net, tp, f, tb, tca, base, ovr); if (err < 0) goto errout; f->next = head->ht[fw_hash(handle)]; tcf_tree_lock(tp); head->ht[fw_hash(handle)] = f; tcf_tree_unlock(tp); RCU_INIT_POINTER(f->next, head->ht[fw_hash(handle)]); rcu_assign_pointer(head->ht[fw_hash(handle)], f); *arg = (unsigned long)f; return 0; Loading @@ -283,7 +325,7 @@ static int fw_change(struct net *net, struct sk_buff *in_skb, static void fw_walk(struct tcf_proto *tp, struct tcf_walker *arg) { struct fw_head *head = tp->root; struct fw_head *head = rtnl_dereference(tp->root); int h; if (head == NULL) Loading @@ -295,7 +337,8 @@ static void fw_walk(struct tcf_proto *tp, struct tcf_walker *arg) for (h = 0; h < HTSIZE; h++) { struct fw_filter *f; for (f = head->ht[h]; f; f = f->next) { for (f = rtnl_dereference(head->ht[h]); f; f = rtnl_dereference(f->next)) { if (arg->count < arg->skip) { arg->count++; continue; Loading @@ -312,7 +355,7 @@ static void fw_walk(struct tcf_proto *tp, struct tcf_walker *arg) static int fw_dump(struct net *net, struct tcf_proto *tp, unsigned long fh, struct sk_buff *skb, struct tcmsg *t) { struct fw_head *head = tp->root; struct fw_head *head = rtnl_dereference(tp->root); struct fw_filter *f = (struct fw_filter *)fh; unsigned char *b = skb_tail_pointer(skb); struct nlattr *nest; Loading