diff --git a/debian/changelog b/debian/changelog index 0318849ea..dcb3eaad4 100644 --- a/debian/changelog +++ b/debian/changelog @@ -3,6 +3,20 @@ linux-2.6 (3.0.0-4) UNRELEASED; urgency=low [ Ben Hutchings ] * Make bug script accept failure of lspci (Closes: #639439) * [alpha] Disable GENERIC_GPIO (Closes: #638696) + * Add stable 3.0.4, including: + - loop: fix deadlock when sysfs and LOOP_CLR_FD race against each other + - Btrfs: fix an oops of log replay + - ext4: Fix ext4_should_writeback_data() for no-journal mode + - ext4: call ext4_ioend_wait and ext4_flush_completed_IO in ext4_evict_inode + - ext4: Resolve the hang of direct i/o read in handling + EXT4_IO_END_UNWRITTEN. + - ext4: fix nomblk_io_submit option so it correctly converts uninit blocks + - xen-blkfront: Drop name and minor adjustments for emulated scsi devices + - xen/x86: replace order-based range checking of M2P table by linear one + - rt2x00: fix order of entry flags modification (Closes: #636531) + - Add a personality to report 2.6.x version numbers + For the complete list of changes, see: + http://www.kernel.org/pub/linux/kernel/v3.0/ChangeLog-3.0.4 -- Ben Hutchings Sun, 28 Aug 2011 17:07:47 +0100 diff --git a/debian/patches/bugfix/all/stable/3.0.4.patch b/debian/patches/bugfix/all/stable/3.0.4.patch new file mode 100644 index 000000000..28d3d582b --- /dev/null +++ b/debian/patches/bugfix/all/stable/3.0.4.patch @@ -0,0 +1,1263 @@ +diff --git a/Makefile b/Makefile +index c44d720..7d2192c 100644 +diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h +index 64a619d..7ff4669 100644 +--- a/arch/x86/include/asm/xen/page.h ++++ b/arch/x86/include/asm/xen/page.h +@@ -39,7 +39,7 @@ typedef struct xpaddr { + ((unsigned long)((u64)CONFIG_XEN_MAX_DOMAIN_MEMORY * 1024 * 1024 * 1024 / PAGE_SIZE)) + + extern unsigned long *machine_to_phys_mapping; +-extern unsigned int machine_to_phys_order; ++extern unsigned long machine_to_phys_nr; + + extern unsigned long get_phys_to_machine(unsigned long pfn); + extern bool set_phys_to_machine(unsigned long pfn, unsigned long mfn); +@@ -87,7 +87,7 @@ static inline unsigned long mfn_to_pfn(unsigned long mfn) + if (xen_feature(XENFEAT_auto_translated_physmap)) + return mfn; + +- if (unlikely((mfn >> machine_to_phys_order) != 0)) { ++ if (unlikely(mfn >= machine_to_phys_nr)) { + pfn = ~0; + goto try_override; + } +diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c +index adc66c3..34b1859 100644 +--- a/arch/x86/kernel/apic/x2apic_uv_x.c ++++ b/arch/x86/kernel/apic/x2apic_uv_x.c +@@ -207,7 +207,6 @@ static int __cpuinit uv_wakeup_secondary(int phys_apicid, unsigned long start_ri + ((start_rip << UVH_IPI_INT_VECTOR_SHFT) >> 12) | + APIC_DM_INIT; + uv_write_global_mmr64(pnode, UVH_IPI_INT, val); +- mdelay(10); + + val = (1UL << UVH_IPI_INT_SEND_SHFT) | + (phys_apicid << UVH_IPI_INT_APIC_ID_SHFT) | +diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c +index da0d779..ed6086e 100644 +--- a/arch/x86/kernel/cpu/intel.c ++++ b/arch/x86/kernel/cpu/intel.c +@@ -465,11 +465,11 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c) + u64 epb; + + rdmsrl(MSR_IA32_ENERGY_PERF_BIAS, epb); +- if ((epb & 0xF) == 0) { +- printk_once(KERN_WARNING, "x86: updated energy_perf_bias" +- " to 'normal' from 'performance'\n" +- "You can view and update epb via utility," +- " such as x86_energy_perf_policy(8)\n"); ++ if ((epb & 0xF) == ENERGY_PERF_BIAS_PERFORMANCE) { ++ printk_once(KERN_WARNING "ENERGY_PERF_BIAS:" ++ " Set to 'normal', was 'performance'\n" ++ "ENERGY_PERF_BIAS: View and update with" ++ " x86_energy_perf_policy(8)\n"); + epb = (epb & ~0xF) | ENERGY_PERF_BIAS_NORMAL; + wrmsrl(MSR_IA32_ENERGY_PERF_BIAS, epb); + } +diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c +index 929739a..3d17bc7 100644 +--- a/arch/x86/kernel/cpu/mtrr/main.c ++++ b/arch/x86/kernel/cpu/mtrr/main.c +@@ -248,6 +248,25 @@ set_mtrr(unsigned int reg, unsigned long base, unsigned long size, mtrr_type typ + unsigned long flags; + int cpu; + ++#ifdef CONFIG_SMP ++ /* ++ * If this cpu is not yet active, we are in the cpu online path. There ++ * can be no stop_machine() in parallel, as stop machine ensures this ++ * by using get_online_cpus(). We can skip taking the stop_cpus_mutex, ++ * as we don't need it and also we can't afford to block while waiting ++ * for the mutex. ++ * ++ * If this cpu is active, we need to prevent stop_machine() happening ++ * in parallel by taking the stop cpus mutex. ++ * ++ * Also, this is called in the context of cpu online path or in the ++ * context where cpu hotplug is prevented. So checking the active status ++ * of the raw_smp_processor_id() is safe. ++ */ ++ if (cpu_active(raw_smp_processor_id())) ++ mutex_lock(&stop_cpus_mutex); ++#endif ++ + preempt_disable(); + + data.smp_reg = reg; +@@ -330,6 +349,10 @@ set_mtrr(unsigned int reg, unsigned long base, unsigned long size, mtrr_type typ + + local_irq_restore(flags); + preempt_enable(); ++#ifdef CONFIG_SMP ++ if (cpu_active(raw_smp_processor_id())) ++ mutex_unlock(&stop_cpus_mutex); ++#endif + } + + /** +diff --git a/arch/x86/platform/olpc/olpc.c b/arch/x86/platform/olpc/olpc.c +index 0060fd5..02e3934 100644 +--- a/arch/x86/platform/olpc/olpc.c ++++ b/arch/x86/platform/olpc/olpc.c +@@ -157,13 +157,13 @@ restart: + if (inbuf && inlen) { + /* write data to EC */ + for (i = 0; i < inlen; i++) { ++ pr_devel("olpc-ec: sending cmd arg 0x%x\n", inbuf[i]); ++ outb(inbuf[i], 0x68); + if (wait_on_ibf(0x6c, 0)) { + printk(KERN_ERR "olpc-ec: timeout waiting for" + " EC accept data!\n"); + goto err; + } +- pr_devel("olpc-ec: sending cmd arg 0x%x\n", inbuf[i]); +- outb(inbuf[i], 0x68); + } + } + if (outbuf && outlen) { +diff --git a/arch/x86/vdso/vdso32/sysenter.S b/arch/x86/vdso/vdso32/sysenter.S +index e2800af..e354bce 100644 +--- a/arch/x86/vdso/vdso32/sysenter.S ++++ b/arch/x86/vdso/vdso32/sysenter.S +@@ -43,7 +43,7 @@ __kernel_vsyscall: + .space 7,0x90 + + /* 14: System call restart point is here! (SYSENTER_RETURN-2) */ +- jmp .Lenter_kernel ++ int $0x80 + /* 16: System call normal return point is here! */ + VDSO32_SYSENTER_RETURN: /* Symbol used by sysenter.c via vdso32-syms.h */ + pop %ebp +diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c +index 5325742..67d69f1 100644 +--- a/arch/x86/xen/enlighten.c ++++ b/arch/x86/xen/enlighten.c +@@ -77,8 +77,8 @@ EXPORT_SYMBOL_GPL(xen_domain_type); + + unsigned long *machine_to_phys_mapping = (void *)MACH2PHYS_VIRT_START; + EXPORT_SYMBOL(machine_to_phys_mapping); +-unsigned int machine_to_phys_order; +-EXPORT_SYMBOL(machine_to_phys_order); ++unsigned long machine_to_phys_nr; ++EXPORT_SYMBOL(machine_to_phys_nr); + + struct start_info *xen_start_info; + EXPORT_SYMBOL_GPL(xen_start_info); +diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c +index 0ccccb6..5f76c0a 100644 +--- a/arch/x86/xen/mmu.c ++++ b/arch/x86/xen/mmu.c +@@ -1626,15 +1626,19 @@ static void __init xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn) + void __init xen_setup_machphys_mapping(void) + { + struct xen_machphys_mapping mapping; +- unsigned long machine_to_phys_nr_ents; + + if (HYPERVISOR_memory_op(XENMEM_machphys_mapping, &mapping) == 0) { + machine_to_phys_mapping = (unsigned long *)mapping.v_start; +- machine_to_phys_nr_ents = mapping.max_mfn + 1; ++ machine_to_phys_nr = mapping.max_mfn + 1; + } else { +- machine_to_phys_nr_ents = MACH2PHYS_NR_ENTRIES; ++ machine_to_phys_nr = MACH2PHYS_NR_ENTRIES; + } +- machine_to_phys_order = fls(machine_to_phys_nr_ents - 1); ++#ifdef CONFIG_X86_32 ++ if ((machine_to_phys_mapping + machine_to_phys_nr) ++ < machine_to_phys_mapping) ++ machine_to_phys_nr = (unsigned long *)NULL ++ - machine_to_phys_mapping; ++#endif + } + + #ifdef CONFIG_X86_64 +diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c +index b4533a8..e79dbb9 100644 +--- a/arch/x86/xen/smp.c ++++ b/arch/x86/xen/smp.c +@@ -521,8 +521,6 @@ static void __init xen_hvm_smp_prepare_cpus(unsigned int max_cpus) + native_smp_prepare_cpus(max_cpus); + WARN_ON(xen_smp_intr_init(0)); + +- if (!xen_have_vector_callback) +- return; + xen_init_lock_cpu(0); + xen_init_spinlocks(); + } +@@ -546,6 +544,8 @@ static void xen_hvm_cpu_die(unsigned int cpu) + + void __init xen_hvm_smp_init(void) + { ++ if (!xen_have_vector_callback) ++ return; + smp_ops.smp_prepare_cpus = xen_hvm_smp_prepare_cpus; + smp_ops.smp_send_reschedule = xen_smp_send_reschedule; + smp_ops.cpu_up = xen_hvm_cpu_up; +diff --git a/drivers/block/loop.c b/drivers/block/loop.c +index 76c8da7..2ebacf0 100644 +--- a/drivers/block/loop.c ++++ b/drivers/block/loop.c +@@ -750,10 +750,10 @@ static ssize_t loop_attr_backing_file_show(struct loop_device *lo, char *buf) + ssize_t ret; + char *p = NULL; + +- mutex_lock(&lo->lo_ctl_mutex); ++ spin_lock_irq(&lo->lo_lock); + if (lo->lo_backing_file) + p = d_path(&lo->lo_backing_file->f_path, buf, PAGE_SIZE - 1); +- mutex_unlock(&lo->lo_ctl_mutex); ++ spin_unlock_irq(&lo->lo_lock); + + if (IS_ERR_OR_NULL(p)) + ret = PTR_ERR(p); +@@ -1007,7 +1007,9 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev) + + kthread_stop(lo->lo_thread); + ++ spin_lock_irq(&lo->lo_lock); + lo->lo_backing_file = NULL; ++ spin_unlock_irq(&lo->lo_lock); + + loop_release_xfer(lo); + lo->transfer = NULL; +diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c +index b536a9c..9ea8c25 100644 +--- a/drivers/block/xen-blkfront.c ++++ b/drivers/block/xen-blkfront.c +@@ -123,8 +123,8 @@ static DEFINE_SPINLOCK(minor_lock); + #define BLKIF_MINOR_EXT(dev) ((dev)&(~EXTENDED)) + #define EMULATED_HD_DISK_MINOR_OFFSET (0) + #define EMULATED_HD_DISK_NAME_OFFSET (EMULATED_HD_DISK_MINOR_OFFSET / 256) +-#define EMULATED_SD_DISK_MINOR_OFFSET (EMULATED_HD_DISK_MINOR_OFFSET + (4 * 16)) +-#define EMULATED_SD_DISK_NAME_OFFSET (EMULATED_HD_DISK_NAME_OFFSET + 4) ++#define EMULATED_SD_DISK_MINOR_OFFSET (0) ++#define EMULATED_SD_DISK_NAME_OFFSET (EMULATED_SD_DISK_MINOR_OFFSET / 256) + + #define DEV_NAME "xvd" /* name in /dev */ + +@@ -529,7 +529,7 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity, + minor = BLKIF_MINOR_EXT(info->vdevice); + nr_parts = PARTS_PER_EXT_DISK; + offset = minor / nr_parts; +- if (xen_hvm_domain() && offset <= EMULATED_HD_DISK_NAME_OFFSET + 4) ++ if (xen_hvm_domain() && offset < EMULATED_HD_DISK_NAME_OFFSET + 4) + printk(KERN_WARNING "blkfront: vdevice 0x%x might conflict with " + "emulated IDE disks,\n\t choose an xvd device name" + "from xvde on\n", info->vdevice); +diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c +index 04f1e7c..f6cf448 100644 +--- a/drivers/edac/i7core_edac.c ++++ b/drivers/edac/i7core_edac.c +@@ -1670,7 +1670,7 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci, + char *type, *optype, *err, *msg; + unsigned long error = m->status & 0x1ff0000l; + u32 optypenum = (m->status >> 4) & 0x07; +- u32 core_err_cnt = (m->status >> 38) && 0x7fff; ++ u32 core_err_cnt = (m->status >> 38) & 0x7fff; + u32 dimm = (m->misc >> 16) & 0x3; + u32 channel = (m->misc >> 18) & 0x3; + u32 syndrome = m->misc >> 32; +diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c +index 6ab6c41..d1b36f8 100644 +--- a/drivers/gpu/drm/radeon/radeon_connectors.c ++++ b/drivers/gpu/drm/radeon/radeon_connectors.c +@@ -466,6 +466,16 @@ static bool radeon_connector_needs_extended_probe(struct radeon_device *dev, + (supported_device == ATOM_DEVICE_DFP2_SUPPORT)) + return true; + } ++ /* TOSHIBA Satellite L300D with ATI Mobility Radeon x1100 ++ * (RS690M) sends data to i2c bus for a HDMI connector that ++ * is not implemented */ ++ if ((dev->pdev->device == 0x791f) && ++ (dev->pdev->subsystem_vendor == 0x1179) && ++ (dev->pdev->subsystem_device == 0xff68)) { ++ if ((connector_type == DRM_MODE_CONNECTOR_HDMIA) && ++ (supported_device == ATOM_DEVICE_DFP2_SUPPORT)) ++ return true; ++ } + + /* Default: no EDID header probe required for DDC probing */ + return false; +diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c +index 2e618b5..b7f0726 100644 +--- a/drivers/gpu/drm/ttm/ttm_bo.c ++++ b/drivers/gpu/drm/ttm/ttm_bo.c +@@ -353,8 +353,10 @@ static int ttm_bo_add_ttm(struct ttm_buffer_object *bo, bool zero_alloc) + + ret = ttm_tt_set_user(bo->ttm, current, + bo->buffer_start, bo->num_pages); +- if (unlikely(ret != 0)) ++ if (unlikely(ret != 0)) { + ttm_tt_destroy(bo->ttm); ++ bo->ttm = NULL; ++ } + break; + default: + printk(KERN_ERR TTM_PFX "Illegal buffer object type\n"); +diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c +index 58d5436..6d3de08 100644 +--- a/drivers/mmc/host/sdhci.c ++++ b/drivers/mmc/host/sdhci.c +@@ -1863,9 +1863,6 @@ static void sdhci_tasklet_finish(unsigned long param) + + del_timer(&host->timer); + +- if (host->version >= SDHCI_SPEC_300) +- del_timer(&host->tuning_timer); +- + mrq = host->mrq; + + /* +diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c +index 0f563c8..493e331 100644 +--- a/drivers/net/igb/e1000_82575.c ++++ b/drivers/net/igb/e1000_82575.c +@@ -1735,6 +1735,7 @@ static s32 igb_reset_hw_82580(struct e1000_hw *hw) + ctrl |= E1000_CTRL_RST; + + wr32(E1000_CTRL, ctrl); ++ wrfl(); + + /* Add delay to insure DEV_RST has time to complete */ + if (global_device_reset) +diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c +index 8f90f62..241a099 100644 +--- a/drivers/net/wireless/rt2x00/rt2x00usb.c ++++ b/drivers/net/wireless/rt2x00/rt2x00usb.c +@@ -262,23 +262,20 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) + struct queue_entry *entry = (struct queue_entry *)urb->context; + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + +- if (!test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) ++ if (!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) + return; +- +- if (rt2x00dev->ops->lib->tx_dma_done) +- rt2x00dev->ops->lib->tx_dma_done(entry); +- +- /* +- * Report the frame as DMA done +- */ +- rt2x00lib_dmadone(entry); +- + /* + * Check if the frame was correctly uploaded + */ + if (urb->status) + set_bit(ENTRY_DATA_IO_FAILED, &entry->flags); ++ /* ++ * Report the frame as DMA done ++ */ ++ rt2x00lib_dmadone(entry); + ++ if (rt2x00dev->ops->lib->tx_dma_done) ++ rt2x00dev->ops->lib->tx_dma_done(entry); + /* + * Schedule the delayed work for reading the TX status + * from the device. +diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c +index 54b8c28..720d885 100644 +--- a/fs/befs/linuxvfs.c ++++ b/fs/befs/linuxvfs.c +@@ -474,17 +474,22 @@ befs_follow_link(struct dentry *dentry, struct nameidata *nd) + befs_data_stream *data = &befs_ino->i_data.ds; + befs_off_t len = data->size; + +- befs_debug(sb, "Follow long symlink"); +- +- link = kmalloc(len, GFP_NOFS); +- if (!link) { +- link = ERR_PTR(-ENOMEM); +- } else if (befs_read_lsymlink(sb, data, link, len) != len) { +- kfree(link); +- befs_error(sb, "Failed to read entire long symlink"); ++ if (len == 0) { ++ befs_error(sb, "Long symlink with illegal length"); + link = ERR_PTR(-EIO); + } else { +- link[len - 1] = '\0'; ++ befs_debug(sb, "Follow long symlink"); ++ ++ link = kmalloc(len, GFP_NOFS); ++ if (!link) { ++ link = ERR_PTR(-ENOMEM); ++ } else if (befs_read_lsymlink(sb, data, link, len) != len) { ++ kfree(link); ++ befs_error(sb, "Failed to read entire long symlink"); ++ link = ERR_PTR(-EIO); ++ } else { ++ link[len - 1] = '\0'; ++ } + } + } else { + link = befs_ino->i_data.symlink; +diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c +index 71cd456..7e20a65 100644 +--- a/fs/btrfs/extent-tree.c ++++ b/fs/btrfs/extent-tree.c +@@ -1784,6 +1784,9 @@ static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr, + + + for (i = 0; i < multi->num_stripes; i++, stripe++) { ++ if (!stripe->dev->can_discard) ++ continue; ++ + ret = btrfs_issue_discard(stripe->dev->bdev, + stripe->physical, + stripe->length); +@@ -1791,11 +1794,16 @@ static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr, + discarded_bytes += stripe->length; + else if (ret != -EOPNOTSUPP) + break; ++ ++ /* ++ * Just in case we get back EOPNOTSUPP for some reason, ++ * just ignore the return value so we don't screw up ++ * people calling discard_extent. ++ */ ++ ret = 0; + } + kfree(multi); + } +- if (discarded_bytes && ret == -EOPNOTSUPP) +- ret = 0; + + if (actual_bytes) + *actual_bytes = discarded_bytes; +diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c +index 4ce8a9f..7fa128d 100644 +--- a/fs/btrfs/tree-log.c ++++ b/fs/btrfs/tree-log.c +@@ -799,14 +799,15 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, + struct extent_buffer *eb, int slot, + struct btrfs_key *key) + { +- struct inode *dir; +- int ret; + struct btrfs_inode_ref *ref; ++ struct btrfs_dir_item *di; ++ struct inode *dir; + struct inode *inode; +- char *name; +- int namelen; + unsigned long ref_ptr; + unsigned long ref_end; ++ char *name; ++ int namelen; ++ int ret; + int search_done = 0; + + /* +@@ -909,6 +910,25 @@ again: + } + btrfs_release_path(path); + ++ /* look for a conflicting sequence number */ ++ di = btrfs_lookup_dir_index_item(trans, root, path, btrfs_ino(dir), ++ btrfs_inode_ref_index(eb, ref), ++ name, namelen, 0); ++ if (di && !IS_ERR(di)) { ++ ret = drop_one_dir_item(trans, root, path, dir, di); ++ BUG_ON(ret); ++ } ++ btrfs_release_path(path); ++ ++ /* look for a conflicing name */ ++ di = btrfs_lookup_dir_item(trans, root, path, btrfs_ino(dir), ++ name, namelen, 0); ++ if (di && !IS_ERR(di)) { ++ ret = drop_one_dir_item(trans, root, path, dir, di); ++ BUG_ON(ret); ++ } ++ btrfs_release_path(path); ++ + insert: + /* insert our name */ + ret = btrfs_add_link(trans, dir, inode, name, namelen, 0, +diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c +index 19450bc..43baaf0 100644 +--- a/fs/btrfs/volumes.c ++++ b/fs/btrfs/volumes.c +@@ -500,6 +500,9 @@ static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices) + fs_devices->rw_devices--; + } + ++ if (device->can_discard) ++ fs_devices->num_can_discard--; ++ + new_device = kmalloc(sizeof(*new_device), GFP_NOFS); + BUG_ON(!new_device); + memcpy(new_device, device, sizeof(*new_device)); +@@ -508,6 +511,7 @@ static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices) + new_device->bdev = NULL; + new_device->writeable = 0; + new_device->in_fs_metadata = 0; ++ new_device->can_discard = 0; + list_replace_rcu(&device->dev_list, &new_device->dev_list); + + call_rcu(&device->rcu, free_device); +@@ -547,6 +551,7 @@ int btrfs_close_devices(struct btrfs_fs_devices *fs_devices) + static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices, + fmode_t flags, void *holder) + { ++ struct request_queue *q; + struct block_device *bdev; + struct list_head *head = &fs_devices->devices; + struct btrfs_device *device; +@@ -603,6 +608,12 @@ static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices, + seeding = 0; + } + ++ q = bdev_get_queue(bdev); ++ if (blk_queue_discard(q)) { ++ device->can_discard = 1; ++ fs_devices->num_can_discard++; ++ } ++ + device->bdev = bdev; + device->in_fs_metadata = 0; + device->mode = flags; +@@ -1542,6 +1553,7 @@ error: + + int btrfs_init_new_device(struct btrfs_root *root, char *device_path) + { ++ struct request_queue *q; + struct btrfs_trans_handle *trans; + struct btrfs_device *device; + struct block_device *bdev; +@@ -1611,6 +1623,9 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) + + lock_chunks(root); + ++ q = bdev_get_queue(bdev); ++ if (blk_queue_discard(q)) ++ device->can_discard = 1; + device->writeable = 1; + device->work.func = pending_bios_fn; + generate_random_uuid(device->uuid); +@@ -1646,6 +1661,8 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) + root->fs_info->fs_devices->num_devices++; + root->fs_info->fs_devices->open_devices++; + root->fs_info->fs_devices->rw_devices++; ++ if (device->can_discard) ++ root->fs_info->fs_devices->num_can_discard++; + root->fs_info->fs_devices->total_rw_bytes += device->total_bytes; + + if (!blk_queue_nonrot(bdev_get_queue(bdev))) +diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h +index 7c12d61..6d866db 100644 +--- a/fs/btrfs/volumes.h ++++ b/fs/btrfs/volumes.h +@@ -48,6 +48,7 @@ struct btrfs_device { + int writeable; + int in_fs_metadata; + int missing; ++ int can_discard; + + spinlock_t io_lock; + +@@ -104,6 +105,7 @@ struct btrfs_fs_devices { + u64 rw_devices; + u64 missing_devices; + u64 total_rw_bytes; ++ u64 num_can_discard; + struct block_device *latest_bdev; + + /* all of the devices in the FS, protected by a mutex +diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c +index ccc1afa..e0ea721 100644 +--- a/fs/cifs/connect.c ++++ b/fs/cifs/connect.c +@@ -2838,7 +2838,8 @@ cleanup_volume_info_contents(struct smb_vol *volume_info) + kfree(volume_info->username); + kzfree(volume_info->password); + kfree(volume_info->UNC); +- kfree(volume_info->UNCip); ++ if (volume_info->UNCip != volume_info->UNC + 2) ++ kfree(volume_info->UNCip); + kfree(volume_info->domainname); + kfree(volume_info->iocharset); + kfree(volume_info->prepath); +diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c +index d8d26f3..16cdd6d 100644 +--- a/fs/cifs/dir.c ++++ b/fs/cifs/dir.c +@@ -110,8 +110,8 @@ cifs_bp_rename_retry: + } + rcu_read_unlock(); + if (namelen != dfsplen || read_seqretry(&rename_lock, seq)) { +- cERROR(1, "did not end path lookup where expected namelen is %d", +- namelen); ++ cFYI(1, "did not end path lookup where expected. namelen=%d " ++ "dfsplen=%d", namelen, dfsplen); + /* presumably this is only possible if racing with a rename + of one of the parent directories (we can not lock the dentries + above us to prevent this, but retrying should be harmless) */ +diff --git a/fs/ext4/ext4_jbd2.h b/fs/ext4/ext4_jbd2.h +index bb85757..5802fa1 100644 +--- a/fs/ext4/ext4_jbd2.h ++++ b/fs/ext4/ext4_jbd2.h +@@ -289,10 +289,10 @@ static inline int ext4_should_order_data(struct inode *inode) + + static inline int ext4_should_writeback_data(struct inode *inode) + { +- if (!S_ISREG(inode->i_mode)) +- return 0; + if (EXT4_JOURNAL(inode) == NULL) + return 1; ++ if (!S_ISREG(inode->i_mode)) ++ return 0; + if (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA)) + return 0; + if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA) +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index e3126c0..b864839 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -189,6 +189,12 @@ void ext4_evict_inode(struct inode *inode) + int err; + + trace_ext4_evict_inode(inode); ++ ++ mutex_lock(&inode->i_mutex); ++ ext4_flush_completed_IO(inode); ++ mutex_unlock(&inode->i_mutex); ++ ext4_ioend_wait(inode); ++ + if (inode->i_nlink) { + truncate_inode_pages(&inode->i_data, 0); + goto no_delete; +@@ -1849,6 +1855,8 @@ static int ext4_journalled_write_end(struct file *file, + from = pos & (PAGE_CACHE_SIZE - 1); + to = from + len; + ++ BUG_ON(!ext4_handle_valid(handle)); ++ + if (copied < len) { + if (!PageUptodate(page)) + copied = 0; +@@ -2148,7 +2156,12 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd, + else if (test_opt(inode->i_sb, MBLK_IO_SUBMIT)) + err = ext4_bio_write_page(&io_submit, page, + len, mpd->wbc); +- else ++ else if (buffer_uninit(page_bufs)) { ++ ext4_set_bh_endio(page_bufs, inode); ++ err = block_write_full_page_endio(page, ++ noalloc_get_block_write, ++ mpd->wbc, ext4_end_io_buffer_write); ++ } else + err = block_write_full_page(page, + noalloc_get_block_write, mpd->wbc); + +@@ -2564,6 +2577,8 @@ static int __ext4_journalled_writepage(struct page *page, + goto out; + } + ++ BUG_ON(!ext4_handle_valid(handle)); ++ + ret = walk_page_buffers(handle, page_bufs, 0, len, NULL, + do_journal_get_write_access); + +@@ -3635,8 +3650,15 @@ static void ext4_end_io_buffer_write(struct buffer_head *bh, int uptodate) + goto out; + } + +- io_end->flag = EXT4_IO_END_UNWRITTEN; ++ /* ++ * It may be over-defensive here to check EXT4_IO_END_UNWRITTEN now, ++ * but being more careful is always safe for the future change. ++ */ + inode = io_end->inode; ++ if (!(io_end->flag & EXT4_IO_END_UNWRITTEN)) { ++ io_end->flag |= EXT4_IO_END_UNWRITTEN; ++ atomic_inc(&EXT4_I(inode)->i_aiodio_unwritten); ++ } + + /* Add the io_end to per-inode completed io list*/ + spin_lock_irqsave(&EXT4_I(inode)->i_completed_io_lock, flags); +diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c +index 7bb8f76..97e5e98 100644 +--- a/fs/ext4/page-io.c ++++ b/fs/ext4/page-io.c +@@ -338,8 +338,10 @@ submit_and_retry: + if ((io_end->num_io_pages >= MAX_IO_PAGES) && + (io_end->pages[io_end->num_io_pages-1] != io_page)) + goto submit_and_retry; +- if (buffer_uninit(bh)) +- io->io_end->flag |= EXT4_IO_END_UNWRITTEN; ++ if (buffer_uninit(bh) && !(io_end->flag & EXT4_IO_END_UNWRITTEN)) { ++ io_end->flag |= EXT4_IO_END_UNWRITTEN; ++ atomic_inc(&EXT4_I(inode)->i_aiodio_unwritten); ++ } + io->io_end->size += bh->b_size; + io->io_next_block++; + ret = bio_add_page(io->io_bio, bh->b_page, bh->b_size, bh_offset(bh)); +diff --git a/fs/ext4/super.c b/fs/ext4/super.c +index 9ea71aa..111ed9d 100644 +--- a/fs/ext4/super.c ++++ b/fs/ext4/super.c +@@ -892,7 +892,6 @@ static void ext4_i_callback(struct rcu_head *head) + + static void ext4_destroy_inode(struct inode *inode) + { +- ext4_ioend_wait(inode); + if (!list_empty(&(EXT4_I(inode)->i_orphan))) { + ext4_msg(inode->i_sb, KERN_ERR, + "Inode %lu (%p): orphan list check failed!", +diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c +index 640fc22..168a80f 100644 +--- a/fs/fuse/dev.c ++++ b/fs/fuse/dev.c +@@ -1358,6 +1358,10 @@ static int fuse_notify_inval_entry(struct fuse_conn *fc, unsigned int size, + if (outarg.namelen > FUSE_NAME_MAX) + goto err; + ++ err = -EINVAL; ++ if (size != sizeof(outarg) + outarg.namelen + 1) ++ goto err; ++ + name.name = buf; + name.len = outarg.namelen; + err = fuse_copy_one(cs, buf, outarg.namelen + 1); +diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h +index b257383..07df5f1 100644 +--- a/fs/nfs/callback.h ++++ b/fs/nfs/callback.h +@@ -38,6 +38,7 @@ enum nfs4_callback_opnum { + struct cb_process_state { + __be32 drc_status; + struct nfs_client *clp; ++ int slotid; + }; + + struct cb_compound_hdr_arg { +@@ -166,7 +167,6 @@ extern unsigned nfs4_callback_layoutrecall( + void *dummy, struct cb_process_state *cps); + + extern void nfs4_check_drain_bc_complete(struct nfs4_session *ses); +-extern void nfs4_cb_take_slot(struct nfs_client *clp); + + struct cb_devicenotifyitem { + uint32_t cbd_notify_type; +diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c +index d4d1954..aaa09e9 100644 +--- a/fs/nfs/callback_proc.c ++++ b/fs/nfs/callback_proc.c +@@ -333,7 +333,7 @@ validate_seqid(struct nfs4_slot_table *tbl, struct cb_sequenceargs * args) + /* Normal */ + if (likely(args->csa_sequenceid == slot->seq_nr + 1)) { + slot->seq_nr++; +- return htonl(NFS4_OK); ++ goto out_ok; + } + + /* Replay */ +@@ -352,11 +352,14 @@ validate_seqid(struct nfs4_slot_table *tbl, struct cb_sequenceargs * args) + /* Wraparound */ + if (args->csa_sequenceid == 1 && (slot->seq_nr + 1) == 0) { + slot->seq_nr = 1; +- return htonl(NFS4_OK); ++ goto out_ok; + } + + /* Misordered request */ + return htonl(NFS4ERR_SEQ_MISORDERED); ++out_ok: ++ tbl->highest_used_slotid = args->csa_slotid; ++ return htonl(NFS4_OK); + } + + /* +@@ -418,26 +421,37 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args, + struct cb_sequenceres *res, + struct cb_process_state *cps) + { ++ struct nfs4_slot_table *tbl; + struct nfs_client *clp; + int i; + __be32 status = htonl(NFS4ERR_BADSESSION); + +- cps->clp = NULL; +- + clp = nfs4_find_client_sessionid(args->csa_addr, &args->csa_sessionid); + if (clp == NULL) + goto out; + ++ tbl = &clp->cl_session->bc_slot_table; ++ ++ spin_lock(&tbl->slot_tbl_lock); + /* state manager is resetting the session */ + if (test_bit(NFS4_SESSION_DRAINING, &clp->cl_session->session_state)) { +- status = NFS4ERR_DELAY; ++ spin_unlock(&tbl->slot_tbl_lock); ++ status = htonl(NFS4ERR_DELAY); ++ /* Return NFS4ERR_BADSESSION if we're draining the session ++ * in order to reset it. ++ */ ++ if (test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state)) ++ status = htonl(NFS4ERR_BADSESSION); + goto out; + } + + status = validate_seqid(&clp->cl_session->bc_slot_table, args); ++ spin_unlock(&tbl->slot_tbl_lock); + if (status) + goto out; + ++ cps->slotid = args->csa_slotid; ++ + /* + * Check for pending referring calls. If a match is found, a + * related callback was received before the response to the original +@@ -454,7 +468,6 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args, + res->csr_slotid = args->csa_slotid; + res->csr_highestslotid = NFS41_BC_MAX_CALLBACKS - 1; + res->csr_target_highestslotid = NFS41_BC_MAX_CALLBACKS - 1; +- nfs4_cb_take_slot(clp); + + out: + cps->clp = clp; /* put in nfs4_callback_compound */ +diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c +index c6c86a7..918ad64 100644 +--- a/fs/nfs/callback_xdr.c ++++ b/fs/nfs/callback_xdr.c +@@ -754,26 +754,15 @@ static void nfs4_callback_free_slot(struct nfs4_session *session) + * Let the state manager know callback processing done. + * A single slot, so highest used slotid is either 0 or -1 + */ +- tbl->highest_used_slotid--; ++ tbl->highest_used_slotid = -1; + nfs4_check_drain_bc_complete(session); + spin_unlock(&tbl->slot_tbl_lock); + } + +-static void nfs4_cb_free_slot(struct nfs_client *clp) ++static void nfs4_cb_free_slot(struct cb_process_state *cps) + { +- if (clp && clp->cl_session) +- nfs4_callback_free_slot(clp->cl_session); +-} +- +-/* A single slot, so highest used slotid is either 0 or -1 */ +-void nfs4_cb_take_slot(struct nfs_client *clp) +-{ +- struct nfs4_slot_table *tbl = &clp->cl_session->bc_slot_table; +- +- spin_lock(&tbl->slot_tbl_lock); +- tbl->highest_used_slotid++; +- BUG_ON(tbl->highest_used_slotid != 0); +- spin_unlock(&tbl->slot_tbl_lock); ++ if (cps->slotid != -1) ++ nfs4_callback_free_slot(cps->clp->cl_session); + } + + #else /* CONFIG_NFS_V4_1 */ +@@ -784,7 +773,7 @@ preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op) + return htonl(NFS4ERR_MINOR_VERS_MISMATCH); + } + +-static void nfs4_cb_free_slot(struct nfs_client *clp) ++static void nfs4_cb_free_slot(struct cb_process_state *cps) + { + } + #endif /* CONFIG_NFS_V4_1 */ +@@ -866,6 +855,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r + struct cb_process_state cps = { + .drc_status = 0, + .clp = NULL, ++ .slotid = -1, + }; + unsigned int nops = 0; + +@@ -906,7 +896,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r + + *hdr_res.status = status; + *hdr_res.nops = htonl(nops); +- nfs4_cb_free_slot(cps.clp); ++ nfs4_cb_free_slot(&cps); + nfs_put_client(cps.clp); + dprintk("%s: done, status = %u\n", __func__, ntohl(status)); + return rpc_success; +diff --git a/fs/nfs/objlayout/objio_osd.c b/fs/nfs/objlayout/objio_osd.c +index 8ff2ea3..1d1dc1e 100644 +--- a/fs/nfs/objlayout/objio_osd.c ++++ b/fs/nfs/objlayout/objio_osd.c +@@ -479,7 +479,6 @@ static int _io_check(struct objio_state *ios, bool is_write) + for (i = 0; i < ios->numdevs; i++) { + struct osd_sense_info osi; + struct osd_request *or = ios->per_dev[i].or; +- unsigned dev; + int ret; + + if (!or) +@@ -500,9 +499,8 @@ static int _io_check(struct objio_state *ios, bool is_write) + + continue; /* we recovered */ + } +- dev = ios->per_dev[i].dev; +- objlayout_io_set_result(&ios->ol_state, dev, +- &ios->layout->comps[dev].oc_object_id, ++ objlayout_io_set_result(&ios->ol_state, i, ++ &ios->layout->comps[i].oc_object_id, + osd_pri_2_pnfs_err(osi.osd_err_pri), + ios->per_dev[i].offset, + ios->per_dev[i].length, +@@ -589,22 +587,19 @@ static void _calc_stripe_info(struct objio_state *ios, u64 file_offset, + } + + static int _add_stripe_unit(struct objio_state *ios, unsigned *cur_pg, +- unsigned pgbase, struct _objio_per_comp *per_dev, int cur_len, ++ unsigned pgbase, struct _objio_per_comp *per_dev, int len, + gfp_t gfp_flags) + { + unsigned pg = *cur_pg; ++ int cur_len = len; + struct request_queue *q = + osd_request_queue(_io_od(ios, per_dev->dev)); + +- per_dev->length += cur_len; +- + if (per_dev->bio == NULL) { +- unsigned stripes = ios->layout->num_comps / +- ios->layout->mirrors_p1; +- unsigned pages_in_stripe = stripes * ++ unsigned pages_in_stripe = ios->layout->group_width * + (ios->layout->stripe_unit / PAGE_SIZE); + unsigned bio_size = (ios->ol_state.nr_pages + pages_in_stripe) / +- stripes; ++ ios->layout->group_width; + + if (BIO_MAX_PAGES_KMALLOC < bio_size) + bio_size = BIO_MAX_PAGES_KMALLOC; +@@ -632,6 +627,7 @@ static int _add_stripe_unit(struct objio_state *ios, unsigned *cur_pg, + } + BUG_ON(cur_len); + ++ per_dev->length += len; + *cur_pg = pg; + return 0; + } +@@ -650,7 +646,7 @@ static int _prepare_one_group(struct objio_state *ios, u64 length, + int ret = 0; + + while (length) { +- struct _objio_per_comp *per_dev = &ios->per_dev[dev]; ++ struct _objio_per_comp *per_dev = &ios->per_dev[dev - first_dev]; + unsigned cur_len, page_off = 0; + + if (!per_dev->length) { +@@ -670,8 +666,8 @@ static int _prepare_one_group(struct objio_state *ios, u64 length, + cur_len = stripe_unit; + } + +- if (max_comp < dev) +- max_comp = dev; ++ if (max_comp < dev - first_dev) ++ max_comp = dev - first_dev; + } else { + cur_len = stripe_unit; + } +@@ -806,7 +802,7 @@ static int _read_mirrors(struct objio_state *ios, unsigned cur_comp) + struct _objio_per_comp *per_dev = &ios->per_dev[cur_comp]; + unsigned dev = per_dev->dev; + struct pnfs_osd_object_cred *cred = +- &ios->layout->comps[dev]; ++ &ios->layout->comps[cur_comp]; + struct osd_obj_id obj = { + .partition = cred->oc_object_id.oid_partition_id, + .id = cred->oc_object_id.oid_object_id, +@@ -904,7 +900,7 @@ static int _write_mirrors(struct objio_state *ios, unsigned cur_comp) + for (; cur_comp < last_comp; ++cur_comp, ++dev) { + struct osd_request *or = NULL; + struct pnfs_osd_object_cred *cred = +- &ios->layout->comps[dev]; ++ &ios->layout->comps[cur_comp]; + struct osd_obj_id obj = { + .partition = cred->oc_object_id.oid_partition_id, + .id = cred->oc_object_id.oid_object_id, +diff --git a/fs/nfs/objlayout/pnfs_osd_xdr_cli.c b/fs/nfs/objlayout/pnfs_osd_xdr_cli.c +index 16fc758..b3918f7 100644 +--- a/fs/nfs/objlayout/pnfs_osd_xdr_cli.c ++++ b/fs/nfs/objlayout/pnfs_osd_xdr_cli.c +@@ -170,6 +170,9 @@ int pnfs_osd_xdr_decode_layout_map(struct pnfs_osd_layout *layout, + p = _osd_xdr_decode_data_map(p, &layout->olo_map); + layout->olo_comps_index = be32_to_cpup(p++); + layout->olo_num_comps = be32_to_cpup(p++); ++ dprintk("%s: olo_comps_index=%d olo_num_comps=%d\n", __func__, ++ layout->olo_comps_index, layout->olo_num_comps); ++ + iter->total_comps = layout->olo_num_comps; + return 0; + } +diff --git a/include/linux/personality.h b/include/linux/personality.h +index eec3bae..8fc7dd1a 100644 +--- a/include/linux/personality.h ++++ b/include/linux/personality.h +@@ -22,6 +22,7 @@ extern int __set_personality(unsigned int); + * These occupy the top three bytes. + */ + enum { ++ UNAME26 = 0x0020000, + ADDR_NO_RANDOMIZE = 0x0040000, /* disable randomization of VA space */ + FDPIC_FUNCPTRS = 0x0080000, /* userspace function ptrs point to descriptors + * (signal handling) +diff --git a/include/linux/stop_machine.h b/include/linux/stop_machine.h +index 092dc9b..14d3524 100644 +--- a/include/linux/stop_machine.h ++++ b/include/linux/stop_machine.h +@@ -27,6 +27,8 @@ struct cpu_stop_work { + struct cpu_stop_done *done; + }; + ++extern struct mutex stop_cpus_mutex; ++ + int stop_one_cpu(unsigned int cpu, cpu_stop_fn_t fn, void *arg); + void stop_one_cpu_nowait(unsigned int cpu, cpu_stop_fn_t fn, void *arg, + struct cpu_stop_work *work_buf); +diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c +index 3a2cab4..e38544d 100644 +--- a/kernel/irq/generic-chip.c ++++ b/kernel/irq/generic-chip.c +@@ -246,7 +246,7 @@ void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk, + gc->mask_cache = irq_reg_readl(gc->reg_base + ct->regs.mask); + + for (i = gc->irq_base; msk; msk >>= 1, i++) { +- if (!msk & 0x01) ++ if (!(msk & 0x01)) + continue; + + if (flags & IRQ_GC_INIT_NESTED_LOCK) +@@ -301,7 +301,7 @@ void irq_remove_generic_chip(struct irq_chip_generic *gc, u32 msk, + raw_spin_unlock(&gc_lock); + + for (; msk; msk >>= 1, i++) { +- if (!msk & 0x01) ++ if (!(msk & 0x01)) + continue; + + /* Remove handler first. That will mask the irq line */ +diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c +index e3516b2..0cae1cc 100644 +--- a/kernel/stop_machine.c ++++ b/kernel/stop_machine.c +@@ -132,8 +132,8 @@ void stop_one_cpu_nowait(unsigned int cpu, cpu_stop_fn_t fn, void *arg, + cpu_stop_queue_work(&per_cpu(cpu_stopper, cpu), work_buf); + } + ++DEFINE_MUTEX(stop_cpus_mutex); + /* static data for stop_cpus */ +-static DEFINE_MUTEX(stop_cpus_mutex); + static DEFINE_PER_CPU(struct cpu_stop_work, stop_cpus_work); + + int __stop_cpus(const struct cpumask *cpumask, cpu_stop_fn_t fn, void *arg) +diff --git a/kernel/sys.c b/kernel/sys.c +index e4128b2..5c942cf 100644 +--- a/kernel/sys.c ++++ b/kernel/sys.c +@@ -38,6 +38,8 @@ + #include + #include + #include ++#include ++#include + + #include + #include +@@ -45,6 +47,8 @@ + #include + + #include ++/* Move somewhere else to avoid recompiling? */ ++#include + + #include + #include +@@ -1124,6 +1128,34 @@ DECLARE_RWSEM(uts_sem); + #define override_architecture(name) 0 + #endif + ++/* ++ * Work around broken programs that cannot handle "Linux 3.0". ++ * Instead we map 3.x to 2.6.40+x, so e.g. 3.0 would be 2.6.40 ++ */ ++static int override_release(char __user *release, int len) ++{ ++ int ret = 0; ++ char buf[len]; ++ ++ if (current->personality & UNAME26) { ++ char *rest = UTS_RELEASE; ++ int ndots = 0; ++ unsigned v; ++ ++ while (*rest) { ++ if (*rest == '.' && ++ndots >= 3) ++ break; ++ if (!isdigit(*rest) && *rest != '.') ++ break; ++ rest++; ++ } ++ v = ((LINUX_VERSION_CODE >> 8) & 0xff) + 40; ++ snprintf(buf, len, "2.6.%u%s", v, rest); ++ ret = copy_to_user(release, buf, len); ++ } ++ return ret; ++} ++ + SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) + { + int errno = 0; +@@ -1133,6 +1165,8 @@ SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) + errno = -EFAULT; + up_read(&uts_sem); + ++ if (!errno && override_release(name->release, sizeof(name->release))) ++ errno = -EFAULT; + if (!errno && override_architecture(name)) + errno = -EFAULT; + return errno; +@@ -1154,6 +1188,8 @@ SYSCALL_DEFINE1(uname, struct old_utsname __user *, name) + error = -EFAULT; + up_read(&uts_sem); + ++ if (!error && override_release(name->release, sizeof(name->release))) ++ error = -EFAULT; + if (!error && override_architecture(name)) + error = -EFAULT; + return error; +@@ -1188,6 +1224,8 @@ SYSCALL_DEFINE1(olduname, struct oldold_utsname __user *, name) + + if (!error && override_architecture(name)) + error = -EFAULT; ++ if (!error && override_release(name->release, sizeof(name->release))) ++ error = -EFAULT; + return error ? -EFAULT : 0; + } + #endif +diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c +index 200c9a1..a872d0a 100644 +--- a/sound/pci/ac97/ac97_patch.c ++++ b/sound/pci/ac97/ac97_patch.c +@@ -1909,6 +1909,7 @@ static unsigned int ad1981_jacks_whitelist[] = { + 0x103c0944, /* HP nc6220 */ + 0x103c0934, /* HP nc8220 */ + 0x103c006d, /* HP nx9105 */ ++ 0x103c300d, /* HP Compaq dc5100 SFF(PT003AW) */ + 0x17340088, /* FSC Scenic-W */ + 0 /* end */ + }; +diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c +index aa52b3e..2cf87f5 100644 +--- a/sound/usb/caiaq/audio.c ++++ b/sound/usb/caiaq/audio.c +@@ -139,8 +139,12 @@ static void stream_stop(struct snd_usb_caiaqdev *dev) + + for (i = 0; i < N_URBS; i++) { + usb_kill_urb(dev->data_urbs_in[i]); +- usb_kill_urb(dev->data_urbs_out[i]); ++ ++ if (test_bit(i, &dev->outurb_active_mask)) ++ usb_kill_urb(dev->data_urbs_out[i]); + } ++ ++ dev->outurb_active_mask = 0; + } + + static int snd_usb_caiaq_substream_open(struct snd_pcm_substream *substream) +@@ -612,8 +616,8 @@ static void read_completed(struct urb *urb) + { + struct snd_usb_caiaq_cb_info *info = urb->context; + struct snd_usb_caiaqdev *dev; +- struct urb *out; +- int frame, len, send_it = 0, outframe = 0; ++ struct urb *out = NULL; ++ int i, frame, len, send_it = 0, outframe = 0; + size_t offset = 0; + + if (urb->status || !info) +@@ -624,7 +628,17 @@ static void read_completed(struct urb *urb) + if (!dev->streaming) + return; + +- out = dev->data_urbs_out[info->index]; ++ /* find an unused output urb that is unused */ ++ for (i = 0; i < N_URBS; i++) ++ if (test_and_set_bit(i, &dev->outurb_active_mask) == 0) { ++ out = dev->data_urbs_out[i]; ++ break; ++ } ++ ++ if (!out) { ++ log("Unable to find an output urb to use\n"); ++ goto requeue; ++ } + + /* read the recently received packet and send back one which has + * the same layout */ +@@ -655,8 +669,12 @@ static void read_completed(struct urb *urb) + out->number_of_packets = outframe; + out->transfer_flags = URB_ISO_ASAP; + usb_submit_urb(out, GFP_ATOMIC); ++ } else { ++ struct snd_usb_caiaq_cb_info *oinfo = out->context; ++ clear_bit(oinfo->index, &dev->outurb_active_mask); + } + ++requeue: + /* re-submit inbound urb */ + for (frame = 0; frame < FRAMES_PER_URB; frame++) { + urb->iso_frame_desc[frame].offset = BYTES_PER_FRAME * frame; +@@ -678,6 +696,8 @@ static void write_completed(struct urb *urb) + dev->output_running = 1; + wake_up(&dev->prepare_wait_queue); + } ++ ++ clear_bit(info->index, &dev->outurb_active_mask); + } + + static struct urb **alloc_urbs(struct snd_usb_caiaqdev *dev, int dir, int *ret) +@@ -829,6 +849,9 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev) + if (!dev->data_cb_info) + return -ENOMEM; + ++ dev->outurb_active_mask = 0; ++ BUILD_BUG_ON(N_URBS > (sizeof(dev->outurb_active_mask) * 8)); ++ + for (i = 0; i < N_URBS; i++) { + dev->data_cb_info[i].dev = dev; + dev->data_cb_info[i].index = i; +diff --git a/sound/usb/caiaq/device.h b/sound/usb/caiaq/device.h +index b2b3101..3f9c633 100644 +--- a/sound/usb/caiaq/device.h ++++ b/sound/usb/caiaq/device.h +@@ -96,6 +96,7 @@ struct snd_usb_caiaqdev { + int input_panic, output_panic, warned; + char *audio_in_buf, *audio_out_buf; + unsigned int samplerates, bpp; ++ unsigned long outurb_active_mask; + + struct snd_pcm_substream *sub_playback[MAX_STREAMS]; + struct snd_pcm_substream *sub_capture[MAX_STREAMS]; +diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c +index c04d7c7..cdd19d7 100644 +--- a/sound/usb/mixer.c ++++ b/sound/usb/mixer.c +@@ -152,6 +152,7 @@ static inline void check_mapped_dB(const struct usbmix_name_map *p, + if (p && p->dB) { + cval->dBmin = p->dB->min; + cval->dBmax = p->dB->max; ++ cval->initialized = 1; + } + } + +@@ -1092,7 +1093,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, + " Switch" : " Volume"); + if (control == UAC_FU_VOLUME) { + check_mapped_dB(map, cval); +- if (cval->dBmin < cval->dBmax) { ++ if (cval->dBmin < cval->dBmax || !cval->initialized) { + kctl->tlv.c = mixer_vol_tlv; + kctl->vd[0].access |= + SNDRV_CTL_ELEM_ACCESS_TLV_READ | diff --git a/debian/patches/series/4 b/debian/patches/series/4 index 0c11a4b9c..6a02529f7 100644 --- a/debian/patches/series/4 +++ b/debian/patches/series/4 @@ -1 +1,9 @@ + bugfix/alpha/alpha-gpio-GENERIC_GPIO-default-must-be-n.patch + +- bugfix/all/fuse-check-size-of-fuse_notify_inval_entry-message.patch +- bugfix/all/drm-ttm-fix-ttm_bo_add_ttm-user-failure-path.patch +- bugfix/all/x86-32-vdso-on-system-call-restart-after-sysenter-use-int.patch +- bugfix/all/cifs-possible-memory-corruption-on-mount.patch +- bugfix/all/befs-validate-length-of-long-symbolic-links.patch +- bugfix/all/genirq-fix-wrong-bit-operation.patch ++ bugfix/all/stable/3.0.4.patch