diff options
author | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-09 09:38:59 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-09 09:38:59 -0800 |
commit | 99b48cff405333afe26ac603b37639c410a48e5d (patch) | |
tree | 31b427930317b1596ca6070585f66a108b722580 /net | |
parent | 200d018eff4be3a1fb9823441cfcebb7de86a677 (diff) | |
parent | d3dcc077bf88806201093f86325ec656e4dbfbce (diff) | |
download | op-kernel-dev-99b48cff405333afe26ac603b37639c410a48e5d.zip op-kernel-dev-99b48cff405333afe26ac603b37639c410a48e5d.tar.gz |
Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6:
[NETLINK]: Put {IFA,IFLA}_{RTA,PAYLOAD} macros back for userspace.
[NET_SCHED] sch_htb: turn intermediate classes into leaves
[NET_SCHED] sch_cbq: deactivating when grafting, purging etc.
[XFRM]: Fix XFRMGRP_REPORT to use correct multicast group.
[NET]: Force a cache line split in hh_cache in SMP.
[NETPOLL]: make arp replies through netpoll use mac address of sender
[NETLINK]: Restore API compatibility of address and neighbour bits
[AX.25]: Fix default address and broadcast address initialization.
[AX.25]: Constify ax25 utility functions
[BNX2]: Add an error check.
[NET]: Convert hh_lock to seqlock.
Diffstat (limited to 'net')
-rw-r--r-- | net/ax25/ax25_addr.c | 34 | ||||
-rw-r--r-- | net/core/neighbour.c | 11 | ||||
-rw-r--r-- | net/core/netpoll.c | 14 | ||||
-rw-r--r-- | net/ipv4/ip_output.c | 14 | ||||
-rw-r--r-- | net/ipv6/ip6_output.c | 17 | ||||
-rw-r--r-- | net/sched/sch_cbq.c | 21 | ||||
-rw-r--r-- | net/sched/sch_htb.c | 51 |
7 files changed, 114 insertions, 48 deletions
diff --git a/net/ax25/ax25_addr.c b/net/ax25/ax25_addr.c index 5f0896a..21a0616 100644 --- a/net/ax25/ax25_addr.c +++ b/net/ax25/ax25_addr.c @@ -29,17 +29,26 @@ #include <linux/interrupt.h> /* - * The null address is defined as a callsign of all spaces with an - * SSID of zero. + * The default broadcast address of an interface is QST-0; the default address + * is LINUX-1. The null address is defined as a callsign of all spaces with + * an SSID of zero. */ -ax25_address null_ax25_address = {{0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00}}; +const ax25_address ax25_bcast = + {{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, 0 << 1}}; +const ax25_address ax25_defaddr = + {{'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, 1 << 1}}; +const ax25_address null_ax25_address = + {{' ' << 1, ' ' << 1, ' ' << 1, ' ' << 1, ' ' << 1, ' ' << 1, 0 << 1}}; + +EXPORT_SYMBOL_GPL(ax25_bcast); +EXPORT_SYMBOL_GPL(ax25_defaddr); EXPORT_SYMBOL(null_ax25_address); /* * ax25 -> ascii conversion */ -char *ax2asc(char *buf, ax25_address *a) +char *ax2asc(char *buf, const ax25_address *a) { char c, *s; int n; @@ -72,7 +81,7 @@ EXPORT_SYMBOL(ax2asc); /* * ascii -> ax25 conversion */ -void asc2ax(ax25_address *addr, char *callsign) +void asc2ax(ax25_address *addr, const char *callsign) { char *s; int n; @@ -107,7 +116,7 @@ EXPORT_SYMBOL(asc2ax); /* * Compare two ax.25 addresses */ -int ax25cmp(ax25_address *a, ax25_address *b) +int ax25cmp(const ax25_address *a, const ax25_address *b) { int ct = 0; @@ -128,7 +137,7 @@ EXPORT_SYMBOL(ax25cmp); /* * Compare two AX.25 digipeater paths. */ -int ax25digicmp(ax25_digi *digi1, ax25_digi *digi2) +int ax25digicmp(const ax25_digi *digi1, const ax25_digi *digi2) { int i; @@ -149,7 +158,9 @@ int ax25digicmp(ax25_digi *digi1, ax25_digi *digi2) * Given an AX.25 address pull of to, from, digi list, command/response and the start of data * */ -unsigned char *ax25_addr_parse(unsigned char *buf, int len, ax25_address *src, ax25_address *dest, ax25_digi *digi, int *flags, int *dama) +const unsigned char *ax25_addr_parse(const unsigned char *buf, int len, + ax25_address *src, ax25_address *dest, ax25_digi *digi, int *flags, + int *dama) { int d = 0; @@ -204,7 +215,8 @@ unsigned char *ax25_addr_parse(unsigned char *buf, int len, ax25_address *src, a /* * Assemble an AX.25 header from the bits */ -int ax25_addr_build(unsigned char *buf, ax25_address *src, ax25_address *dest, ax25_digi *d, int flag, int modulus) +int ax25_addr_build(unsigned char *buf, const ax25_address *src, + const ax25_address *dest, const ax25_digi *d, int flag, int modulus) { int len = 0; int ct = 0; @@ -261,7 +273,7 @@ int ax25_addr_build(unsigned char *buf, ax25_address *src, ax25_address *dest, a return len; } -int ax25_addr_size(ax25_digi *dp) +int ax25_addr_size(const ax25_digi *dp) { if (dp == NULL) return 2 * AX25_ADDR_LEN; @@ -272,7 +284,7 @@ int ax25_addr_size(ax25_digi *dp) /* * Reverse Digipeat List. May not pass both parameters as same struct */ -void ax25_digi_invert(ax25_digi *in, ax25_digi *out) +void ax25_digi_invert(const ax25_digi *in, ax25_digi *out) { int ct; diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 0ab1987..e7300b6 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -577,9 +577,10 @@ void neigh_destroy(struct neighbour *neigh) while ((hh = neigh->hh) != NULL) { neigh->hh = hh->hh_next; hh->hh_next = NULL; - write_lock_bh(&hh->hh_lock); + + write_seqlock_bh(&hh->hh_lock); hh->hh_output = neigh_blackhole; - write_unlock_bh(&hh->hh_lock); + write_sequnlock_bh(&hh->hh_lock); if (atomic_dec_and_test(&hh->hh_refcnt)) kfree(hh); } @@ -897,9 +898,9 @@ static void neigh_update_hhs(struct neighbour *neigh) if (update) { for (hh = neigh->hh; hh; hh = hh->hh_next) { - write_lock_bh(&hh->hh_lock); + write_seqlock_bh(&hh->hh_lock); update(hh, neigh->dev, neigh->ha); - write_unlock_bh(&hh->hh_lock); + write_sequnlock_bh(&hh->hh_lock); } } } @@ -1089,7 +1090,7 @@ static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst, break; if (!hh && (hh = kzalloc(sizeof(*hh), GFP_ATOMIC)) != NULL) { - rwlock_init(&hh->hh_lock); + seqlock_init(&hh->hh_lock); hh->hh_type = protocol; atomic_set(&hh->hh_refcnt, 0); hh->hh_next = NULL; diff --git a/net/core/netpoll.c b/net/core/netpoll.c index b3c559b..8a27128 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -330,6 +330,7 @@ static void arp_reply(struct sk_buff *skb) unsigned char *arp_ptr; int size, type = ARPOP_REPLY, ptype = ETH_P_ARP; __be32 sip, tip; + unsigned char *sha; struct sk_buff *send_skb; struct netpoll *np = NULL; @@ -356,9 +357,14 @@ static void arp_reply(struct sk_buff *skb) arp->ar_op != htons(ARPOP_REQUEST)) return; - arp_ptr = (unsigned char *)(arp+1) + skb->dev->addr_len; + arp_ptr = (unsigned char *)(arp+1); + /* save the location of the src hw addr */ + sha = arp_ptr; + arp_ptr += skb->dev->addr_len; memcpy(&sip, arp_ptr, 4); - arp_ptr += 4 + skb->dev->addr_len; + arp_ptr += 4; + /* if we actually cared about dst hw addr, it would get copied here */ + arp_ptr += skb->dev->addr_len; memcpy(&tip, arp_ptr, 4); /* Should we ignore arp? */ @@ -381,7 +387,7 @@ static void arp_reply(struct sk_buff *skb) if (np->dev->hard_header && np->dev->hard_header(send_skb, skb->dev, ptype, - np->remote_mac, np->local_mac, + sha, np->local_mac, send_skb->len) < 0) { kfree_skb(send_skb); return; @@ -405,7 +411,7 @@ static void arp_reply(struct sk_buff *skb) arp_ptr += np->dev->addr_len; memcpy(arp_ptr, &tip, 4); arp_ptr += 4; - memcpy(arp_ptr, np->remote_mac, np->dev->addr_len); + memcpy(arp_ptr, sha, np->dev->addr_len); arp_ptr += np->dev->addr_len; memcpy(arp_ptr, &sip, 4); diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index a35209d..f071f84 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -164,7 +164,6 @@ EXPORT_SYMBOL_GPL(ip_build_and_send_pkt); static inline int ip_finish_output2(struct sk_buff *skb) { struct dst_entry *dst = skb->dst; - struct hh_cache *hh = dst->hh; struct net_device *dev = dst->dev; int hh_len = LL_RESERVED_SPACE(dev); @@ -183,16 +182,9 @@ static inline int ip_finish_output2(struct sk_buff *skb) skb = skb2; } - if (hh) { - int hh_alen; - - read_lock_bh(&hh->hh_lock); - hh_alen = HH_DATA_ALIGN(hh->hh_len); - memcpy(skb->data - hh_alen, hh->hh_data, hh_alen); - read_unlock_bh(&hh->hh_lock); - skb_push(skb, hh->hh_len); - return hh->hh_output(skb); - } else if (dst->neighbour) + if (dst->hh) + return neigh_hh_output(dst->hh, skb); + else if (dst->neighbour) return dst->neighbour->output(skb); if (net_ratelimit()) diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index e9212c7..7b7bd44 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -72,20 +72,11 @@ static __inline__ void ipv6_select_ident(struct sk_buff *skb, struct frag_hdr *f static inline int ip6_output_finish(struct sk_buff *skb) { - struct dst_entry *dst = skb->dst; - struct hh_cache *hh = dst->hh; - - if (hh) { - int hh_alen; - - read_lock_bh(&hh->hh_lock); - hh_alen = HH_DATA_ALIGN(hh->hh_len); - memcpy(skb->data - hh_alen, hh->hh_data, hh_alen); - read_unlock_bh(&hh->hh_lock); - skb_push(skb, hh->hh_len); - return hh->hh_output(skb); - } else if (dst->neighbour) + + if (dst->hh) + return neigh_hh_output(dst->hh, skb); + else if (dst->neighbour) return dst->neighbour->output(skb); IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index ba82dfa..f79a4f3 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -371,8 +371,6 @@ static void cbq_deactivate_class(struct cbq_class *this) return; } } - - cl = cl_prev->next_alive; return; } } while ((cl_prev = cl) != q->active[prio]); @@ -1258,6 +1256,8 @@ static unsigned int cbq_drop(struct Qdisc* sch) do { if (cl->q->ops->drop && (len = cl->q->ops->drop(cl->q))) { sch->q.qlen--; + if (!cl->q->q.qlen) + cbq_deactivate_class(cl); return len; } } while ((cl = cl->next_alive) != cl_head); @@ -1685,8 +1685,7 @@ static int cbq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, #endif } sch_tree_lock(sch); - *old = cl->q; - cl->q = new; + *old = xchg(&cl->q, new); qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); qdisc_reset(*old); sch_tree_unlock(sch); @@ -1704,6 +1703,14 @@ cbq_leaf(struct Qdisc *sch, unsigned long arg) return cl ? cl->q : NULL; } +static void cbq_qlen_notify(struct Qdisc *sch, unsigned long arg) +{ + struct cbq_class *cl = (struct cbq_class *)arg; + + if (cl->q->q.qlen == 0) + cbq_deactivate_class(cl); +} + static unsigned long cbq_get(struct Qdisc *sch, u32 classid) { struct cbq_sched_data *q = qdisc_priv(sch); @@ -1988,12 +1995,17 @@ static int cbq_delete(struct Qdisc *sch, unsigned long arg) { struct cbq_sched_data *q = qdisc_priv(sch); struct cbq_class *cl = (struct cbq_class*)arg; + unsigned int qlen; if (cl->filters || cl->children || cl == &q->link) return -EBUSY; sch_tree_lock(sch); + qlen = cl->q->q.qlen; + qdisc_reset(cl->q); + qdisc_tree_decrease_qlen(cl->q, qlen); + if (cl->next_alive) cbq_deactivate_class(cl); @@ -2084,6 +2096,7 @@ static void cbq_walk(struct Qdisc *sch, struct qdisc_walker *arg) static struct Qdisc_class_ops cbq_class_ops = { .graft = cbq_graft, .leaf = cbq_leaf, + .qlen_notify = cbq_qlen_notify, .get = cbq_get, .put = cbq_put, .change = cbq_change_class, diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 215e68c..15f23c5 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -147,6 +147,10 @@ struct htb_class { psched_tdiff_t mbuffer; /* max wait time */ long tokens, ctokens; /* current number of tokens */ psched_time_t t_c; /* checkpoint time */ + + int prio; /* For parent to leaf return possible here */ + int quantum; /* we do backup. Finally full replacement */ + /* of un.leaf originals should be done. */ }; /* TODO: maybe compute rate when size is too large .. or drop ? */ @@ -1271,6 +1275,38 @@ static void htb_destroy_filters(struct tcf_proto **fl) } } +static inline int htb_parent_last_child(struct htb_class *cl) +{ + if (!cl->parent) + /* the root class */ + return 0; + + if (!(cl->parent->children.next == &cl->sibling && + cl->parent->children.prev == &cl->sibling)) + /* not the last child */ + return 0; + + return 1; +} + +static void htb_parent_to_leaf(struct htb_class *cl, struct Qdisc *new_q) +{ + struct htb_class *parent = cl->parent; + + BUG_TRAP(!cl->level && cl->un.leaf.q && !cl->prio_activity); + + parent->level = 0; + memset(&parent->un.inner, 0, sizeof(parent->un.inner)); + INIT_LIST_HEAD(&parent->un.leaf.drop_list); + parent->un.leaf.q = new_q ? new_q : &noop_qdisc; + parent->un.leaf.quantum = parent->quantum; + parent->un.leaf.prio = parent->prio; + parent->tokens = parent->buffer; + parent->ctokens = parent->cbuffer; + PSCHED_GET_TIME(parent->t_c); + parent->cmode = HTB_CAN_SEND; +} + static void htb_destroy_class(struct Qdisc *sch, struct htb_class *cl) { struct htb_sched *q = qdisc_priv(sch); @@ -1328,6 +1364,8 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg) struct htb_sched *q = qdisc_priv(sch); struct htb_class *cl = (struct htb_class *)arg; unsigned int qlen; + struct Qdisc *new_q = NULL; + int last_child = 0; // TODO: why don't allow to delete subtree ? references ? does // tc subsys quarantee us that in htb_destroy it holds no class @@ -1335,6 +1373,12 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg) if (!list_empty(&cl->children) || cl->filter_cnt) return -EBUSY; + if (!cl->level && htb_parent_last_child(cl)) { + new_q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, + cl->parent->classid); + last_child = 1; + } + sch_tree_lock(sch); /* delete from hash and active; remainder in destroy_class */ @@ -1349,6 +1393,9 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg) if (cl->prio_activity) htb_deactivate(q, cl); + if (last_child) + htb_parent_to_leaf(cl, new_q); + if (--cl->refcnt == 0) htb_destroy_class(sch, cl); @@ -1483,6 +1530,10 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, cl->un.leaf.quantum = hopt->quantum; if ((cl->un.leaf.prio = hopt->prio) >= TC_HTB_NUMPRIO) cl->un.leaf.prio = TC_HTB_NUMPRIO - 1; + + /* backup for htb_parent_to_leaf */ + cl->quantum = cl->un.leaf.quantum; + cl->prio = cl->un.leaf.prio; } cl->buffer = hopt->buffer; |