From 42e33148df38c60b99d984b76b302c64397ebe4c Mon Sep 17 00:00:00 2001 From: "James.Smart@Emulex.Com" Date: Thu, 15 Dec 2005 09:56:22 -0500 Subject: [SCSI] fix for fc transport recursion problem. In the scenario that a link was broken, the devloss timer for each rport was expire at roughly the same time, causing lots of "delete" workqueue items being queued. Depth is dependent upon the number of rports that were on the link. The rport target remove calls were calling flush_scheduled_work(), which would interrupt the stream, and start the next workqueue item, which did the same thing, and so on until recursion depth was large. This fix stops the recursion in the initial delete path, and pushes it off to a host-level work item that reaps the dead rports. Signed-off-by: James Bottomley --- include/scsi/scsi_transport_fc.h | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'include') diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h index fac547d32a98..394f14a5b7cb 100644 --- a/include/scsi/scsi_transport_fc.h +++ b/include/scsi/scsi_transport_fc.h @@ -79,6 +79,7 @@ enum fc_port_state { FC_PORTSTATE_LINKDOWN, FC_PORTSTATE_ERROR, FC_PORTSTATE_LOOPBACK, + FC_PORTSTATE_DELETED, }; @@ -325,8 +326,14 @@ struct fc_host_attrs { struct list_head rport_bindings; u32 next_rport_number; u32 next_target_id; + u8 flags; + struct work_struct rport_del_work; }; +/* values for struct fc_host_attrs "flags" field: */ +#define FC_SHOST_RPORT_DEL_SCHEDULED 0x01 + + #define fc_host_node_name(x) \ (((struct fc_host_attrs *)(x)->shost_data)->node_name) #define fc_host_port_name(x) \ @@ -365,6 +372,10 @@ struct fc_host_attrs { (((struct fc_host_attrs *)(x)->shost_data)->next_rport_number) #define fc_host_next_target_id(x) \ (((struct fc_host_attrs *)(x)->shost_data)->next_target_id) +#define fc_host_flags(x) \ + (((struct fc_host_attrs *)(x)->shost_data)->flags) +#define fc_host_rport_del_work(x) \ + (((struct fc_host_attrs *)(x)->shost_data)->rport_del_work) /* The functions by which the transport class and the driver communicate */ -- cgit v1.2.3-59-g8ed1b From 6b80ebedbee87c5b2213fc3635bf0bd7450bce30 Mon Sep 17 00:00:00 2001 From: Kristian Slavov Date: Mon, 19 Dec 2005 13:54:44 -0800 Subject: [RTNETLINK]: Fix RTNLGRP definitions in rtnetlink.h I reported a problem and gave hints to the solution, but nobody seemed to react. So I prepared a patch against 2.6.14.4. Tested on 2.6.14.4 with "ip monitor addr" and with the program attached, while adding and removing IPv6 address. Both programs didn't receive any messages. Tested 2.6.14.4 + this patch, and both programs received add and remove messages. Signed-off-by: Kristian Slavov Acked-by: Jamal Hadi salim ACKed-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/rtnetlink.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include') diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index c231e9a08f0b..d50482ba27fe 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -866,6 +866,7 @@ enum rtnetlink_groups { #define RTNLGRP_IPV4_MROUTE RTNLGRP_IPV4_MROUTE RTNLGRP_IPV4_ROUTE, #define RTNLGRP_IPV4_ROUTE RTNLGRP_IPV4_ROUTE + RTNLGRP_NOP1, RTNLGRP_IPV6_IFADDR, #define RTNLGRP_IPV6_IFADDR RTNLGRP_IPV6_IFADDR RTNLGRP_IPV6_MROUTE, @@ -876,8 +877,11 @@ enum rtnetlink_groups { #define RTNLGRP_IPV6_IFINFO RTNLGRP_IPV6_IFINFO RTNLGRP_DECnet_IFADDR, #define RTNLGRP_DECnet_IFADDR RTNLGRP_DECnet_IFADDR + RTNLGRP_NOP2, RTNLGRP_DECnet_ROUTE, #define RTNLGRP_DECnet_ROUTE RTNLGRP_DECnet_ROUTE + RTNLGRP_NOP3, + RTNLGRP_NOP4, RTNLGRP_IPV6_PREFIX, #define RTNLGRP_IPV6_PREFIX RTNLGRP_IPV6_PREFIX __RTNLGRP_MAX -- cgit v1.2.3-59-g8ed1b From 399c180ac5f0cb66ef9479358e0b8b6bafcbeafe Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 19 Dec 2005 14:23:23 -0800 Subject: [IPSEC]: Perform SA switchover immediately. When we insert a new xfrm_state which potentially subsumes an existing one, make sure all cached bundles are flushed so that the new SA is used immediately. Signed-off-by: David S. Miller --- include/net/xfrm.h | 1 + net/xfrm/xfrm_policy.c | 19 ++++++++++++++----- net/xfrm/xfrm_state.c | 5 +++++ 3 files changed, 20 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 5beae1ccd574..1cdb87912137 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -890,6 +890,7 @@ struct xfrm_state * xfrm_find_acq(u8 mode, u32 reqid, u8 proto, extern void xfrm_policy_flush(void); extern int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol); extern int xfrm_flush_bundles(void); +extern void xfrm_flush_all_bundles(void); extern int xfrm_bundle_ok(struct xfrm_dst *xdst, struct flowi *fl, int family); extern void xfrm_init_pmtu(struct dst_entry *dst); diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 0db9e57013fd..54a4be6a7d26 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -1014,13 +1014,12 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family) } EXPORT_SYMBOL(__xfrm_route_forward); -/* Optimize later using cookies and generation ids. */ - static struct dst_entry *xfrm_dst_check(struct dst_entry *dst, u32 cookie) { - if (!stale_bundle(dst)) - return dst; - + /* If it is marked obsolete, which is how we even get here, + * then we have purged it from the policy bundle list and we + * did that for a good reason. + */ return NULL; } @@ -1104,6 +1103,16 @@ int xfrm_flush_bundles(void) return 0; } +static int always_true(struct dst_entry *dst) +{ + return 1; +} + +void xfrm_flush_all_bundles(void) +{ + xfrm_prune_bundles(always_true); +} + void xfrm_init_pmtu(struct dst_entry *dst) { do { diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 7cf48aa6c95b..479effc97666 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -431,6 +431,8 @@ void xfrm_state_insert(struct xfrm_state *x) spin_lock_bh(&xfrm_state_lock); __xfrm_state_insert(x); spin_unlock_bh(&xfrm_state_lock); + + xfrm_flush_all_bundles(); } EXPORT_SYMBOL(xfrm_state_insert); @@ -478,6 +480,9 @@ out: spin_unlock_bh(&xfrm_state_lock); xfrm_state_put_afinfo(afinfo); + if (!err) + xfrm_flush_all_bundles(); + if (x1) { xfrm_state_delete(x1); xfrm_state_put(x1); -- cgit v1.2.3-59-g8ed1b From 29884df0d89c1df0dec3449405bc41569bb44800 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 13 Dec 2005 16:13:54 -0500 Subject: NFS: Fix another O_DIRECT race Ensure we call unmap_mapping_range() and sync dirty pages to disk before doing an NFS direct write. Signed-off-by: Trond Myklebust --- fs/nfs/direct.c | 24 ++++++------------------ fs/nfs/file.c | 23 ++++------------------- fs/nfs/inode.c | 28 +++++++++++++++++++++++----- include/linux/nfs_fs.h | 1 + 4 files changed, 34 insertions(+), 42 deletions(-) (limited to 'include') diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index b497c71384e8..079228817603 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -678,15 +678,9 @@ nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t if (!count) goto out; - if (mapping->nrpages) { - retval = filemap_fdatawrite(mapping); - if (retval == 0) - retval = nfs_wb_all(inode); - if (retval == 0) - retval = filemap_fdatawait(mapping); - if (retval) - goto out; - } + retval = nfs_sync_mapping(mapping); + if (retval) + goto out; retval = nfs_direct_read(inode, ctx, &iov, pos, 1); if (retval > 0) @@ -764,15 +758,9 @@ nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, if (!count) goto out; - if (mapping->nrpages) { - retval = filemap_fdatawrite(mapping); - if (retval == 0) - retval = nfs_wb_all(inode); - if (retval == 0) - retval = filemap_fdatawait(mapping); - if (retval) - goto out; - } + retval = nfs_sync_mapping(mapping); + if (retval) + goto out; retval = nfs_direct_write(inode, ctx, &iov, pos, 1); if (mapping->nrpages) diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 57d3e77d97ee..eb5cd4c3bbfd 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -433,11 +433,7 @@ static int do_unlk(struct file *filp, int cmd, struct file_lock *fl) * Flush all pending writes before doing anything * with locks.. */ - filemap_fdatawrite(filp->f_mapping); - down(&inode->i_sem); - nfs_wb_all(inode); - up(&inode->i_sem); - filemap_fdatawait(filp->f_mapping); + nfs_sync_mapping(filp->f_mapping); /* NOTE: special case * If we're signalled while cleaning up locks on process exit, we @@ -465,15 +461,8 @@ static int do_setlk(struct file *filp, int cmd, struct file_lock *fl) * Flush all pending writes before doing anything * with locks.. */ - status = filemap_fdatawrite(filp->f_mapping); - if (status == 0) { - down(&inode->i_sem); - status = nfs_wb_all(inode); - up(&inode->i_sem); - if (status == 0) - status = filemap_fdatawait(filp->f_mapping); - } - if (status < 0) + status = nfs_sync_mapping(filp->f_mapping); + if (status != 0) goto out; lock_kernel(); @@ -497,11 +486,7 @@ static int do_setlk(struct file *filp, int cmd, struct file_lock *fl) * Make sure we clear the cache whenever we try to get the lock. * This makes locking act as a cache coherency point. */ - filemap_fdatawrite(filp->f_mapping); - down(&inode->i_sem); - nfs_wb_all(inode); /* we may have slept */ - up(&inode->i_sem); - filemap_fdatawait(filp->f_mapping); + nfs_sync_mapping(filp->f_mapping); nfs_zap_caches(inode); out: rpc_clnt_sigunmask(NFS_CLIENT(inode), &oldset); diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index afd75d0463fd..432f41cd75e6 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -640,6 +640,27 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt) return 0; } +/** + * nfs_sync_mapping - helper to flush all mmapped dirty data to disk + */ +int nfs_sync_mapping(struct address_space *mapping) +{ + int ret; + + if (mapping->nrpages == 0) + return 0; + unmap_mapping_range(mapping, 0, 0, 0); + ret = filemap_fdatawrite(mapping); + if (ret != 0) + goto out; + ret = filemap_fdatawait(mapping); + if (ret != 0) + goto out; + ret = nfs_wb_all(mapping->host); +out: + return ret; +} + /* * Invalidate the local caches */ @@ -1179,11 +1200,8 @@ void nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping) struct nfs_inode *nfsi = NFS_I(inode); if (nfsi->cache_validity & NFS_INO_INVALID_DATA) { - if (S_ISREG(inode->i_mode)) { - if (filemap_fdatawrite(mapping) == 0) - filemap_fdatawait(mapping); - nfs_wb_all(inode); - } + if (S_ISREG(inode->i_mode)) + nfs_sync_mapping(mapping); invalidate_inode_pages2(mapping); spin_lock(&inode->i_lock); diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 12787a9b0259..2516adeccecf 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -291,6 +291,7 @@ static inline int nfs_verify_change_attribute(struct inode *inode, unsigned long /* * linux/fs/nfs/inode.c */ +extern int nfs_sync_mapping(struct address_space *mapping); extern void nfs_zap_caches(struct inode *); extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *, struct nfs_fattr *); -- cgit v1.2.3-59-g8ed1b From fd30fc3256824f03c2ff9317269d66f72f7042ca Mon Sep 17 00:00:00 2001 From: Tom Zanussi Date: Tue, 20 Dec 2005 13:10:22 -0600 Subject: [PATCH] relayfs: remove warning printk() in relay_switch_subbuf() There's currently a diagnostic printk in relay_switch_subbuf() meant as a warning if you accidentally try to log an event larger than the sub-buffer size. The problem is if this happens while logging from somewhere it's not safe to be doing printks, such as in the scheduler, you can end up with a deadlock. This patch removes the warning from relay_switch_subbuf() and instead prints some diagnostic info when the channel is closed. Thanks to Mathieu Desnoyers for pointing out the problem and suggesting a fix. Signed-off-by: Tom Zanussi Signed-off-by: Linus Torvalds --- fs/relayfs/relay.c | 8 ++++++-- include/linux/relayfs_fs.h | 5 +++-- 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/fs/relayfs/relay.c b/fs/relayfs/relay.c index 16446a15c96d..2a6f7f12b7f9 100644 --- a/fs/relayfs/relay.c +++ b/fs/relayfs/relay.c @@ -333,8 +333,7 @@ size_t relay_switch_subbuf(struct rchan_buf *buf, size_t length) return length; toobig: - printk(KERN_WARNING "relayfs: event too large (%Zd)\n", length); - WARN_ON(1); + buf->chan->last_toobig = length; return 0; } @@ -399,6 +398,11 @@ void relay_close(struct rchan *chan) relay_close_buf(chan->buf[i]); } + if (chan->last_toobig) + printk(KERN_WARNING "relayfs: one or more items not logged " + "[item size (%Zd) > sub-buffer size (%Zd)]\n", + chan->last_toobig, chan->subbuf_size); + kref_put(&chan->kref, relay_destroy_channel); } diff --git a/include/linux/relayfs_fs.h b/include/linux/relayfs_fs.h index cfafc3e76bc2..fb7e80737325 100644 --- a/include/linux/relayfs_fs.h +++ b/include/linux/relayfs_fs.h @@ -20,9 +20,9 @@ #include /* - * Tracks changes to rchan_buf struct + * Tracks changes to rchan/rchan_buf structs */ -#define RELAYFS_CHANNEL_VERSION 5 +#define RELAYFS_CHANNEL_VERSION 6 /* * Per-cpu relay channel buffer @@ -60,6 +60,7 @@ struct rchan struct rchan_callbacks *cb; /* client callbacks */ struct kref kref; /* channel refcount */ void *private_data; /* for user-defined data */ + size_t last_toobig; /* tried to log event > subbuf size */ struct rchan_buf *buf[NR_CPUS]; /* per-cpu channel buffers */ }; -- cgit v1.2.3-59-g8ed1b From 05465fd5622202d65634b3a9a8bcc9cbb384a82a Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Thu, 8 Dec 2005 15:37:00 -0500 Subject: [ACPI] increase owner_id limit to 64 from 32 This is an interim patch until changes in an updated ACPICA core increase the limit to 255. Signed-off-by: Alex Williamson Signed-off-by: Len Brown --- drivers/acpi/utilities/utmisc.c | 18 +++++++++--------- include/acpi/acglobal.h | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c index 0c5abc536c7a..b886780f9def 100644 --- a/drivers/acpi/utilities/utmisc.c +++ b/drivers/acpi/utilities/utmisc.c @@ -84,14 +84,14 @@ acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id) /* Find a free owner ID */ - for (i = 0; i < 32; i++) { - if (!(acpi_gbl_owner_id_mask & (1 << i))) { + for (i = 0; i < 64; i++) { + if (!(acpi_gbl_owner_id_mask & (1ULL << i))) { ACPI_DEBUG_PRINT((ACPI_DB_VALUES, - "Current owner_id mask: %8.8X New ID: %2.2X\n", + "Current owner_id mask: %16.16lX New ID: %2.2X\n", acpi_gbl_owner_id_mask, (unsigned int)(i + 1))); - acpi_gbl_owner_id_mask |= (1 << i); + acpi_gbl_owner_id_mask |= (1ULL << i); *owner_id = (acpi_owner_id) (i + 1); goto exit; } @@ -106,7 +106,7 @@ acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id) */ *owner_id = 0; status = AE_OWNER_ID_LIMIT; - ACPI_REPORT_ERROR(("Could not allocate new owner_id (32 max), AE_OWNER_ID_LIMIT\n")); + ACPI_REPORT_ERROR(("Could not allocate new owner_id (64 max), AE_OWNER_ID_LIMIT\n")); exit: (void)acpi_ut_release_mutex(ACPI_MTX_CACHES); @@ -123,7 +123,7 @@ acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id) * control method or unloading a table. Either way, we would * ignore any error anyway. * - * DESCRIPTION: Release a table or method owner ID. Valid IDs are 1 - 32 + * DESCRIPTION: Release a table or method owner ID. Valid IDs are 1 - 64 * ******************************************************************************/ @@ -140,7 +140,7 @@ void acpi_ut_release_owner_id(acpi_owner_id * owner_id_ptr) /* Zero is not a valid owner_iD */ - if ((owner_id == 0) || (owner_id > 32)) { + if ((owner_id == 0) || (owner_id > 64)) { ACPI_REPORT_ERROR(("Invalid owner_id: %2.2X\n", owner_id)); return_VOID; } @@ -158,8 +158,8 @@ void acpi_ut_release_owner_id(acpi_owner_id * owner_id_ptr) /* Free the owner ID only if it is valid */ - if (acpi_gbl_owner_id_mask & (1 << owner_id)) { - acpi_gbl_owner_id_mask ^= (1 << owner_id); + if (acpi_gbl_owner_id_mask & (1ULL << owner_id)) { + acpi_gbl_owner_id_mask ^= (1ULL << owner_id); } (void)acpi_ut_release_mutex(ACPI_MTX_CACHES); diff --git a/include/acpi/acglobal.h b/include/acpi/acglobal.h index e9c2790139ec..4ab2ca18b8df 100644 --- a/include/acpi/acglobal.h +++ b/include/acpi/acglobal.h @@ -211,7 +211,7 @@ ACPI_EXTERN u32 acpi_gbl_original_mode; ACPI_EXTERN u32 acpi_gbl_rsdp_original_location; ACPI_EXTERN u32 acpi_gbl_ns_lookup_count; ACPI_EXTERN u32 acpi_gbl_ps_find_count; -ACPI_EXTERN u32 acpi_gbl_owner_id_mask; +ACPI_EXTERN u64 acpi_gbl_owner_id_mask; ACPI_EXTERN u16 acpi_gbl_pm1_enable_register_save; ACPI_EXTERN u16 acpi_gbl_global_lock_handle; ACPI_EXTERN u8 acpi_gbl_debugger_configuration; -- cgit v1.2.3-59-g8ed1b From 58c4fb86eabcbc385d954843a635b7f4327be6b0 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Wed, 21 Dec 2005 22:56:42 +0900 Subject: [IPV6]: Flag RTF_ANYCAST for anycast routes. Signed-off-by: YOSHIFUJI Hideaki --- include/linux/ipv6_route.h | 1 + net/ipv6/route.c | 13 +++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/linux/ipv6_route.h b/include/linux/ipv6_route.h index e2f935038013..d7c41d1d706a 100644 --- a/include/linux/ipv6_route.h +++ b/include/linux/ipv6_route.h @@ -18,6 +18,7 @@ fallback, no routers on link */ #define RTF_ADDRCONF 0x00040000 /* addrconf route - RA */ #define RTF_PREFIX_RT 0x00080000 /* A prefix only route - RA */ +#define RTF_ANYCAST 0x00100000 /* Anycast */ #define RTF_NONEXTHOP 0x00200000 /* route with no nexthop */ #define RTF_EXPIRES 0x00400000 diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 7c68bfbee361..66140f13d119 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -413,11 +413,14 @@ static struct rt6_info *rt6_cow(struct rt6_info *ort, struct in6_addr *daddr, rt = ip6_rt_copy(ort); if (rt) { - ipv6_addr_copy(&rt->rt6i_dst.addr, daddr); - - if (!(rt->rt6i_flags&RTF_GATEWAY)) + if (!(rt->rt6i_flags&RTF_GATEWAY)) { + if (rt->rt6i_dst.plen != 128 && + ipv6_addr_equal(&rt->rt6i_dst.addr, daddr)) + rt->rt6i_flags |= RTF_ANYCAST; ipv6_addr_copy(&rt->rt6i_gateway, daddr); + } + ipv6_addr_copy(&rt->rt6i_dst.addr, daddr); rt->rt6i_dst.plen = 128; rt->rt6i_flags |= RTF_CACHE; rt->u.dst.flags |= DST_HOST; @@ -1413,7 +1416,9 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, rt->u.dst.obsolete = -1; rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP; - if (!anycast) + if (anycast) + rt->rt6i_flags |= RTF_ANYCAST; + else rt->rt6i_flags |= RTF_LOCAL; rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway); if (rt->rt6i_nexthop == NULL) { -- cgit v1.2.3-59-g8ed1b From 3c21edbd113788b110116141c8078623a0900b6a Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Wed, 21 Dec 2005 22:57:24 +0900 Subject: [IPV6]: Defer IPv6 device initialization until the link becomes ready. NETDEV_UP might be sent even if the link attached to the interface was not ready. DAD does not make sense in such case, so we won't do so. After interface Signed-off-by: YOSHIFUJI Hideaki --- include/net/if_inet6.h | 1 + net/ipv6/addrconf.c | 74 +++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 65 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h index e97a9accb71d..d8234f9bd4c4 100644 --- a/include/net/if_inet6.h +++ b/include/net/if_inet6.h @@ -24,6 +24,7 @@ #define IF_RA_MANAGED 0x40 #define IF_RA_RCVD 0x20 #define IF_RS_SENT 0x10 +#define IF_READY 0x80000000 /* prefix flags */ #define IF_PREFIX_ONLINK 0x01 diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 4ea8cf7c0cc4..d012f6ac7040 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -388,6 +388,9 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev) } #endif + if (netif_carrier_ok(dev)) + ndev->if_flags |= IF_READY; + write_lock_bh(&addrconf_lock); dev->ip6_ptr = ndev; write_unlock_bh(&addrconf_lock); @@ -1215,10 +1218,8 @@ int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2) /* Gets referenced address, destroys ifaddr */ -void addrconf_dad_failure(struct inet6_ifaddr *ifp) +void addrconf_dad_stop(struct inet6_ifaddr *ifp) { - if (net_ratelimit()) - printk(KERN_INFO "%s: duplicate address detected!\n", ifp->idev->dev->name); if (ifp->flags&IFA_F_PERMANENT) { spin_lock_bh(&ifp->lock); addrconf_del_timer(ifp); @@ -1244,6 +1245,12 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp) ipv6_del_addr(ifp); } +void addrconf_dad_failure(struct inet6_ifaddr *ifp) +{ + if (net_ratelimit()) + printk(KERN_INFO "%s: duplicate address detected!\n", ifp->idev->dev->name); + addrconf_dad_stop(ifp); +} /* Join to solicited addr multicast group. */ @@ -2136,6 +2143,37 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, switch(event) { case NETDEV_UP: + case NETDEV_CHANGE: + if (event == NETDEV_UP) { + if (!netif_carrier_ok(dev)) { + /* device is not ready yet. */ + printk(KERN_INFO + "ADDRCONF(NETDEV_UP): %s: " + "link is not ready\n", + dev->name); + break; + } + } else { + if (!netif_carrier_ok(dev)) { + /* device is still not ready. */ + break; + } + + if (idev) { + if (idev->if_flags & IF_READY) { + /* device is already configured. */ + break; + } + idev->if_flags |= IF_READY; + } + + printk(KERN_INFO + "ADDRCONF(NETDEV_CHANGE): %s: " + "link becomes ready\n", + dev->name); + + } + switch(dev->type) { case ARPHRD_SIT: addrconf_sit_config(dev); @@ -2186,8 +2224,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, */ addrconf_ifdown(dev, event != NETDEV_DOWN); break; - case NETDEV_CHANGE: - break; + case NETDEV_CHANGENAME: #ifdef CONFIG_SYSCTL if (idev) { @@ -2268,7 +2305,7 @@ static int addrconf_ifdown(struct net_device *dev, int how) /* Step 3: clear flags for stateless addrconf */ if (how != 1) - idev->if_flags &= ~(IF_RS_SENT|IF_RA_RCVD); + idev->if_flags &= ~(IF_RS_SENT|IF_RA_RCVD|IF_READY); /* Step 4: clear address list */ #ifdef CONFIG_IPV6_PRIVACY @@ -2377,11 +2414,20 @@ out: /* * Duplicate Address Detection */ +static void addrconf_dad_kick(struct inet6_ifaddr *ifp) +{ + unsigned long rand_num; + struct inet6_dev *idev = ifp->idev; + + rand_num = net_random() % (idev->cnf.rtr_solicit_delay ? : 1); + ifp->probes = idev->cnf.dad_transmits; + addrconf_mod_timer(ifp, AC_DAD, rand_num); +} + static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) { struct inet6_dev *idev = ifp->idev; struct net_device *dev = idev->dev; - unsigned long rand_num; addrconf_join_solict(dev, &ifp->addr); @@ -2390,7 +2436,6 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) flags); net_srandom(ifp->addr.s6_addr32[3]); - rand_num = net_random() % (idev->cnf.rtr_solicit_delay ? : 1); read_lock_bh(&idev->lock); if (ifp->dead) @@ -2407,8 +2452,17 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) return; } - ifp->probes = idev->cnf.dad_transmits; - addrconf_mod_timer(ifp, AC_DAD, rand_num); + if (idev->if_flags & IF_READY) + addrconf_dad_kick(ifp); + else { + /* + * If the defice is not ready: + * - keep it tentative if it is a permanent address. + * - otherwise, kill it. + */ + in6_ifa_hold(ifp); + addrconf_dad_stop(ifp); + } spin_unlock_bh(&ifp->lock); out: -- cgit v1.2.3-59-g8ed1b From 23f9b317e0ba4fbc5fc9524275d0105fa87e2027 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 21 Dec 2005 02:27:50 +0100 Subject: [PATCH] include/linux/irq.h: #include Jan's crosscompile page [1] shows, that one regression in 2.6.15-rc is that the v850 defconfig does no longer compile. The compile error is: <-- snip --> ... CC arch/v850/kernel/setup.o In file included from /usr/src/ctest/rc/kernel/arch/v850/kernel/setup.c:17: /usr/src/ctest/rc/kernel/include/linux/irq.h:13:43: asm/smp.h: No such file or directory make[2]: *** [arch/v850/kernel/setup.o] Error 1 <-- snip --> The #include in irq.h was intruduced in 2.6.15-rc. Since include/linux/irq.h needs code from asm/smp.h only in the CONFIG_SMP=y case and linux/smp.h #include's asm/smp.h only in the CONFIG_SMP=y case, I'm suggesting this patch to #include in irq.h. I've tested the compilation with both CONFIG_SMP=y and CONFIG_SMP=n on i386. Signed-off-by: Adrian Bunk Acked-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/irq.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/irq.h b/include/linux/irq.h index c516382fbec2..f04ba20712a2 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -10,7 +10,7 @@ */ #include -#include /* cpu_online_map */ +#include #if !defined(CONFIG_ARCH_S390) -- cgit v1.2.3-59-g8ed1b From d6f029130fb83b36fb709a187275b0494035d689 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 21 Dec 2005 12:26:25 -0500 Subject: [PATCH] fix race with preempt_enable() Currently a simple void foo(void) { preempt_enable(); } produces the following code on ARM: foo: bic r3, sp, #8128 bic r3, r3, #63 ldr r2, [r3, #4] ldr r1, [r3, #0] sub r2, r2, #1 tst r1, #4 str r2, [r3, #4] blne preempt_schedule mov pc, lr The problem is that the TIF_NEED_RESCHED flag is loaded _before_ the preemption count is stored back, hence any interrupt coming within that 3 instruction window causing TIF_NEED_RESCHED to be set won't be seen and scheduling won't happen as it should. Nothing currently prevents gcc from performing that reordering. There is already a barrier() before the decrement of the preemption count, but another one is needed between this and the TIF_NEED_RESCHED flag test for proper code ordering. Signed-off-by: Nicolas Pitre Acked-by: Nick Piggin Signed-off-by: Linus Torvalds --- include/linux/preempt.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/linux/preempt.h b/include/linux/preempt.h index d9a2f5254a51..5769d14d1e6a 100644 --- a/include/linux/preempt.h +++ b/include/linux/preempt.h @@ -48,6 +48,7 @@ do { \ #define preempt_enable() \ do { \ preempt_enable_no_resched(); \ + barrier(); \ preempt_check_resched(); \ } while (0) -- cgit v1.2.3-59-g8ed1b From c660439ba90aaaa056f68a5b0fc79f6b9e0506f5 Mon Sep 17 00:00:00 2001 From: Ravikiran G Thirumalai Date: Thu, 22 Dec 2005 14:21:34 -0800 Subject: [PATCH] x86_64/ia64 : Fix compilation error for node_to_first_cpu Fixes a compiler error in node_to_first_cpu, __ffs expects unsigned long as a parameter; instead cpumask_t was being passed. The macro node_to_first_cpu was not yet used in x86_64 and ia64 arches, and so we never hit this. This patch replaces __ffs with first_cpu macro, similar to other arches. Signed-off-by: Alok N Kataria Signed-off-by: Ravikiran G Thirumalai Signed-off-by: Shai Fultheim Signed-off-by: Linus Torvalds --- include/asm-ia64/topology.h | 2 +- include/asm-x86_64/topology.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/asm-ia64/topology.h b/include/asm-ia64/topology.h index a9f738bf18a7..f7c330467e7e 100644 --- a/include/asm-ia64/topology.h +++ b/include/asm-ia64/topology.h @@ -38,7 +38,7 @@ /* * Returns the number of the first CPU on Node 'node'. */ -#define node_to_first_cpu(node) (__ffs(node_to_cpumask(node))) +#define node_to_first_cpu(node) (first_cpu(node_to_cpumask(node))) /* * Determines the node for a given pci bus diff --git a/include/asm-x86_64/topology.h b/include/asm-x86_64/topology.h index d39ebd5263ed..7d82bc56b9fa 100644 --- a/include/asm-x86_64/topology.h +++ b/include/asm-x86_64/topology.h @@ -23,7 +23,7 @@ extern int __node_distance(int, int); #define cpu_to_node(cpu) (cpu_to_node[cpu]) #define parent_node(node) (node) -#define node_to_first_cpu(node) (__ffs(node_to_cpumask[node])) +#define node_to_first_cpu(node) (first_cpu(node_to_cpumask[node])) #define node_to_cpumask(node) (node_to_cpumask[node]) #define pcibus_to_node(bus) ((long)(bus->sysdata)) #define pcibus_to_cpumask(bus) node_to_cpumask(pcibus_to_node(bus)); -- cgit v1.2.3-59-g8ed1b From e5c34a57c8b3a94b8d2b329936f8b1cbcc765307 Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Fri, 23 Dec 2005 09:10:03 -0500 Subject: [PATCH] Fix typo in x86_64 __build_write_lock_const assembly Based on __build_read_lock_const, this looked like a bug. [ Indeed. Maybe nobody uses this version? Worth fixing up anyway ] Signed-off-by: Linus Torvalds --- include/asm-x86_64/rwlock.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/asm-x86_64/rwlock.h b/include/asm-x86_64/rwlock.h index 8a78a4ace53c..9942cc393064 100644 --- a/include/asm-x86_64/rwlock.h +++ b/include/asm-x86_64/rwlock.h @@ -64,7 +64,7 @@ ::"a" (rw) : "memory") #define __build_write_lock_const(rw, helper) \ - asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" \ + asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",%0\n\t" \ "jnz 2f\n" \ "1:\n" \ LOCK_SECTION_START("") \ -- cgit v1.2.3-59-g8ed1b From 01e33b5a2a153eec74dd87522e264948030b88c1 Mon Sep 17 00:00:00 2001 From: Kurt Huwig Date: Sun, 25 Dec 2005 00:13:08 +0100 Subject: [PATCH] n_r3964: fixed usage of HZ; removed bad include Fix n_r3964 timeouts (hardcoded for 100Hz) Also the include of in 'n_r3964.h' is unnecessary and prevents using the header file in any application that has to include due to duplicate definition of 'struct termio'. Signed-off-by: Linus Torvalds --- include/linux/n_r3964.h | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/linux/n_r3964.h b/include/linux/n_r3964.h index 2352bcd31a06..db4f3776978a 100644 --- a/include/linux/n_r3964.h +++ b/include/linux/n_r3964.h @@ -13,6 +13,10 @@ * L. Haag * * $Log: r3964.h,v $ + * Revision 1.4 2005/12/21 19:54:24 Kurt Huwig + * Fixed HZ usage on 2.6 kernels + * Removed unnecessary include + * * Revision 1.3 2001/03/18 13:02:24 dwmw2 * Fix timer usage, use spinlocks properly. * @@ -45,9 +49,11 @@ #define __LINUX_N_R3964_H__ /* line disciplines for r3964 protocol */ -#include #ifdef __KERNEL__ + +#include + /* * Common ascii handshake characters: */ @@ -58,14 +64,14 @@ #define NAK 0x15 /* - * Timeouts (msecs/10 msecs per timer interrupt): + * Timeouts (from milliseconds to jiffies) */ -#define R3964_TO_QVZ 550/10 -#define R3964_TO_ZVZ 220/10 -#define R3964_TO_NO_BUF 400/10 -#define R3964_NO_TX_ROOM 100/10 -#define R3964_TO_RX_PANIC 4000/10 +#define R3964_TO_QVZ ((550)*HZ/1000) +#define R3964_TO_ZVZ ((220)*HZ/1000) +#define R3964_TO_NO_BUF ((400)*HZ/1000) +#define R3964_NO_TX_ROOM ((100)*HZ/1000) +#define R3964_TO_RX_PANIC ((4000)*HZ/1000) #define R3964_MAX_RETRIES 5 #endif -- cgit v1.2.3-59-g8ed1b From 5ab4a6c81eb3dbe32361791d1535f9153f79b0ed Mon Sep 17 00:00:00 2001 From: David L Stevens Date: Tue, 27 Dec 2005 14:03:00 -0800 Subject: [IPV6] mcast: Fix multiple issues in MLDv2 reports. The below "jumbo" patch fixes the following problems in MLDv2. 1) Add necessary "ntohs" to recent "pskb_may_pull" check [breaks all nonzero source queries on little-endian (!)] 2) Add locking to source filter list [resend of prior patch] 3) fix "mld_marksources()" to a) send nothing when all queried sources are excluded b) send full exclude report when source queried sources are not excluded c) don't schedule a timer when there's nothing to report NOTE: RFC 3810 specifies the source list should be saved and each source reported individually as an IS_IN. This is an obvious DOS path, requiring the host to store and then multicast as many sources as are queried (e.g., millions...). This alternative sends a full, relevant report that's limited to number of sources present on the machine. 4) fix "add_grec()" to send empty-source records when it should The original check doesn't account for a non-empty source list with all sources inactive; the new code keeps that short-circuit case, and also generates the group header with an empty list if needed. 5) fix mca_crcount decrement to be after add_grec(), which needs its original value These issues (other than item #1 ;-) ) were all found by Yan Zheng, much thanks! Signed-off-by: David L Stevens Signed-off-by: David S. Miller --- include/net/if_inet6.h | 1 + net/ipv6/mcast.c | 140 ++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 111 insertions(+), 30 deletions(-) (limited to 'include') diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h index d8234f9bd4c4..eb8afe3499a9 100644 --- a/include/net/if_inet6.h +++ b/include/net/if_inet6.h @@ -83,6 +83,7 @@ struct ipv6_mc_socklist struct in6_addr addr; int ifindex; struct ipv6_mc_socklist *next; + rwlock_t sflock; unsigned int sfmode; /* MCAST_{INCLUDE,EXCLUDE} */ struct ip6_sf_socklist *sflist; }; diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 057d8619ba13..f829a4ad3ccc 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -224,6 +224,7 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, struct in6_addr *addr) mc_lst->ifindex = dev->ifindex; mc_lst->sfmode = MCAST_EXCLUDE; + mc_lst->sflock = RW_LOCK_UNLOCKED; mc_lst->sflist = NULL; /* @@ -360,6 +361,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk, struct ip6_sf_socklist *psl; int i, j, rv; int leavegroup = 0; + int pmclocked = 0; int err; if (pgsr->gsr_group.ss_family != AF_INET6 || @@ -403,6 +405,9 @@ int ip6_mc_source(int add, int omode, struct sock *sk, pmc->sfmode = omode; } + write_lock_bh(&pmc->sflock); + pmclocked = 1; + psl = pmc->sflist; if (!add) { if (!psl) @@ -475,6 +480,8 @@ int ip6_mc_source(int add, int omode, struct sock *sk, /* update the interface list */ ip6_mc_add_src(idev, group, omode, 1, source, 1); done: + if (pmclocked) + write_unlock_bh(&pmc->sflock); read_unlock_bh(&ipv6_sk_mc_lock); read_unlock_bh(&idev->lock); in6_dev_put(idev); @@ -510,6 +517,8 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf) dev = idev->dev; err = 0; + read_lock_bh(&ipv6_sk_mc_lock); + if (gsf->gf_fmode == MCAST_INCLUDE && gsf->gf_numsrc == 0) { leavegroup = 1; goto done; @@ -549,6 +558,8 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf) newpsl = NULL; (void) ip6_mc_add_src(idev, group, gsf->gf_fmode, 0, NULL, 0); } + + write_lock_bh(&pmc->sflock); psl = pmc->sflist; if (psl) { (void) ip6_mc_del_src(idev, group, pmc->sfmode, @@ -558,8 +569,10 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf) (void) ip6_mc_del_src(idev, group, pmc->sfmode, 0, NULL, 0); pmc->sflist = newpsl; pmc->sfmode = gsf->gf_fmode; + write_unlock_bh(&pmc->sflock); err = 0; done: + read_unlock_bh(&ipv6_sk_mc_lock); read_unlock_bh(&idev->lock); in6_dev_put(idev); dev_put(dev); @@ -592,6 +605,11 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf, dev = idev->dev; err = -EADDRNOTAVAIL; + /* + * changes to the ipv6_mc_list require the socket lock and + * a read lock on ip6_sk_mc_lock. We have the socket lock, + * so reading the list is safe. + */ for (pmc=inet6->ipv6_mc_list; pmc; pmc=pmc->next) { if (pmc->ifindex != gsf->gf_interface) @@ -614,6 +632,10 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf, copy_to_user(optval, gsf, GROUP_FILTER_SIZE(0))) { return -EFAULT; } + /* changes to psl require the socket lock, a read lock on + * on ipv6_sk_mc_lock and a write lock on pmc->sflock. We + * have the socket lock, so reading here is safe. + */ for (i=0; isflock); psl = mc->sflist; if (!psl) { rv = mc->sfmode == MCAST_EXCLUDE; @@ -665,6 +688,7 @@ int inet6_mc_check(struct sock *sk, struct in6_addr *mc_addr, if (mc->sfmode == MCAST_EXCLUDE && i < psl->sl_count) rv = 0; } + read_unlock(&mc->sflock); read_unlock(&ipv6_sk_mc_lock); return rv; @@ -1068,7 +1092,8 @@ static void igmp6_group_queried(struct ifmcaddr6 *ma, unsigned long resptime) ma->mca_flags |= MAF_TIMER_RUNNING; } -static void mld_marksources(struct ifmcaddr6 *pmc, int nsrcs, +/* mark EXCLUDE-mode sources */ +static int mld_xmarksources(struct ifmcaddr6 *pmc, int nsrcs, struct in6_addr *srcs) { struct ip6_sf_list *psf; @@ -1078,13 +1103,53 @@ static void mld_marksources(struct ifmcaddr6 *pmc, int nsrcs, for (psf=pmc->mca_sources; psf; psf=psf->sf_next) { if (scount == nsrcs) break; - for (i=0; imca_sfcount[MCAST_INCLUDE] || + pmc->mca_sfcount[MCAST_EXCLUDE] != + psf->sf_count[MCAST_EXCLUDE]) + continue; + if (ipv6_addr_equal(&srcs[i], &psf->sf_addr)) { + scount++; + break; + } + } + } + pmc->mca_flags &= ~MAF_GSQUERY; + if (scount == nsrcs) /* all sources excluded */ + return 0; + return 1; +} + +static int mld_marksources(struct ifmcaddr6 *pmc, int nsrcs, + struct in6_addr *srcs) +{ + struct ip6_sf_list *psf; + int i, scount; + + if (pmc->mca_sfmode == MCAST_EXCLUDE) + return mld_xmarksources(pmc, nsrcs, srcs); + + /* mark INCLUDE-mode sources */ + + scount = 0; + for (psf=pmc->mca_sources; psf; psf=psf->sf_next) { + if (scount == nsrcs) + break; + for (i=0; isf_addr)) { psf->sf_gsresp = 1; scount++; break; } + } + } + if (!scount) { + pmc->mca_flags &= ~MAF_GSQUERY; + return 0; } + pmc->mca_flags |= MAF_GSQUERY; + return 1; } int igmp6_event_query(struct sk_buff *skb) @@ -1167,7 +1232,7 @@ int igmp6_event_query(struct sk_buff *skb) /* mark sources to include, if group & source-specific */ if (mlh2->nsrcs != 0) { if (!pskb_may_pull(skb, srcs_offset + - mlh2->nsrcs * sizeof(struct in6_addr))) { + ntohs(mlh2->nsrcs) * sizeof(struct in6_addr))) { in6_dev_put(idev); return -EINVAL; } @@ -1203,10 +1268,9 @@ int igmp6_event_query(struct sk_buff *skb) else ma->mca_flags &= ~MAF_GSQUERY; } - if (ma->mca_flags & MAF_GSQUERY) - mld_marksources(ma, ntohs(mlh2->nsrcs), - mlh2->srcs); - igmp6_group_queried(ma, max_delay); + if (!(ma->mca_flags & MAF_GSQUERY) || + mld_marksources(ma, ntohs(mlh2->nsrcs), mlh2->srcs)) + igmp6_group_queried(ma, max_delay); spin_unlock_bh(&ma->mca_lock); if (group_type != IPV6_ADDR_ANY) break; @@ -1281,7 +1345,18 @@ static int is_in(struct ifmcaddr6 *pmc, struct ip6_sf_list *psf, int type, case MLD2_MODE_IS_EXCLUDE: if (gdeleted || sdeleted) return 0; - return !((pmc->mca_flags & MAF_GSQUERY) && !psf->sf_gsresp); + if (!((pmc->mca_flags & MAF_GSQUERY) && !psf->sf_gsresp)) { + if (pmc->mca_sfmode == MCAST_INCLUDE) + return 1; + /* don't include if this source is excluded + * in all filters + */ + if (psf->sf_count[MCAST_INCLUDE]) + return 0; + return pmc->mca_sfcount[MCAST_EXCLUDE] == + psf->sf_count[MCAST_EXCLUDE]; + } + return 0; case MLD2_CHANGE_TO_INCLUDE: if (gdeleted || sdeleted) return 0; @@ -1450,7 +1525,7 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc, struct mld2_report *pmr; struct mld2_grec *pgr = NULL; struct ip6_sf_list *psf, *psf_next, *psf_prev, **psf_list; - int scount, first, isquery, truncate; + int scount, stotal, first, isquery, truncate; if (pmc->mca_flags & MAF_NOREPORT) return skb; @@ -1460,25 +1535,13 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc, truncate = type == MLD2_MODE_IS_EXCLUDE || type == MLD2_CHANGE_TO_EXCLUDE; + stotal = scount = 0; + psf_list = sdeleted ? &pmc->mca_tomb : &pmc->mca_sources; - if (!*psf_list) { - if (type == MLD2_ALLOW_NEW_SOURCES || - type == MLD2_BLOCK_OLD_SOURCES) - return skb; - if (pmc->mca_crcount || isquery) { - /* make sure we have room for group header and at - * least one source. - */ - if (skb && AVAILABLE(skb) < sizeof(struct mld2_grec)+ - sizeof(struct in6_addr)) { - mld_sendpack(skb); - skb = NULL; /* add_grhead will get a new one */ - } - skb = add_grhead(skb, pmc, type, &pgr); - } - return skb; - } + if (!*psf_list) + goto empty_source; + pmr = skb ? (struct mld2_report *)skb->h.raw : NULL; /* EX and TO_EX get a fresh packet, if needed */ @@ -1491,7 +1554,6 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc, } } first = 1; - scount = 0; psf_prev = NULL; for (psf=*psf_list; psf; psf=psf_next) { struct in6_addr *psrc; @@ -1525,7 +1587,7 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc, } psrc = (struct in6_addr *)skb_put(skb, sizeof(*psrc)); *psrc = psf->sf_addr; - scount++; + scount++; stotal++; if ((type == MLD2_ALLOW_NEW_SOURCES || type == MLD2_BLOCK_OLD_SOURCES) && psf->sf_crcount) { psf->sf_crcount--; @@ -1540,6 +1602,21 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc, } psf_prev = psf; } + +empty_source: + if (!stotal) { + if (type == MLD2_ALLOW_NEW_SOURCES || + type == MLD2_BLOCK_OLD_SOURCES) + return skb; + if (pmc->mca_crcount || isquery) { + /* make sure we have room for group header */ + if (skb && AVAILABLE(skb) < sizeof(struct mld2_grec)) { + mld_sendpack(skb); + skb = NULL; /* add_grhead will get a new one */ + } + skb = add_grhead(skb, pmc, type, &pgr); + } + } if (pgr) pgr->grec_nsrcs = htons(scount); @@ -1621,11 +1698,11 @@ static void mld_send_cr(struct inet6_dev *idev) skb = add_grec(skb, pmc, dtype, 1, 1); } if (pmc->mca_crcount) { - pmc->mca_crcount--; if (pmc->mca_sfmode == MCAST_EXCLUDE) { type = MLD2_CHANGE_TO_INCLUDE; skb = add_grec(skb, pmc, type, 1, 0); } + pmc->mca_crcount--; if (pmc->mca_crcount == 0) { mld_clear_zeros(&pmc->mca_tomb); mld_clear_zeros(&pmc->mca_sources); @@ -1659,12 +1736,12 @@ static void mld_send_cr(struct inet6_dev *idev) /* filter mode changes */ if (pmc->mca_crcount) { - pmc->mca_crcount--; if (pmc->mca_sfmode == MCAST_EXCLUDE) type = MLD2_CHANGE_TO_EXCLUDE; else type = MLD2_CHANGE_TO_INCLUDE; skb = add_grec(skb, pmc, type, 0, 0); + pmc->mca_crcount--; } spin_unlock_bh(&pmc->mca_lock); } @@ -2023,6 +2100,9 @@ static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml, { int err; + /* callers have the socket lock and a write lock on ipv6_sk_mc_lock, + * so no other readers or writers of iml or its sflist + */ if (iml->sflist == 0) { /* any-source empty exclude case */ return ip6_mc_del_src(idev, &iml->addr, iml->sfmode, 0, NULL, 0); -- cgit v1.2.3-59-g8ed1b From abe842eb98c45e2b77c5868ef106616ca828a3e4 Mon Sep 17 00:00:00 2001 From: Dag-Erling Smørgrav Date: Mon, 2 Jan 2006 15:57:06 +0100 Subject: [PATCH] Avoid namespace pollution in In commit 3D59121003721a8fad11ee72e646fd9d3076b5679c, the x86 and x86-64 was changed to include for the configurable timer frequency. However, asm/param.h is sometimes used in userland (it is included indirectly from ), so your commit pollutes the userland namespace with tons of CONFIG_FOO macros. This greatly confuses software packages (such as BusyBox) which use CONFIG_FOO macros themselves to control the inclusion of optional features. After a short exchange, Christoph approved this patch Signed-off-by: Linus Torvalds --- include/asm-i386/param.h | 3 +-- include/asm-x86_64/param.h | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/asm-i386/param.h b/include/asm-i386/param.h index fa02e67ea86b..095580f3a45c 100644 --- a/include/asm-i386/param.h +++ b/include/asm-i386/param.h @@ -1,9 +1,8 @@ -#include - #ifndef _ASMi386_PARAM_H #define _ASMi386_PARAM_H #ifdef __KERNEL__ +# include # define HZ CONFIG_HZ /* Internal kernel timer frequency */ # define USER_HZ 100 /* .. some user interfaces are in "ticks" */ # define CLOCKS_PER_SEC (USER_HZ) /* like times() */ diff --git a/include/asm-x86_64/param.h b/include/asm-x86_64/param.h index 40b11937180d..5956b23b57c2 100644 --- a/include/asm-x86_64/param.h +++ b/include/asm-x86_64/param.h @@ -1,9 +1,8 @@ -#include - #ifndef _ASMx86_64_PARAM_H #define _ASMx86_64_PARAM_H #ifdef __KERNEL__ +# include # define HZ CONFIG_HZ /* Internal kernel timer frequency */ # define USER_HZ 100 /* .. some user interfaces are in "ticks */ #define CLOCKS_PER_SEC (USER_HZ) /* like times() */ -- cgit v1.2.3-59-g8ed1b