diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index 72ac18067ecef58c4af36c49502e387be119d3fd..0377decc07190a4f6b7629f41ad73a43a82e921a 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c @@ -48,11 +48,6 @@ static struct hw_interrupt_type xics_pic = { .set_affinity = xics_set_affinity }; -static struct hw_interrupt_type xics_8259_pic = { - .typename = " XICS/8259", - .ack = xics_mask_and_ack_irq, -}; - /* This is used to map real irq numbers to virtual */ static struct radix_tree_root irq_map = RADIX_TREE_INIT(GFP_ATOMIC); @@ -367,12 +362,7 @@ int xics_get_irq(struct pt_regs *regs) /* for sanity, this had better be < NR_IRQS - 16 */ if (vec == xics_irq_8259_cascade_real) { irq = i8259_irq(regs); - if (irq == -1) { - /* Spurious cascaded interrupt. Still must ack xics */ - xics_end_irq(irq_offset_up(xics_irq_8259_cascade)); - - irq = -1; - } + xics_end_irq(irq_offset_up(xics_irq_8259_cascade)); } else if (vec == XICS_IRQ_SPURIOUS) { irq = -1; } else { @@ -542,6 +532,7 @@ void xics_init_IRQ(void) xics_irq_8259_cascade_real = *ireg; xics_irq_8259_cascade = virt_irq_create_mapping(xics_irq_8259_cascade_real); + i8259_init(0, 0); of_node_put(np); } @@ -565,12 +556,7 @@ void xics_init_IRQ(void) #endif /* CONFIG_SMP */ } - xics_8259_pic.enable = i8259_pic.enable; - xics_8259_pic.disable = i8259_pic.disable; - xics_8259_pic.end = i8259_pic.end; - for (i = 0; i < 16; ++i) - get_irq_desc(i)->handler = &xics_8259_pic; - for (; i < NR_IRQS; ++i) + for (i = irq_offset_value(); i < NR_IRQS; ++i) get_irq_desc(i)->handler = &xics_pic; xics_setup_cpu(); @@ -590,7 +576,6 @@ static int __init xics_setup_i8259(void) no_action, 0, "8259 cascade", NULL)) printk(KERN_ERR "xics_setup_i8259: couldn't get 8259 " "cascade\n"); - i8259_init(0, 0); } return 0; } diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c index 3428e1ed00329f53a48c7b9620a13205178159e1..c36f014f1fdf21bb63c78521608e64e36a60d251 100644 --- a/drivers/media/video/saa7127.c +++ b/drivers/media/video/saa7127.c @@ -389,7 +389,7 @@ static int saa7127_set_vps(struct i2c_client *client, struct v4l2_sliced_vbi_dat static int saa7127_set_cc(struct i2c_client *client, struct v4l2_sliced_vbi_data *data) { struct saa7127_state *state = i2c_get_clientdata(client); - u16 cc = data->data[0] << 8 | data->data[1]; + u16 cc = data->data[1] << 8 | data->data[0]; int enable = (data->line != 0); if (enable && (data->field != 0 || data->line != 21)) @@ -397,7 +397,7 @@ static int saa7127_set_cc(struct i2c_client *client, struct v4l2_sliced_vbi_data if (state->cc_enable != enable) { saa7127_dbg("Turn CC %s\n", enable ? "on" : "off"); saa7127_write(client, SAA7127_REG_CLOSED_CAPTION, - (enable << 6) | 0x11); + (state->xds_enable << 7) | (enable << 6) | 0x11); state->cc_enable = enable; } if (!enable) @@ -423,7 +423,7 @@ static int saa7127_set_xds(struct i2c_client *client, struct v4l2_sliced_vbi_dat if (state->xds_enable != enable) { saa7127_dbg("Turn XDS %s\n", enable ? "on" : "off"); saa7127_write(client, SAA7127_REG_CLOSED_CAPTION, - (enable << 7) | 0x11); + (enable << 7) | (state->cc_enable << 6) | 0x11); state->xds_enable = enable; } if (!enable) diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig index c512c4411b38319b513b9bc9bfb7ac80bfda2c59..c0f604a6fe42be25651750f5d239b9ad6b0ddd37 100644 --- a/drivers/media/video/saa7134/Kconfig +++ b/drivers/media/video/saa7134/Kconfig @@ -1,11 +1,10 @@ config VIDEO_SAA7134 tristate "Philips SAA7134 support" - depends on VIDEO_DEV && PCI && I2C && SOUND && SND + depends on VIDEO_DEV && PCI && I2C select VIDEO_BUF select VIDEO_IR select VIDEO_TUNER select CRC32 - select SND_PCM_OSS ---help--- This is a video4linux driver for Philips SAA713x based TV cards. @@ -13,6 +12,29 @@ config VIDEO_SAA7134 To compile this driver as a module, choose M here: the module will be called saa7134. +config VIDEO_SAA7134_ALSA + tristate "Philips SAA7134 DMA audio support" + depends on VIDEO_SAA7134 && SOUND && SND && (!VIDEO_SAA7134_OSS || VIDEO_SAA7134_OSS = m) + select SND_PCM_OSS + ---help--- + This is a video4linux driver for direct (DMA) audio in + Philips SAA713x based TV cards using ALSA + + To compile this driver as a module, choose M here: the + module will be called saa7134-alsa. + +config VIDEO_SAA7134_OSS + tristate "Philips SAA7134 DMA audio support (OSS, DEPRECATED)" + depends on VIDEO_SAA7134 && SOUND_PRIME && (!VIDEO_SAA7134_ALSA || VIDEO_SAA7134_ALSA = m) + ---help--- + This is a video4linux driver for direct (DMA) audio in + Philips SAA713x based TV cards using OSS + + This is deprecated in favor of the ALSA module + + To compile this driver as a module, choose M here: the + module will be called saa7134-oss. + config VIDEO_SAA7134_DVB tristate "DVB/ATSC Support for saa7134 based TV cards" depends on VIDEO_SAA7134 && DVB_CORE diff --git a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile index 134f83a962188f7d8da5b0d45db4c5cb380455a3..1ba998424bbdcb376fbf6901028f765031aa1e32 100644 --- a/drivers/media/video/saa7134/Makefile +++ b/drivers/media/video/saa7134/Makefile @@ -4,8 +4,11 @@ saa7134-objs := saa7134-cards.o saa7134-core.o saa7134-i2c.o \ saa7134-video.o saa7134-input.o obj-$(CONFIG_VIDEO_SAA7134) += saa7134.o saa7134-empress.o \ - saa6752hs.o saa7134-alsa.o \ - saa7134-oss.o + saa6752hs.o + +obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o +obj-$(CONFIG_VIDEO_SAA7134_OSS) += saa7134-oss.o + obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o EXTRA_CFLAGS += -I$(src)/.. diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c index 953d5fec82d515d23a8efe953dd78044e5f8f29d..ade05f75fdb05d2c23165c42091913ca56f67859 100644 --- a/drivers/media/video/saa7134/saa7134-alsa.c +++ b/drivers/media/video/saa7134/saa7134-alsa.c @@ -989,6 +989,14 @@ static int saa7134_alsa_init(void) struct saa7134_dev *dev = NULL; struct list_head *list; + if (!dmasound_init && !dmasound_exit) { + dmasound_init = alsa_device_init; + dmasound_exit = alsa_device_exit; + } else { + printk(KERN_WARNING "saa7134 ALSA: can't load, DMA sound handler already assigned (probably to OSS)\n"); + return -EBUSY; + } + printk(KERN_INFO "saa7134 ALSA driver for DMA sound loaded\n"); list_for_each(list,&saa7134_devlist) { @@ -1001,9 +1009,6 @@ static int saa7134_alsa_init(void) } } - dmasound_init = alsa_device_init; - dmasound_exit = alsa_device_exit; - if (dev == NULL) printk(KERN_INFO "saa7134 ALSA: no saa7134 cards found\n"); @@ -1023,12 +1028,15 @@ static void saa7134_alsa_exit(void) snd_card_free(snd_saa7134_cards[idx]); } + dmasound_init = NULL; + dmasound_exit = NULL; printk(KERN_INFO "saa7134 ALSA driver for DMA sound unloaded\n"); return; } -module_init(saa7134_alsa_init); +/* We initialize this late, to make sure the sound system is up and running */ +late_initcall(saa7134_alsa_init); module_exit(saa7134_alsa_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Ricardo Cerqueira"); diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c index 513a699a6df2a300c7c22bd3ea842509f4306441..8badd2a9cb2ff08d1e5fe07661999c245e6708eb 100644 --- a/drivers/media/video/saa7134/saa7134-oss.c +++ b/drivers/media/video/saa7134/saa7134-oss.c @@ -959,8 +959,17 @@ static int saa7134_oss_init(void) struct saa7134_dev *dev = NULL; struct list_head *list; + if (!dmasound_init && !dmasound_exit) { + dmasound_init = oss_device_init; + dmasound_exit = oss_device_exit; + } else { + printk(KERN_WARNING "saa7134 OSS: can't load, DMA sound handler already assigned (probably to ALSA)\n"); + return -EBUSY; + } + printk(KERN_INFO "saa7134 OSS driver for DMA sound loaded\n"); + list_for_each(list,&saa7134_devlist) { dev = list_entry(list, struct saa7134_dev, devlist); if (dev->dmasound.priv_data == NULL) { @@ -974,9 +983,6 @@ static int saa7134_oss_init(void) if (dev == NULL) printk(KERN_INFO "saa7134 OSS: no saa7134 cards found\n"); - dmasound_init = oss_device_init; - dmasound_exit = oss_device_exit; - return 0; } @@ -997,12 +1003,16 @@ static void saa7134_oss_exit(void) } + dmasound_init = NULL; + dmasound_exit = NULL; + printk(KERN_INFO "saa7134 OSS driver for DMA sound unloaded\n"); return; } -module_init(saa7134_oss_init); +/* We initialize this late, to make sure the sound system is up and running */ +late_initcall(saa7134_oss_init); module_exit(saa7134_oss_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 94e5167f260dbc93642b554ac2378cbc5f546908..e36c21e06d31e7b40e2599992082f98492c72c9b 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -400,6 +400,35 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, return found_target; } +struct work_queue_wrapper { + struct work_struct work; + struct scsi_target *starget; +}; + +static void scsi_target_reap_work(void *data) { + struct work_queue_wrapper *wqw = (struct work_queue_wrapper *)data; + struct scsi_target *starget = wqw->starget; + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + unsigned long flags; + + kfree(wqw); + + spin_lock_irqsave(shost->host_lock, flags); + + if (--starget->reap_ref == 0 && list_empty(&starget->devices)) { + list_del_init(&starget->siblings); + spin_unlock_irqrestore(shost->host_lock, flags); + device_del(&starget->dev); + transport_unregister_device(&starget->dev); + put_device(&starget->dev); + return; + + } + spin_unlock_irqrestore(shost->host_lock, flags); + + return; +} + /** * scsi_target_reap - check to see if target is in use and destroy if not * @@ -411,19 +440,18 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, */ void scsi_target_reap(struct scsi_target *starget) { - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - unsigned long flags; - spin_lock_irqsave(shost->host_lock, flags); + struct work_queue_wrapper *wqw = + kzalloc(sizeof(struct work_queue_wrapper), GFP_ATOMIC); - if (--starget->reap_ref == 0 && list_empty(&starget->devices)) { - list_del_init(&starget->siblings); - spin_unlock_irqrestore(shost->host_lock, flags); - device_del(&starget->dev); - transport_unregister_device(&starget->dev); - put_device(&starget->dev); + if (!wqw) { + starget_printk(KERN_ERR, starget, + "Failed to allocate memory in scsi_reap_target()\n"); return; } - spin_unlock_irqrestore(shost->host_lock, flags); + + INIT_WORK(&wqw->work, scsi_target_reap_work, wqw); + wqw->starget = starget; + schedule_work(&wqw->work); } /** diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 6cd5931d9a54a005987a31329399088c93187083..2a1a99a2ef5633fbffe80cd214d160a18063c6fa 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -105,6 +105,7 @@ static struct { { FC_PORTSTATE_LINKDOWN, "Linkdown" }, { FC_PORTSTATE_ERROR, "Error" }, { FC_PORTSTATE_LOOPBACK, "Loopback" }, + { FC_PORTSTATE_DELETED, "Deleted" }, }; fc_enum_name_search(port_state, fc_port_state, fc_port_state_names) #define FC_PORTSTATE_MAX_NAMELEN 20 @@ -211,6 +212,7 @@ fc_bitfield_name_search(remote_port_roles, fc_remote_port_role_names) #define FC_MGMTSRVR_PORTID 0x00000a +static void fc_shost_remove_rports(void *data); static void fc_timeout_deleted_rport(void *data); static void fc_scsi_scan_rport(void *data); static void fc_rport_terminate(struct fc_rport *rport); @@ -318,6 +320,8 @@ static int fc_host_setup(struct transport_container *tc, struct device *dev, fc_host_next_rport_number(shost) = 0; fc_host_next_target_id(shost) = 0; + fc_host_flags(shost) = 0; + INIT_WORK(&fc_host_rport_del_work(shost), fc_shost_remove_rports, shost); return 0; } @@ -387,6 +391,7 @@ show_fc_rport_##field (struct class_device *cdev, char *buf) \ struct fc_internal *i = to_fc_internal(shost->transportt); \ if ((i->f->get_rport_##field) && \ !((rport->port_state == FC_PORTSTATE_BLOCKED) || \ + (rport->port_state == FC_PORTSTATE_DELETED) || \ (rport->port_state == FC_PORTSTATE_NOTPRESENT))) \ i->f->get_rport_##field(rport); \ return snprintf(buf, sz, format_string, cast rport->field); \ @@ -402,6 +407,7 @@ store_fc_rport_##field(struct class_device *cdev, const char *buf, \ struct Scsi_Host *shost = rport_to_shost(rport); \ struct fc_internal *i = to_fc_internal(shost->transportt); \ if ((rport->port_state == FC_PORTSTATE_BLOCKED) || \ + (rport->port_state == FC_PORTSTATE_DELETED) || \ (rport->port_state == FC_PORTSTATE_NOTPRESENT)) \ return -EBUSY; \ val = simple_strtoul(buf, NULL, 0); \ @@ -519,6 +525,7 @@ store_fc_rport_dev_loss_tmo(struct class_device *cdev, const char *buf, struct Scsi_Host *shost = rport_to_shost(rport); struct fc_internal *i = to_fc_internal(shost->transportt); if ((rport->port_state == FC_PORTSTATE_BLOCKED) || + (rport->port_state == FC_PORTSTATE_DELETED) || (rport->port_state == FC_PORTSTATE_NOTPRESENT)) return -EBUSY; val = simple_strtoul(buf, NULL, 0); @@ -1769,7 +1776,7 @@ fc_timeout_deleted_rport(void *data) rport->maxframe_size = -1; rport->supported_classes = FC_COS_UNSPECIFIED; rport->roles = FC_RPORT_ROLE_UNKNOWN; - rport->port_state = FC_PORTSTATE_NOTPRESENT; + rport->port_state = FC_PORTSTATE_DELETED; /* remove the identifiers that aren't used in the consisting binding */ switch (fc_host_tgtid_bind_type(shost)) { @@ -1789,14 +1796,23 @@ fc_timeout_deleted_rport(void *data) break; } - spin_unlock_irqrestore(shost->host_lock, flags); - /* * As this only occurs if the remote port (scsi target) * went away and didn't come back - we'll remove * all attached scsi devices. + * + * We'll schedule the shost work item to perform the actual removal + * to avoid recursion in the different flush calls if we perform + * the removal in each target - and there are lots of targets + * whose timeouts fire at the same time. */ - fc_rport_tgt_remove(rport); + + if ( !(fc_host_flags(shost) & FC_SHOST_RPORT_DEL_SCHEDULED)) { + fc_host_flags(shost) |= FC_SHOST_RPORT_DEL_SCHEDULED; + scsi_queue_work(shost, &fc_host_rport_del_work(shost)); + } + + spin_unlock_irqrestore(shost->host_lock, flags); } /** @@ -1818,6 +1834,41 @@ fc_scsi_scan_rport(void *data) } +/** + * fc_shost_remove_rports - called to remove all rports that are marked + * as in a deleted (not connected) state. + * + * @data: shost whose rports are to be looked at + **/ +static void +fc_shost_remove_rports(void *data) +{ + struct Scsi_Host *shost = (struct Scsi_Host *)data; + struct fc_rport *rport, *next_rport; + unsigned long flags; + + spin_lock_irqsave(shost->host_lock, flags); + while (fc_host_flags(shost) & FC_SHOST_RPORT_DEL_SCHEDULED) { + + fc_host_flags(shost) &= ~FC_SHOST_RPORT_DEL_SCHEDULED; + +restart_search: + list_for_each_entry_safe(rport, next_rport, + &fc_host_rport_bindings(shost), peers) { + if (rport->port_state == FC_PORTSTATE_DELETED) { + rport->port_state = FC_PORTSTATE_NOTPRESENT; + spin_unlock_irqrestore(shost->host_lock, flags); + fc_rport_tgt_remove(rport); + spin_lock_irqsave(shost->host_lock, flags); + goto restart_search; + } + } + + } + spin_unlock_irqrestore(shost->host_lock, flags); +} + + MODULE_AUTHOR("Martin Hicks"); MODULE_DESCRIPTION("FC Transport Attributes"); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index e197ce9353de0f4591ad38861413b7ceb1b66593..e80ef946782559e4bd2f6f83f27b2d10a9463a84 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -1432,7 +1432,8 @@ static int usb_generic_suspend(struct device *dev, pm_message_t message) mark_quiesced(intf); } else { // FIXME else if there's no suspend method, disconnect... - dev_warn(dev, "no %s?\n", "suspend"); + dev_warn(dev, "no suspend for driver %s?\n", driver->name); + mark_quiesced(intf); status = 0; } return status; @@ -1460,8 +1461,10 @@ static int usb_generic_resume(struct device *dev) } if ((dev->driver == NULL) || - (dev->driver_data == &usb_generic_driver_data)) + (dev->driver_data == &usb_generic_driver_data)) { + dev->power.power_state.event = PM_EVENT_FREEZE; return 0; + } intf = to_usb_interface(dev); driver = to_usb_driver(dev->driver); @@ -1481,7 +1484,7 @@ static int usb_generic_resume(struct device *dev) mark_quiesced(intf); } } else - dev_warn(dev, "no %s?\n", "resume"); + dev_warn(dev, "no resume for driver %s?\n", driver->name); return 0; } diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index 4837524eada7170049c78f61fdff0eab29fddd0a..4ef5527028c5e1fa03be05552cd8201a126c5236 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -109,7 +109,7 @@ static int slave_configure(struct scsi_device *sdev) * data comes from. */ if (sdev->scsi_level < SCSI_2) - sdev->scsi_level = SCSI_2; + sdev->scsi_level = sdev->sdev_target->scsi_level = SCSI_2; /* According to the technical support people at Genesys Logic, * devices using their chips have problems transferring more than @@ -162,7 +162,7 @@ static int slave_configure(struct scsi_device *sdev) * a Get-Max-LUN request, we won't lose much by setting the * revision level down to 2. The only devices that would be * affected are those with sparse LUNs. */ - sdev->scsi_level = SCSI_2; + sdev->scsi_level = sdev->sdev_target->scsi_level = SCSI_2; /* USB-IDE bridges tend to report SK = 0x04 (Non-recoverable * Hardware Error) when any low-level error occurs, diff --git a/fs/nfs/file.c b/fs/nfs/file.c index eb5cd4c3bbfdbf3aae12b0f367f544fcc4c4a13b..7a79fbe9f5394c67dd53b01526d37e29fae0ce4e 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -509,7 +509,8 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl) return -EINVAL; /* No mandatory locks over NFS */ - if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) + if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID && + fl->fl_type != F_UNLCK) return -ENOLCK; if (IS_GETLK(cmd)) diff --git a/include/linux/ipv6_route.h b/include/linux/ipv6_route.h index e2f935038013b745252dd4ac6670c18474ec1e99..d7c41d1d706a30d592d6183079627afb101d42f8 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/include/linux/irq.h b/include/linux/irq.h index c516382fbec2fa5fb5871937ba0bab6de48d4dfd..f04ba20712a2968cba8d9e77e31c2d716f157830 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) diff --git a/include/linux/preempt.h b/include/linux/preempt.h index d9a2f5254a51194858091bec44bf6bfb43cb9168..5769d14d1e6ab658b7ab8b2a2c9de117ec2b4838 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) diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h index e97a9accb71df31630d5c4d4455ef52bec535991..d8234f9bd4c418298e9775cf4af01a1e69d27fe4 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/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h index fac547d32a98f112123ec4c2e35c59e2e1a586c4..394f14a5b7cb44cc17ed888f865b358200eddaac 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 */ diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 91e412b0ab005b439e328cf8800f4ee08fb7bdeb..67465b65abe4345181f1029360ac8654e189eaf0 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -753,6 +753,8 @@ static int vlan_ioctl_handler(void __user *arg) break; case GET_VLAN_REALDEV_NAME_CMD: err = vlan_dev_get_realdev_name(args.device1, args.u.device2); + if (err) + goto out; if (copy_to_user(arg, &args, sizeof(struct vlan_ioctl_args))) { err = -EFAULT; @@ -761,6 +763,8 @@ static int vlan_ioctl_handler(void __user *arg) case GET_VLAN_VID_CMD: err = vlan_dev_get_vid(args.device1, &vid); + if (err) + goto out; args.u.VID = vid; if (copy_to_user(arg, &args, sizeof(struct vlan_ioctl_args))) { @@ -774,7 +778,7 @@ static int vlan_ioctl_handler(void __user *arg) __FUNCTION__, args.cmd); return -EINVAL; }; - +out: return err; } diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index ca03521112c52bfa4e279b351aee54c980105e71..656e13e38cfb69622e02df1d54aadd08e334bdfc 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -1251,7 +1251,7 @@ static int dccp_v4_destroy_sock(struct sock *sk) struct dccp_sock *dp = dccp_sk(sk); /* - * DCCP doesn't use sk_qrite_queue, just sk_send_head + * DCCP doesn't use sk_write_queue, just sk_send_head * for retransmissions */ if (sk->sk_send_head != NULL) { diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 4ea8cf7c0cc443bab3fe8cfa5c860e8e6592f12c..510220f2ae8bebafd56d0779479da8b8365a3103 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -137,6 +137,7 @@ static int addrconf_ifdown(struct net_device *dev, int how); static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags); static void addrconf_dad_timer(unsigned long data); static void addrconf_dad_completed(struct inet6_ifaddr *ifp); +static void addrconf_dad_run(struct inet6_dev *idev); static void addrconf_rs_timer(unsigned long data); static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa); static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa); @@ -388,6 +389,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); @@ -415,6 +419,7 @@ static struct inet6_dev * ipv6_find_idev(struct net_device *dev) if ((idev = ipv6_add_dev(dev)) == NULL) return NULL; } + if (dev->flags&IFF_UP) ipv6_mc_up(idev); return idev; @@ -634,8 +639,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) } #endif - for (ifap = &idev->addr_list; (ifa=*ifap) != NULL; - ifap = &ifa->if_next) { + for (ifap = &idev->addr_list; (ifa=*ifap) != NULL;) { if (ifa == ifp) { *ifap = ifa->if_next; __in6_ifa_put(ifp); @@ -643,6 +647,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) if (!(ifp->flags & IFA_F_PERMANENT) || onlink > 0) break; deleted = 1; + continue; } else if (ifp->flags & IFA_F_PERMANENT) { if (ipv6_prefix_equal(&ifa->addr, &ifp->addr, ifp->prefix_len)) { @@ -666,6 +671,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) } } } + ifap = &ifa->if_next; } write_unlock_bh(&idev->lock); @@ -903,11 +909,18 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev, score.addr_type = __ipv6_addr_type(&ifa->addr); - /* Rule 0: Candidate Source Address (section 4) + /* Rule 0: + * - Tentative Address (RFC2462 section 5.4) + * - A tentative address is not considered + * "assigned to an interface" in the traditional + * sense. + * - Candidate Source Address (section 4) * - In any case, anycast addresses, multicast * addresses, and the unspecified address MUST * NOT be included in a candidate set. */ + if (ifa->flags & IFA_F_TENTATIVE) + continue; if (unlikely(score.addr_type == IPV6_ADDR_ANY || score.addr_type & IPV6_ADDR_MULTICAST)) { LIMIT_NETDEBUG(KERN_DEBUG @@ -1215,10 +1228,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 +1255,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. */ @@ -2133,9 +2150,42 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, { struct net_device *dev = (struct net_device *) data; struct inet6_dev *idev = __in6_dev_get(dev); + int run_pending = 0; 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); + + run_pending = 1; + } + switch(dev->type) { case ARPHRD_SIT: addrconf_sit_config(dev); @@ -2152,6 +2202,9 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, break; }; if (idev) { + if (run_pending) + addrconf_dad_run(idev); + /* If the MTU changed during the interface down, when the interface up, the changed MTU must be reflected in the idev as well as routers. @@ -2186,8 +2239,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 +2320,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 +2429,20 @@ static void addrconf_rs_timer(unsigned long data) /* * 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 +2451,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 +2467,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: @@ -2492,6 +2561,22 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp) } } +static void addrconf_dad_run(struct inet6_dev *idev) { + struct inet6_ifaddr *ifp; + + read_lock_bh(&idev->lock); + for (ifp = idev->addr_list; ifp; ifp = ifp->if_next) { + spin_lock_bh(&ifp->lock); + if (!(ifp->flags & IFA_F_TENTATIVE)) { + spin_unlock_bh(&ifp->lock); + continue; + } + spin_unlock_bh(&ifp->lock); + addrconf_dad_kick(ifp); + } + read_unlock_bh(&idev->lock); +} + #ifdef CONFIG_PROC_FS struct if6_iter_state { int bucket; diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 34a332225c1749f215f126d46788404f5e5e9850..6ec6a2b549bbd6d6930230d8bb8ca00d0e208f1f 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -328,8 +328,10 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, iif = skb->dev->ifindex; /* - * Must not send if we know that source is Anycast also. - * for now we don't know that. + * Must not send error if the source does not uniquely + * identify a single node (RFC2463 Section 2.4). + * We check unspecified / multicast addresses here, + * and anycast addresses will be checked later. */ if ((addr_type == IPV6_ADDR_ANY) || (addr_type & IPV6_ADDR_MULTICAST)) { LIMIT_NETDEBUG(KERN_DEBUG "icmpv6_send: addr_any/mcast source\n"); @@ -373,6 +375,16 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, err = ip6_dst_lookup(sk, &dst, &fl); if (err) goto out; + + /* + * We won't send icmp if the destination is known + * anycast. + */ + if (((struct rt6_info *)dst)->rt6i_flags & RTF_ANYCAST) { + LIMIT_NETDEBUG(KERN_DEBUG "icmpv6_send: acast source\n"); + goto out_dst_release; + } + if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) goto out; diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 7c68bfbee36193caca29325ad160d5be62c73265..66140f13d1197130c29f5d9fa90c4f10a3bf3819 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) { diff --git a/net/netrom/nr_in.c b/net/netrom/nr_in.c index 004e8599b8fe595f5b72c92b0b51bb203b99a44d..a7d88b5ad756a85731d97feec43a58193129367c 100644 --- a/net/netrom/nr_in.c +++ b/net/netrom/nr_in.c @@ -99,7 +99,7 @@ static int nr_state1_machine(struct sock *sk, struct sk_buff *skb, break; case NR_RESET: - if (sysctl_netrom_reset_circuit); + if (sysctl_netrom_reset_circuit) nr_disconnect(sk, ECONNRESET); break; @@ -130,7 +130,7 @@ static int nr_state2_machine(struct sock *sk, struct sk_buff *skb, break; case NR_RESET: - if (sysctl_netrom_reset_circuit); + if (sysctl_netrom_reset_circuit) nr_disconnect(sk, ECONNRESET); break; @@ -265,7 +265,7 @@ static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype break; case NR_RESET: - if (sysctl_netrom_reset_circuit); + if (sysctl_netrom_reset_circuit) nr_disconnect(sk, ECONNRESET); break; diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 54a4be6a7d269de50d3db7683b6020785bf0a15f..d19e274b9c4a346b48bf32558ddec3db69fd5942 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -346,6 +346,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) struct xfrm_policy *pol, **p; struct xfrm_policy *delpol = NULL; struct xfrm_policy **newpos = NULL; + struct dst_entry *gc_list; write_lock_bh(&xfrm_policy_lock); for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL;) { @@ -381,9 +382,36 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) xfrm_pol_hold(policy); write_unlock_bh(&xfrm_policy_lock); - if (delpol) { + if (delpol) xfrm_policy_kill(delpol); + + read_lock_bh(&xfrm_policy_lock); + gc_list = NULL; + for (policy = policy->next; policy; policy = policy->next) { + struct dst_entry *dst; + + write_lock(&policy->lock); + dst = policy->bundles; + if (dst) { + struct dst_entry *tail = dst; + while (tail->next) + tail = tail->next; + tail->next = gc_list; + gc_list = dst; + + policy->bundles = NULL; + } + write_unlock(&policy->lock); } + read_unlock_bh(&xfrm_policy_lock); + + while (gc_list) { + struct dst_entry *dst = gc_list; + + gc_list = dst->next; + dst_free(dst); + } + return 0; } EXPORT_SYMBOL(xfrm_policy_insert);