Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'net_sched-next'

John Fastabend says:

====================
net sched rcu updates

This fixes the use of tcf_proto from RCU callbacks it requires
moving the unbind calls out of the callbacks and removing the
tcf_proto argument from the tcf_em_tree_destroy().

This is a rework of two previous series and addresses comments
from Cong. And should apply against latest net-next.

The previous series links below for reference:

(1/2) net: sched: do not use tcf_proto 'tp' argument from call_rcu
http://patchwork.ozlabs.org/patch/396149/

(2/2) net: sched: replace ematch calls to use struct net
http://patchwork.ozlabs.org/patch/396150/

net: sched: cls_cgroup tear down exts and ematch from rcu callback
http://patchwork.ozlabs.org/patch/396307/
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+40 -35
+5 -5
include/net/pkt_cls.h
··· 166 166 unsigned int datalen; 167 167 u16 matchid; 168 168 u16 flags; 169 + struct net *net; 169 170 }; 170 171 171 172 static inline int tcf_em_is_container(struct tcf_ematch *em) ··· 230 229 struct tcf_ematch_ops { 231 230 int kind; 232 231 int datalen; 233 - int (*change)(struct tcf_proto *, void *, 232 + int (*change)(struct net *net, void *, 234 233 int, struct tcf_ematch *); 235 234 int (*match)(struct sk_buff *, struct tcf_ematch *, 236 235 struct tcf_pkt_info *); 237 - void (*destroy)(struct tcf_proto *, 238 - struct tcf_ematch *); 236 + void (*destroy)(struct tcf_ematch *); 239 237 int (*dump)(struct sk_buff *, struct tcf_ematch *); 240 238 struct module *owner; 241 239 struct list_head link; ··· 244 244 void tcf_em_unregister(struct tcf_ematch_ops *); 245 245 int tcf_em_tree_validate(struct tcf_proto *, struct nlattr *, 246 246 struct tcf_ematch_tree *); 247 - void tcf_em_tree_destroy(struct tcf_proto *, struct tcf_ematch_tree *); 247 + void tcf_em_tree_destroy(struct tcf_ematch_tree *); 248 248 int tcf_em_tree_dump(struct sk_buff *, struct tcf_ematch_tree *, int); 249 249 int __tcf_em_tree_match(struct sk_buff *, struct tcf_ematch_tree *, 250 250 struct tcf_pkt_info *); ··· 301 301 }; 302 302 303 303 #define tcf_em_tree_validate(tp, tb, t) ((void)(t), 0) 304 - #define tcf_em_tree_destroy(tp, t) do { (void)(t); } while(0) 304 + #define tcf_em_tree_destroy(t) do { (void)(t); } while(0) 305 305 #define tcf_em_tree_dump(skb, t, tlv) (0) 306 306 #define tcf_em_tree_change(tp, dst, src) do { } while(0) 307 307 #define tcf_em_tree_match(skb, t, info) ((void)(info), 1)
+4 -3
net/sched/cls_basic.c
··· 91 91 static void basic_delete_filter(struct rcu_head *head) 92 92 { 93 93 struct basic_filter *f = container_of(head, struct basic_filter, rcu); 94 - struct tcf_proto *tp = f->tp; 95 94 96 - tcf_unbind_filter(tp, &f->res); 97 95 tcf_exts_destroy(&f->exts); 98 - tcf_em_tree_destroy(tp, &f->ematches); 96 + tcf_em_tree_destroy(&f->ematches); 99 97 kfree(f); 100 98 } 101 99 ··· 104 106 105 107 list_for_each_entry_safe(f, n, &head->flist, link) { 106 108 list_del_rcu(&f->link); 109 + tcf_unbind_filter(tp, &f->res); 107 110 call_rcu(&f->rcu, basic_delete_filter); 108 111 } 109 112 RCU_INIT_POINTER(tp->root, NULL); ··· 119 120 list_for_each_entry(t, &head->flist, link) 120 121 if (t == f) { 121 122 list_del_rcu(&t->link); 123 + tcf_unbind_filter(tp, &t->res); 122 124 call_rcu(&t->rcu, basic_delete_filter); 123 125 return 0; 124 126 } ··· 222 222 223 223 if (fold) { 224 224 list_replace_rcu(&fold->link, &fnew->link); 225 + tcf_unbind_filter(tp, &fold->res); 225 226 call_rcu(&fold->rcu, basic_delete_filter); 226 227 } else { 227 228 list_add_rcu(&fnew->link, &head->flist);
+3 -1
net/sched/cls_bpf.c
··· 92 92 93 93 static void cls_bpf_delete_prog(struct tcf_proto *tp, struct cls_bpf_prog *prog) 94 94 { 95 - tcf_unbind_filter(tp, &prog->res); 96 95 tcf_exts_destroy(&prog->exts); 97 96 98 97 bpf_prog_destroy(prog->filter); ··· 115 116 list_for_each_entry(prog, &head->plist, link) { 116 117 if (prog == todel) { 117 118 list_del_rcu(&prog->link); 119 + tcf_unbind_filter(tp, &prog->res); 118 120 call_rcu(&prog->rcu, __cls_bpf_delete_prog); 119 121 return 0; 120 122 } ··· 131 131 132 132 list_for_each_entry_safe(prog, tmp, &head->plist, link) { 133 133 list_del_rcu(&prog->link); 134 + tcf_unbind_filter(tp, &prog->res); 134 135 call_rcu(&prog->rcu, __cls_bpf_delete_prog); 135 136 } 136 137 ··· 283 282 284 283 if (oldprog) { 285 284 list_replace_rcu(&prog->link, &oldprog->link); 285 + tcf_unbind_filter(tp, &oldprog->res); 286 286 call_rcu(&oldprog->rcu, __cls_bpf_delete_prog); 287 287 } else { 288 288 list_add_rcu(&prog->link, &head->plist);
+2 -4
net/sched/cls_cgroup.c
··· 87 87 rcu); 88 88 89 89 tcf_exts_destroy(&head->exts); 90 - tcf_em_tree_destroy(head->tp, &head->ematches); 90 + tcf_em_tree_destroy(&head->ematches); 91 91 kfree(head); 92 92 } 93 93 ··· 156 156 struct cls_cgroup_head *head = rtnl_dereference(tp->root); 157 157 158 158 if (head) { 159 - tcf_exts_destroy(&head->exts); 160 - tcf_em_tree_destroy(tp, &head->ematches); 161 159 RCU_INIT_POINTER(tp->root, NULL); 162 - kfree_rcu(head, rcu); 160 + call_rcu(&head->rcu, cls_cgroup_destroy_rcu); 163 161 } 164 162 } 165 163
+2 -2
net/sched/cls_flow.c
··· 355 355 356 356 del_timer_sync(&f->perturb_timer); 357 357 tcf_exts_destroy(&f->exts); 358 - tcf_em_tree_destroy(f->tp, &f->ematches); 358 + tcf_em_tree_destroy(&f->ematches); 359 359 kfree(f); 360 360 } 361 361 ··· 530 530 return 0; 531 531 532 532 err2: 533 - tcf_em_tree_destroy(tp, &t); 533 + tcf_em_tree_destroy(&t); 534 534 kfree(fnew); 535 535 err1: 536 536 tcf_exts_destroy(&e);
+3 -2
net/sched/cls_fw.c
··· 123 123 static void fw_delete_filter(struct rcu_head *head) 124 124 { 125 125 struct fw_filter *f = container_of(head, struct fw_filter, rcu); 126 - struct tcf_proto *tp = f->tp; 127 126 128 - tcf_unbind_filter(tp, &f->res); 129 127 tcf_exts_destroy(&f->exts); 130 128 kfree(f); 131 129 } ··· 141 143 while ((f = rtnl_dereference(head->ht[h])) != NULL) { 142 144 RCU_INIT_POINTER(head->ht[h], 143 145 rtnl_dereference(f->next)); 146 + tcf_unbind_filter(tp, &f->res); 144 147 call_rcu(&f->rcu, fw_delete_filter); 145 148 } 146 149 } ··· 165 166 fp = &pfp->next, pfp = rtnl_dereference(*fp)) { 166 167 if (pfp == f) { 167 168 RCU_INIT_POINTER(*fp, rtnl_dereference(f->next)); 169 + tcf_unbind_filter(tp, &f->res); 168 170 call_rcu(&f->rcu, fw_delete_filter); 169 171 return 0; 170 172 } ··· 280 280 281 281 RCU_INIT_POINTER(fnew->next, rtnl_dereference(pfp->next)); 282 282 rcu_assign_pointer(*fp, fnew); 283 + tcf_unbind_filter(tp, &f->res); 283 284 call_rcu(&f->rcu, fw_delete_filter); 284 285 285 286 *arg = (unsigned long)fnew;
+5 -3
net/sched/cls_route.c
··· 269 269 route4_delete_filter(struct rcu_head *head) 270 270 { 271 271 struct route4_filter *f = container_of(head, struct route4_filter, rcu); 272 - struct tcf_proto *tp = f->tp; 273 272 274 - tcf_unbind_filter(tp, &f->res); 275 273 tcf_exts_destroy(&f->exts); 276 274 kfree(f); 277 275 } ··· 295 297 296 298 next = rtnl_dereference(f->next); 297 299 RCU_INIT_POINTER(b->ht[h2], next); 300 + tcf_unbind_filter(tp, &f->res); 298 301 call_rcu(&f->rcu, route4_delete_filter); 299 302 } 300 303 } ··· 337 338 route4_reset_fastmap(head); 338 339 339 340 /* Delete it */ 341 + tcf_unbind_filter(tp, &f->res); 340 342 call_rcu(&f->rcu, route4_delete_filter); 341 343 342 344 /* Strip RTNL protected tree */ ··· 545 545 546 546 route4_reset_fastmap(head); 547 547 *arg = (unsigned long)f; 548 - if (fold) 548 + if (fold) { 549 + tcf_unbind_filter(tp, &fold->res); 549 550 call_rcu(&fold->rcu, route4_delete_filter); 551 + } 550 552 return 0; 551 553 552 554 errout:
+2 -2
net/sched/em_canid.c
··· 120 120 return match; 121 121 } 122 122 123 - static int em_canid_change(struct tcf_proto *tp, void *data, int len, 123 + static int em_canid_change(struct net *net, void *data, int len, 124 124 struct tcf_ematch *m) 125 125 { 126 126 struct can_filter *conf = data; /* Array with rules */ ··· 183 183 return 0; 184 184 } 185 185 186 - static void em_canid_destroy(struct tcf_proto *tp, struct tcf_ematch *m) 186 + static void em_canid_destroy(struct tcf_ematch *m) 187 187 { 188 188 struct canid_match *cm = em_canid_priv(m); 189 189
+3 -4
net/sched/em_ipset.c
··· 19 19 #include <net/ip.h> 20 20 #include <net/pkt_cls.h> 21 21 22 - static int em_ipset_change(struct tcf_proto *tp, void *data, int data_len, 22 + static int em_ipset_change(struct net *net, void *data, int data_len, 23 23 struct tcf_ematch *em) 24 24 { 25 25 struct xt_set_info *set = data; 26 26 ip_set_id_t index; 27 - struct net *net = dev_net(qdisc_dev(tp->q)); 28 27 29 28 if (data_len != sizeof(*set)) 30 29 return -EINVAL; ··· 41 42 return -ENOMEM; 42 43 } 43 44 44 - static void em_ipset_destroy(struct tcf_proto *p, struct tcf_ematch *em) 45 + static void em_ipset_destroy(struct tcf_ematch *em) 45 46 { 46 47 const struct xt_set_info *set = (const void *) em->data; 47 48 if (set) { 48 - ip_set_nfnl_put(dev_net(qdisc_dev(p->q)), set->index); 49 + ip_set_nfnl_put(em->net, set->index); 49 50 kfree((void *) em->data); 50 51 } 51 52 }
+2 -2
net/sched/em_meta.c
··· 856 856 [TCA_EM_META_HDR] = { .len = sizeof(struct tcf_meta_hdr) }, 857 857 }; 858 858 859 - static int em_meta_change(struct tcf_proto *tp, void *data, int len, 859 + static int em_meta_change(struct net *net, void *data, int len, 860 860 struct tcf_ematch *m) 861 861 { 862 862 int err; ··· 908 908 return err; 909 909 } 910 910 911 - static void em_meta_destroy(struct tcf_proto *tp, struct tcf_ematch *m) 911 + static void em_meta_destroy(struct tcf_ematch *m) 912 912 { 913 913 if (m) 914 914 meta_delete((struct meta_match *) m->data);
+1 -1
net/sched/em_nbyte.c
··· 23 23 char pattern[0]; 24 24 }; 25 25 26 - static int em_nbyte_change(struct tcf_proto *tp, void *data, int data_len, 26 + static int em_nbyte_change(struct net *net, void *data, int data_len, 27 27 struct tcf_ematch *em) 28 28 { 29 29 struct tcf_em_nbyte *nbyte = data;
+2 -2
net/sched/em_text.c
··· 45 45 return skb_find_text(skb, from, to, tm->config, &state) != UINT_MAX; 46 46 } 47 47 48 - static int em_text_change(struct tcf_proto *tp, void *data, int len, 48 + static int em_text_change(struct net *net, void *data, int len, 49 49 struct tcf_ematch *m) 50 50 { 51 51 struct text_match *tm; ··· 100 100 return 0; 101 101 } 102 102 103 - static void em_text_destroy(struct tcf_proto *tp, struct tcf_ematch *m) 103 + static void em_text_destroy(struct tcf_ematch *m) 104 104 { 105 105 if (EM_TEXT_PRIV(m) && EM_TEXT_PRIV(m)->config) 106 106 textsearch_destroy(EM_TEXT_PRIV(m)->config);
+6 -4
net/sched/ematch.c
··· 178 178 struct tcf_ematch_hdr *em_hdr = nla_data(nla); 179 179 int data_len = nla_len(nla) - sizeof(*em_hdr); 180 180 void *data = (void *) em_hdr + sizeof(*em_hdr); 181 + struct net *net = dev_net(qdisc_dev(tp->q)); 181 182 182 183 if (!TCF_EM_REL_VALID(em_hdr->flags)) 183 184 goto errout; ··· 241 240 goto errout; 242 241 243 242 if (em->ops->change) { 244 - err = em->ops->change(tp, data, data_len, em); 243 + err = em->ops->change(net, data, data_len, em); 245 244 if (err < 0) 246 245 goto errout; 247 246 } else if (data_len > 0) { ··· 272 271 em->matchid = em_hdr->matchid; 273 272 em->flags = em_hdr->flags; 274 273 em->datalen = data_len; 274 + em->net = net; 275 275 276 276 err = 0; 277 277 errout: ··· 380 378 return err; 381 379 382 380 errout_abort: 383 - tcf_em_tree_destroy(tp, tree); 381 + tcf_em_tree_destroy(tree); 384 382 return err; 385 383 } 386 384 EXPORT_SYMBOL(tcf_em_tree_validate); ··· 395 393 * tcf_em_tree_validate()/tcf_em_tree_change(). You must ensure that 396 394 * the ematch tree is not in use before calling this function. 397 395 */ 398 - void tcf_em_tree_destroy(struct tcf_proto *tp, struct tcf_ematch_tree *tree) 396 + void tcf_em_tree_destroy(struct tcf_ematch_tree *tree) 399 397 { 400 398 int i; 401 399 ··· 407 405 408 406 if (em->ops) { 409 407 if (em->ops->destroy) 410 - em->ops->destroy(tp, em); 408 + em->ops->destroy(em); 411 409 else if (!tcf_em_is_simple(em)) 412 410 kfree((void *) em->data); 413 411 module_put(em->ops->owner);