lkml.org 
[lkml]   [2011]   [Oct]   [25]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    SubjectRe: Linux 3.0.8
    diff --git a/Makefile b/Makefile
    index 11c4249..9f6e3cd 100644
    --- a/Makefile
    +++ b/Makefile
    @@ -1,6 +1,6 @@
    VERSION = 3
    PATCHLEVEL = 0
    -SUBLEVEL = 7
    +SUBLEVEL = 8
    EXTRAVERSION =
    NAME = Sneaky Weasel

    diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c
    index 4960686..4372763 100644
    --- a/arch/arm/kernel/perf_event_v7.c
    +++ b/arch/arm/kernel/perf_event_v7.c
    @@ -264,8 +264,8 @@ static const unsigned armv7_a9_perf_map[PERF_COUNT_HW_MAX] = {
    [PERF_COUNT_HW_CPU_CYCLES] = ARMV7_PERFCTR_CPU_CYCLES,
    [PERF_COUNT_HW_INSTRUCTIONS] =
    ARMV7_PERFCTR_INST_OUT_OF_RENAME_STAGE,
    - [PERF_COUNT_HW_CACHE_REFERENCES] = ARMV7_PERFCTR_COHERENT_LINE_HIT,
    - [PERF_COUNT_HW_CACHE_MISSES] = ARMV7_PERFCTR_COHERENT_LINE_MISS,
    + [PERF_COUNT_HW_CACHE_REFERENCES] = ARMV7_PERFCTR_DCACHE_ACCESS,
    + [PERF_COUNT_HW_CACHE_MISSES] = ARMV7_PERFCTR_DCACHE_REFILL,
    [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV7_PERFCTR_PC_WRITE,
    [PERF_COUNT_HW_BRANCH_MISSES] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
    [PERF_COUNT_HW_BUS_CYCLES] = ARMV7_PERFCTR_CLOCK_CYCLES,
    diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
    index c19571c..4a4eba5 100644
    --- a/arch/arm/mm/init.c
    +++ b/arch/arm/mm/init.c
    @@ -473,6 +473,13 @@ static void __init free_unused_memmap(struct meminfo *mi)
    */
    bank_start = min(bank_start,
    ALIGN(prev_bank_end, PAGES_PER_SECTION));
    +#else
    + /*
    + * Align down here since the VM subsystem insists that the
    + * memmap entries are valid from the bank start aligned to
    + * MAX_ORDER_NR_PAGES.
    + */
    + bank_start = round_down(bank_start, MAX_ORDER_NR_PAGES);
    #endif
    /*
    * If we had a previous bank, and there is a space
    diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
    index 3032644..87488b9 100644
    --- a/arch/x86/mm/init.c
    +++ b/arch/x86/mm/init.c
    @@ -63,9 +63,8 @@ static void __init find_early_table_space(unsigned long end, int use_pse,
    #ifdef CONFIG_X86_32
    /* for fixmap */
    tables += roundup(__end_of_fixed_addresses * sizeof(pte_t), PAGE_SIZE);
    -
    - good_end = max_pfn_mapped << PAGE_SHIFT;
    #endif
    + good_end = max_pfn_mapped << PAGE_SHIFT;

    base = memblock_find_in_range(start, good_end, tables, PAGE_SIZE);
    if (base == MEMBLOCK_ERROR)
    diff --git a/crypto/ghash-generic.c b/crypto/ghash-generic.c
    index be44256..7835b8f 100644
    --- a/crypto/ghash-generic.c
    +++ b/crypto/ghash-generic.c
    @@ -67,6 +67,9 @@ static int ghash_update(struct shash_desc *desc,
    struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);
    u8 *dst = dctx->buffer;

    + if (!ctx->gf128)
    + return -ENOKEY;
    +
    if (dctx->bytes) {
    int n = min(srclen, dctx->bytes);
    u8 *pos = dst + (GHASH_BLOCK_SIZE - dctx->bytes);
    @@ -119,6 +122,9 @@ static int ghash_final(struct shash_desc *desc, u8 *dst)
    struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);
    u8 *buf = dctx->buffer;

    + if (!ctx->gf128)
    + return -ENOKEY;
    +
    ghash_flush(ctx, dctx);
    memcpy(dst, buf, GHASH_BLOCK_SIZE);

    diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c
    index 41841a3..17cef86 100644
    --- a/drivers/firewire/sbp2.c
    +++ b/drivers/firewire/sbp2.c
    @@ -1198,6 +1198,10 @@ static int sbp2_remove(struct device *dev)
    {
    struct fw_unit *unit = fw_unit(dev);
    struct sbp2_target *tgt = dev_get_drvdata(&unit->device);
    + struct sbp2_logical_unit *lu;
    +
    + list_for_each_entry(lu, &tgt->lu_list, link)
    + cancel_delayed_work_sync(&lu->work);

    sbp2_target_put(tgt);
    return 0;
    diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c
    index ebdb0fd..9a0aee2 100644
    --- a/drivers/gpu/drm/radeon/atom.c
    +++ b/drivers/gpu/drm/radeon/atom.c
    @@ -277,7 +277,12 @@ static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr,
    case ATOM_ARG_FB:
    idx = U8(*ptr);
    (*ptr)++;
    - val = gctx->scratch[((gctx->fb_base + idx) / 4)];
    + if ((gctx->fb_base + (idx * 4)) > gctx->scratch_size_bytes) {
    + DRM_ERROR("ATOM: fb read beyond scratch region: %d vs. %d\n",
    + gctx->fb_base + (idx * 4), gctx->scratch_size_bytes);
    + val = 0;
    + } else
    + val = gctx->scratch[(gctx->fb_base / 4) + idx];
    if (print)
    DEBUG("FB[0x%02X]", idx);
    break;
    @@ -531,7 +536,11 @@ static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr,
    case ATOM_ARG_FB:
    idx = U8(*ptr);
    (*ptr)++;
    - gctx->scratch[((gctx->fb_base + idx) / 4)] = val;
    + if ((gctx->fb_base + (idx * 4)) > gctx->scratch_size_bytes) {
    + DRM_ERROR("ATOM: fb write beyond scratch region: %d vs. %d\n",
    + gctx->fb_base + (idx * 4), gctx->scratch_size_bytes);
    + } else
    + gctx->scratch[(gctx->fb_base / 4) + idx] = val;
    DEBUG("FB[0x%02X]", idx);
    break;
    case ATOM_ARG_PLL:
    @@ -1367,11 +1376,13 @@ int atom_allocate_fb_scratch(struct atom_context *ctx)

    usage_bytes = firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb * 1024;
    }
    + ctx->scratch_size_bytes = 0;
    if (usage_bytes == 0)
    usage_bytes = 20 * 1024;
    /* allocate some scratch memory */
    ctx->scratch = kzalloc(usage_bytes, GFP_KERNEL);
    if (!ctx->scratch)
    return -ENOMEM;
    + ctx->scratch_size_bytes = usage_bytes;
    return 0;
    }
    diff --git a/drivers/gpu/drm/radeon/atom.h b/drivers/gpu/drm/radeon/atom.h
    index a589a55..93cfe20 100644
    --- a/drivers/gpu/drm/radeon/atom.h
    +++ b/drivers/gpu/drm/radeon/atom.h
    @@ -137,6 +137,7 @@ struct atom_context {
    int cs_equal, cs_above;
    int io_mode;
    uint32_t *scratch;
    + int scratch_size_bytes;
    };

    extern int atom_debug;
    diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
    index b7f0726..e2b2d78 100644
    --- a/drivers/gpu/drm/ttm/ttm_bo.c
    +++ b/drivers/gpu/drm/ttm/ttm_bo.c
    @@ -392,10 +392,12 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,
    * Create and bind a ttm if required.
    */

    - if (!(new_man->flags & TTM_MEMTYPE_FLAG_FIXED) && (bo->ttm == NULL)) {
    - ret = ttm_bo_add_ttm(bo, false);
    - if (ret)
    - goto out_err;
    + if (!(new_man->flags & TTM_MEMTYPE_FLAG_FIXED)) {
    + if (bo->ttm == NULL) {
    + ret = ttm_bo_add_ttm(bo, false);
    + if (ret)
    + goto out_err;
    + }

    ret = ttm_tt_set_placement_caching(bo->ttm, mem->placement);
    if (ret)
    diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c
    index 77dbf40..ae3c6f5 100644
    --- a/drivers/gpu/drm/ttm/ttm_bo_util.c
    +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c
    @@ -635,13 +635,13 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo,
    if (ret)
    return ret;

    - ttm_bo_free_old_node(bo);
    if ((man->flags & TTM_MEMTYPE_FLAG_FIXED) &&
    (bo->ttm != NULL)) {
    ttm_tt_unbind(bo->ttm);
    ttm_tt_destroy(bo->ttm);
    bo->ttm = NULL;
    }
    + ttm_bo_free_old_node(bo);
    } else {
    /**
    * This should help pipeline ordinary buffer moves.
    diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
    index a756ee6..c946d90 100644
    --- a/drivers/hid/hid-ids.h
    +++ b/drivers/hid/hid-ids.h
    @@ -568,6 +568,9 @@
    #define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001
    #define USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE 0x0600

    +#define USB_VENDOR_ID_SIGMA_MICRO 0x1c4f
    +#define USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD 0x0002
    +
    #define USB_VENDOR_ID_SKYCABLE 0x1223
    #define USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER 0x3F07

    diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
    index 0ec91c1..56d0539 100644
    --- a/drivers/hid/hid-magicmouse.c
    +++ b/drivers/hid/hid-magicmouse.c
    @@ -501,9 +501,17 @@ static int magicmouse_probe(struct hid_device *hdev,
    }
    report->size = 6;

    + /*
    + * Some devices repond with 'invalid report id' when feature
    + * report switching it into multitouch mode is sent to it.
    + *
    + * This results in -EIO from the _raw low-level transport callback,
    + * but there seems to be no other way of switching the mode.
    + * Thus the super-ugly hacky success check below.
    + */
    ret = hdev->hid_output_raw_report(hdev, feature, sizeof(feature),
    HID_FEATURE_REPORT);
    - if (ret != sizeof(feature)) {
    + if (ret != -EIO && ret != sizeof(feature)) {
    hid_err(hdev, "unable to request touch data (%d)\n", ret);
    goto err_stop_hw;
    }
    diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
    index 621959d..4bdb5d4 100644
    --- a/drivers/hid/usbhid/hid-quirks.c
    +++ b/drivers/hid/usbhid/hid-quirks.c
    @@ -89,6 +89,7 @@ static const struct hid_blacklist {

    { USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_MULTI_TOUCH, HID_QUIRK_MULTI_INPUT },
    { USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS, HID_QUIRK_MULTI_INPUT },
    + { USB_VENDOR_ID_SIGMA_MICRO, USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD, HID_QUIRK_NO_INIT_REPORTS },
    { 0, 0 }
    };

    diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
    index f2b377c..36d7f27 100644
    --- a/drivers/hwmon/w83627ehf.c
    +++ b/drivers/hwmon/w83627ehf.c
    @@ -390,7 +390,7 @@ temp_from_reg(u16 reg, s16 regval)
    {
    if (is_word_sized(reg))
    return LM75_TEMP_FROM_REG(regval);
    - return regval * 1000;
    + return ((s8)regval) * 1000;
    }

    static inline u16
    @@ -398,7 +398,8 @@ temp_to_reg(u16 reg, long temp)
    {
    if (is_word_sized(reg))
    return LM75_TEMP_TO_REG(temp);
    - return DIV_ROUND_CLOSEST(SENSORS_LIMIT(temp, -127000, 128000), 1000);
    + return (s8)DIV_ROUND_CLOSEST(SENSORS_LIMIT(temp, -127000, 128000),
    + 1000);
    }

    /* Some of analog inputs have internal scaling (2x), 8mV is ADC LSB */
    @@ -1715,7 +1716,8 @@ static void w83627ehf_device_remove_files(struct device *dev)
    }

    /* Get the monitoring functions started */
    -static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
    +static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data,
    + enum kinds kind)
    {
    int i;
    u8 tmp, diode;
    @@ -1746,10 +1748,16 @@ static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
    w83627ehf_write_value(data, W83627EHF_REG_VBAT, tmp | 0x01);

    /* Get thermal sensor types */
    - diode = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
    + switch (kind) {
    + case w83627ehf:
    + diode = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
    + break;
    + default:
    + diode = 0x70;
    + }
    for (i = 0; i < 3; i++) {
    if ((tmp & (0x02 << i)))
    - data->temp_type[i] = (diode & (0x10 << i)) ? 1 : 2;
    + data->temp_type[i] = (diode & (0x10 << i)) ? 1 : 3;
    else
    data->temp_type[i] = 4; /* thermistor */
    }
    @@ -2016,7 +2024,7 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
    }

    /* Initialize the chip */
    - w83627ehf_init_device(data);
    + w83627ehf_init_device(data, sio_data->kind);

    data->vrm = vid_which_vrm();
    superio_enter(sio_data->sioreg);
    diff --git a/drivers/media/video/uvc/uvc_entity.c b/drivers/media/video/uvc/uvc_entity.c
    index 48fea37..29e2399 100644
    --- a/drivers/media/video/uvc/uvc_entity.c
    +++ b/drivers/media/video/uvc/uvc_entity.c
    @@ -49,7 +49,7 @@ static int uvc_mc_register_entity(struct uvc_video_chain *chain,
    if (remote == NULL)
    return -EINVAL;

    - source = (UVC_ENTITY_TYPE(remote) != UVC_TT_STREAMING)
    + source = (UVC_ENTITY_TYPE(remote) == UVC_TT_STREAMING)
    ? (remote->vdev ? &remote->vdev->entity : NULL)
    : &remote->subdev.entity;
    if (source == NULL)
    diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c
    index d347116..1658575 100644
    --- a/drivers/platform/x86/samsung-laptop.c
    +++ b/drivers/platform/x86/samsung-laptop.c
    @@ -601,6 +601,16 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = {
    .callback = dmi_check_cb,
    },
    {
    + .ident = "N150/N210/N220",
    + .matches = {
    + DMI_MATCH(DMI_SYS_VENDOR,
    + "SAMSUNG ELECTRONICS CO., LTD."),
    + DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"),
    + DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"),
    + },
    + .callback = dmi_check_cb,
    + },
    + {
    .ident = "N150/N210/N220/N230",
    .matches = {
    DMI_MATCH(DMI_SYS_VENDOR,
    diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
    index fc7e57b..53e7d72 100644
    --- a/fs/cifs/cifsfs.c
    +++ b/fs/cifs/cifsfs.c
    @@ -566,6 +566,12 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb)
    struct inode *dir = dentry->d_inode;
    struct dentry *child;

    + if (!dir) {
    + dput(dentry);
    + dentry = ERR_PTR(-ENOENT);
    + break;
    + }
    +
    /* skip separators */
    while (*s == sep)
    s++;
    @@ -581,10 +587,6 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb)
    mutex_unlock(&dir->i_mutex);
    dput(dentry);
    dentry = child;
    - if (!dentry->d_inode) {
    - dput(dentry);
    - dentry = ERR_PTR(-ENOENT);
    - }
    } while (!IS_ERR(dentry));
    _FreeXid(xid);
    kfree(full_path);
    diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
    index 168a80f..5cb8614 100644
    --- a/fs/fuse/dev.c
    +++ b/fs/fuse/dev.c
    @@ -258,10 +258,14 @@ void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget,
    forget->forget_one.nlookup = nlookup;

    spin_lock(&fc->lock);
    - fc->forget_list_tail->next = forget;
    - fc->forget_list_tail = forget;
    - wake_up(&fc->waitq);
    - kill_fasync(&fc->fasync, SIGIO, POLL_IN);
    + if (fc->connected) {
    + fc->forget_list_tail->next = forget;
    + fc->forget_list_tail = forget;
    + wake_up(&fc->waitq);
    + kill_fasync(&fc->fasync, SIGIO, POLL_IN);
    + } else {
    + kfree(forget);
    + }
    spin_unlock(&fc->lock);
    }

    diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h
    index d685752..4e7f64b 100644
    --- a/fs/hfsplus/hfsplus_fs.h
    +++ b/fs/hfsplus/hfsplus_fs.h
    @@ -13,6 +13,7 @@
    #include <linux/fs.h>
    #include <linux/mutex.h>
    #include <linux/buffer_head.h>
    +#include <linux/blkdev.h>
    #include "hfsplus_raw.h"

    #define DBG_BNODE_REFS 0x00000001
    @@ -110,7 +111,9 @@ struct hfsplus_vh;
    struct hfs_btree;

    struct hfsplus_sb_info {
    + void *s_vhdr_buf;
    struct hfsplus_vh *s_vhdr;
    + void *s_backup_vhdr_buf;
    struct hfsplus_vh *s_backup_vhdr;
    struct hfs_btree *ext_tree;
    struct hfs_btree *cat_tree;
    @@ -258,6 +261,15 @@ struct hfsplus_readdir_data {
    struct hfsplus_cat_key key;
    };

    +/*
    + * Find minimum acceptible I/O size for an hfsplus sb.
    + */
    +static inline unsigned short hfsplus_min_io_size(struct super_block *sb)
    +{
    + return max_t(unsigned short, bdev_logical_block_size(sb->s_bdev),
    + HFSPLUS_SECTOR_SIZE);
    +}
    +
    #define hfs_btree_open hfsplus_btree_open
    #define hfs_btree_close hfsplus_btree_close
    #define hfs_btree_write hfsplus_btree_write
    @@ -436,8 +448,8 @@ int hfsplus_compare_dentry(const struct dentry *parent,
    /* wrapper.c */
    int hfsplus_read_wrapper(struct super_block *);
    int hfs_part_find(struct super_block *, sector_t *, sector_t *);
    -int hfsplus_submit_bio(struct block_device *bdev, sector_t sector,
    - void *data, int rw);
    +int hfsplus_submit_bio(struct super_block *sb, sector_t sector,
    + void *buf, void **data, int rw);

    /* time macros */
    #define __hfsp_mt2ut(t) (be32_to_cpu(t) - 2082844800U)
    diff --git a/fs/hfsplus/part_tbl.c b/fs/hfsplus/part_tbl.c
    index 40ad88c..eb355d8 100644
    --- a/fs/hfsplus/part_tbl.c
    +++ b/fs/hfsplus/part_tbl.c
    @@ -88,11 +88,12 @@ static int hfs_parse_old_pmap(struct super_block *sb, struct old_pmap *pm,
    return -ENOENT;
    }

    -static int hfs_parse_new_pmap(struct super_block *sb, struct new_pmap *pm,
    - sector_t *part_start, sector_t *part_size)
    +static int hfs_parse_new_pmap(struct super_block *sb, void *buf,
    + struct new_pmap *pm, sector_t *part_start, sector_t *part_size)
    {
    struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
    int size = be32_to_cpu(pm->pmMapBlkCnt);
    + int buf_size = hfsplus_min_io_size(sb);
    int res;
    int i = 0;

    @@ -107,11 +108,14 @@ static int hfs_parse_new_pmap(struct super_block *sb, struct new_pmap *pm,
    if (++i >= size)
    return -ENOENT;

    - res = hfsplus_submit_bio(sb->s_bdev,
    - *part_start + HFS_PMAP_BLK + i,
    - pm, READ);
    - if (res)
    - return res;
    + pm = (struct new_pmap *)((u8 *)pm + HFSPLUS_SECTOR_SIZE);
    + if ((u8 *)pm - (u8 *)buf >= buf_size) {
    + res = hfsplus_submit_bio(sb,
    + *part_start + HFS_PMAP_BLK + i,
    + buf, (void **)&pm, READ);
    + if (res)
    + return res;
    + }
    } while (pm->pmSig == cpu_to_be16(HFS_NEW_PMAP_MAGIC));

    return -ENOENT;
    @@ -124,15 +128,15 @@ static int hfs_parse_new_pmap(struct super_block *sb, struct new_pmap *pm,
    int hfs_part_find(struct super_block *sb,
    sector_t *part_start, sector_t *part_size)
    {
    - void *data;
    + void *buf, *data;
    int res;

    - data = kmalloc(HFSPLUS_SECTOR_SIZE, GFP_KERNEL);
    - if (!data)
    + buf = kmalloc(hfsplus_min_io_size(sb), GFP_KERNEL);
    + if (!buf)
    return -ENOMEM;

    - res = hfsplus_submit_bio(sb->s_bdev, *part_start + HFS_PMAP_BLK,
    - data, READ);
    + res = hfsplus_submit_bio(sb, *part_start + HFS_PMAP_BLK,
    + buf, &data, READ);
    if (res)
    goto out;

    @@ -141,13 +145,13 @@ int hfs_part_find(struct super_block *sb,
    res = hfs_parse_old_pmap(sb, data, part_start, part_size);
    break;
    case HFS_NEW_PMAP_MAGIC:
    - res = hfs_parse_new_pmap(sb, data, part_start, part_size);
    + res = hfs_parse_new_pmap(sb, buf, data, part_start, part_size);
    break;
    default:
    res = -ENOENT;
    break;
    }
    out:
    - kfree(data);
    + kfree(buf);
    return res;
    }
    diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
    index 84a47b7..c3a76fd 100644
    --- a/fs/hfsplus/super.c
    +++ b/fs/hfsplus/super.c
    @@ -197,17 +197,17 @@ int hfsplus_sync_fs(struct super_block *sb, int wait)
    write_backup = 1;
    }

    - error2 = hfsplus_submit_bio(sb->s_bdev,
    + error2 = hfsplus_submit_bio(sb,
    sbi->part_start + HFSPLUS_VOLHEAD_SECTOR,
    - sbi->s_vhdr, WRITE_SYNC);
    + sbi->s_vhdr_buf, NULL, WRITE_SYNC);
    if (!error)
    error = error2;
    if (!write_backup)
    goto out;

    - error2 = hfsplus_submit_bio(sb->s_bdev,
    + error2 = hfsplus_submit_bio(sb,
    sbi->part_start + sbi->sect_count - 2,
    - sbi->s_backup_vhdr, WRITE_SYNC);
    + sbi->s_backup_vhdr_buf, NULL, WRITE_SYNC);
    if (!error)
    error2 = error;
    out:
    @@ -251,8 +251,8 @@ static void hfsplus_put_super(struct super_block *sb)
    hfs_btree_close(sbi->ext_tree);
    iput(sbi->alloc_file);
    iput(sbi->hidden_dir);
    - kfree(sbi->s_vhdr);
    - kfree(sbi->s_backup_vhdr);
    + kfree(sbi->s_vhdr_buf);
    + kfree(sbi->s_backup_vhdr_buf);
    unload_nls(sbi->nls);
    kfree(sb->s_fs_info);
    sb->s_fs_info = NULL;
    @@ -508,8 +508,8 @@ out_close_cat_tree:
    out_close_ext_tree:
    hfs_btree_close(sbi->ext_tree);
    out_free_vhdr:
    - kfree(sbi->s_vhdr);
    - kfree(sbi->s_backup_vhdr);
    + kfree(sbi->s_vhdr_buf);
    + kfree(sbi->s_backup_vhdr_buf);
    out_unload_nls:
    unload_nls(sbi->nls);
    unload_nls(nls);
    diff --git a/fs/hfsplus/wrapper.c b/fs/hfsplus/wrapper.c
    index 4ac88ff..7b8112d 100644
    --- a/fs/hfsplus/wrapper.c
    +++ b/fs/hfsplus/wrapper.c
    @@ -31,25 +31,67 @@ static void hfsplus_end_io_sync(struct bio *bio, int err)
    complete(bio->bi_private);
    }

    -int hfsplus_submit_bio(struct block_device *bdev, sector_t sector,
    - void *data, int rw)
    +/*
    + * hfsplus_submit_bio - Perfrom block I/O
    + * @sb: super block of volume for I/O
    + * @sector: block to read or write, for blocks of HFSPLUS_SECTOR_SIZE bytes
    + * @buf: buffer for I/O
    + * @data: output pointer for location of requested data
    + * @rw: direction of I/O
    + *
    + * The unit of I/O is hfsplus_min_io_size(sb), which may be bigger than
    + * HFSPLUS_SECTOR_SIZE, and @buf must be sized accordingly. On reads
    + * @data will return a pointer to the start of the requested sector,
    + * which may not be the same location as @buf.
    + *
    + * If @sector is not aligned to the bdev logical block size it will
    + * be rounded down. For writes this means that @buf should contain data
    + * that starts at the rounded-down address. As long as the data was
    + * read using hfsplus_submit_bio() and the same buffer is used things
    + * will work correctly.
    + */
    +int hfsplus_submit_bio(struct super_block *sb, sector_t sector,
    + void *buf, void **data, int rw)
    {
    DECLARE_COMPLETION_ONSTACK(wait);
    struct bio *bio;
    int ret = 0;
    + unsigned int io_size;
    + loff_t start;
    + int offset;
    +
    + /*
    + * Align sector to hardware sector size and find offset. We
    + * assume that io_size is a power of two, which _should_
    + * be true.
    + */
    + io_size = hfsplus_min_io_size(sb);
    + start = (loff_t)sector << HFSPLUS_SECTOR_SHIFT;
    + offset = start & (io_size - 1);
    + sector &= ~((io_size >> HFSPLUS_SECTOR_SHIFT) - 1);

    bio = bio_alloc(GFP_NOIO, 1);
    bio->bi_sector = sector;
    - bio->bi_bdev = bdev;
    + bio->bi_bdev = sb->s_bdev;
    bio->bi_end_io = hfsplus_end_io_sync;
    bio->bi_private = &wait;

    - /*
    - * We always submit one sector at a time, so bio_add_page must not fail.
    - */
    - if (bio_add_page(bio, virt_to_page(data), HFSPLUS_SECTOR_SIZE,
    - offset_in_page(data)) != HFSPLUS_SECTOR_SIZE)
    - BUG();
    + if (!(rw & WRITE) && data)
    + *data = (u8 *)buf + offset;
    +
    + while (io_size > 0) {
    + unsigned int page_offset = offset_in_page(buf);
    + unsigned int len = min_t(unsigned int, PAGE_SIZE - page_offset,
    + io_size);
    +
    + ret = bio_add_page(bio, virt_to_page(buf), len, page_offset);
    + if (ret != len) {
    + ret = -EIO;
    + goto out;
    + }
    + io_size -= len;
    + buf = (u8 *)buf + len;
    + }

    submit_bio(rw, bio);
    wait_for_completion(&wait);
    @@ -57,8 +99,9 @@ int hfsplus_submit_bio(struct block_device *bdev, sector_t sector,
    if (!bio_flagged(bio, BIO_UPTODATE))
    ret = -EIO;

    +out:
    bio_put(bio);
    - return ret;
    + return ret < 0 ? ret : 0;
    }

    static int hfsplus_read_mdb(void *bufptr, struct hfsplus_wd *wd)
    @@ -147,17 +190,17 @@ int hfsplus_read_wrapper(struct super_block *sb)
    }

    error = -ENOMEM;
    - sbi->s_vhdr = kmalloc(HFSPLUS_SECTOR_SIZE, GFP_KERNEL);
    - if (!sbi->s_vhdr)
    + sbi->s_vhdr_buf = kmalloc(hfsplus_min_io_size(sb), GFP_KERNEL);
    + if (!sbi->s_vhdr_buf)
    goto out;
    - sbi->s_backup_vhdr = kmalloc(HFSPLUS_SECTOR_SIZE, GFP_KERNEL);
    - if (!sbi->s_backup_vhdr)
    + sbi->s_backup_vhdr_buf = kmalloc(hfsplus_min_io_size(sb), GFP_KERNEL);
    + if (!sbi->s_backup_vhdr_buf)
    goto out_free_vhdr;

    reread:
    - error = hfsplus_submit_bio(sb->s_bdev,
    - part_start + HFSPLUS_VOLHEAD_SECTOR,
    - sbi->s_vhdr, READ);
    + error = hfsplus_submit_bio(sb, part_start + HFSPLUS_VOLHEAD_SECTOR,
    + sbi->s_vhdr_buf, (void **)&sbi->s_vhdr,
    + READ);
    if (error)
    goto out_free_backup_vhdr;

    @@ -186,9 +229,9 @@ reread:
    goto reread;
    }

    - error = hfsplus_submit_bio(sb->s_bdev,
    - part_start + part_size - 2,
    - sbi->s_backup_vhdr, READ);
    + error = hfsplus_submit_bio(sb, part_start + part_size - 2,
    + sbi->s_backup_vhdr_buf,
    + (void **)&sbi->s_backup_vhdr, READ);
    if (error)
    goto out_free_backup_vhdr;

    @@ -232,9 +275,9 @@ reread:
    return 0;

    out_free_backup_vhdr:
    - kfree(sbi->s_backup_vhdr);
    + kfree(sbi->s_backup_vhdr_buf);
    out_free_vhdr:
    - kfree(sbi->s_vhdr);
    + kfree(sbi->s_vhdr_buf);
    out:
    return error;
    }
    diff --git a/fs/xfs/linux-2.6/xfs_linux.h b/fs/xfs/linux-2.6/xfs_linux.h
    index 8633521..8731516 100644
    --- a/fs/xfs/linux-2.6/xfs_linux.h
    +++ b/fs/xfs/linux-2.6/xfs_linux.h
    @@ -70,6 +70,8 @@
    #include <linux/ctype.h>
    #include <linux/writeback.h>
    #include <linux/capability.h>
    +#include <linux/kthread.h>
    +#include <linux/freezer.h>
    #include <linux/list_sort.h>

    #include <asm/page.h>
    diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
    index a1a881e..347cae9 100644
    --- a/fs/xfs/linux-2.6/xfs_super.c
    +++ b/fs/xfs/linux-2.6/xfs_super.c
    @@ -1412,37 +1412,35 @@ xfs_fs_fill_super(
    sb->s_time_gran = 1;
    set_posix_acl_flag(sb);

    - error = xfs_syncd_init(mp);
    - if (error)
    - goto out_filestream_unmount;
    -
    xfs_inode_shrinker_register(mp);

    error = xfs_mountfs(mp);
    if (error)
    - goto out_syncd_stop;
    + goto out_filestream_unmount;
    +
    + error = xfs_syncd_init(mp);
    + if (error)
    + goto out_unmount;

    root = igrab(VFS_I(mp->m_rootip));
    if (!root) {
    error = ENOENT;
    - goto fail_unmount;
    + goto out_syncd_stop;
    }
    if (is_bad_inode(root)) {
    error = EINVAL;
    - goto fail_vnrele;
    + goto out_syncd_stop;
    }
    sb->s_root = d_alloc_root(root);
    if (!sb->s_root) {
    error = ENOMEM;
    - goto fail_vnrele;
    + goto out_iput;
    }

    return 0;

    - out_syncd_stop:
    - xfs_inode_shrinker_unregister(mp);
    - xfs_syncd_stop(mp);
    out_filestream_unmount:
    + xfs_inode_shrinker_unregister(mp);
    xfs_filestream_unmount(mp);
    out_free_sb:
    xfs_freesb(mp);
    @@ -1456,17 +1454,12 @@ xfs_fs_fill_super(
    out:
    return -error;

    - fail_vnrele:
    - if (sb->s_root) {
    - dput(sb->s_root);
    - sb->s_root = NULL;
    - } else {
    - iput(root);
    - }
    -
    - fail_unmount:
    - xfs_inode_shrinker_unregister(mp);
    + out_iput:
    + iput(root);
    + out_syncd_stop:
    xfs_syncd_stop(mp);
    + out_unmount:
    + xfs_inode_shrinker_unregister(mp);

    /*
    * Blow away any referenced inode in the filestreams cache.
    @@ -1667,24 +1660,13 @@ xfs_init_workqueues(void)
    */
    xfs_syncd_wq = alloc_workqueue("xfssyncd", WQ_CPU_INTENSIVE, 8);
    if (!xfs_syncd_wq)
    - goto out;
    -
    - xfs_ail_wq = alloc_workqueue("xfsail", WQ_CPU_INTENSIVE, 8);
    - if (!xfs_ail_wq)
    - goto out_destroy_syncd;
    -
    + return -ENOMEM;
    return 0;
    -
    -out_destroy_syncd:
    - destroy_workqueue(xfs_syncd_wq);
    -out:
    - return -ENOMEM;
    }

    STATIC void
    xfs_destroy_workqueues(void)
    {
    - destroy_workqueue(xfs_ail_wq);
    destroy_workqueue(xfs_syncd_wq);
    }

    diff --git a/fs/xfs/quota/xfs_dquot_item.c b/fs/xfs/quota/xfs_dquot_item.c
    index 9e0e2fa..8126fc2 100644
    --- a/fs/xfs/quota/xfs_dquot_item.c
    +++ b/fs/xfs/quota/xfs_dquot_item.c
    @@ -183,13 +183,14 @@ xfs_qm_dqunpin_wait(
    * search the buffer cache can be a time consuming thing, and AIL lock is a
    * spinlock.
    */
    -STATIC void
    +STATIC bool
    xfs_qm_dquot_logitem_pushbuf(
    struct xfs_log_item *lip)
    {
    struct xfs_dq_logitem *qlip = DQUOT_ITEM(lip);
    struct xfs_dquot *dqp = qlip->qli_dquot;
    struct xfs_buf *bp;
    + bool ret = true;

    ASSERT(XFS_DQ_IS_LOCKED(dqp));

    @@ -201,17 +202,20 @@ xfs_qm_dquot_logitem_pushbuf(
    if (completion_done(&dqp->q_flush) ||
    !(lip->li_flags & XFS_LI_IN_AIL)) {
    xfs_dqunlock(dqp);
    - return;
    + return true;
    }

    bp = xfs_incore(dqp->q_mount->m_ddev_targp, qlip->qli_format.qlf_blkno,
    dqp->q_mount->m_quotainfo->qi_dqchunklen, XBF_TRYLOCK);
    xfs_dqunlock(dqp);
    if (!bp)
    - return;
    + return true;
    if (XFS_BUF_ISDELAYWRITE(bp))
    xfs_buf_delwri_promote(bp);
    + if (XFS_BUF_ISPINNED(bp))
    + ret = false;
    xfs_buf_relse(bp);
    + return ret;
    }

    /*
    diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c
    index 7b7e005..a7342e8 100644
    --- a/fs/xfs/xfs_buf_item.c
    +++ b/fs/xfs/xfs_buf_item.c
    @@ -632,7 +632,7 @@ xfs_buf_item_push(
    * the xfsbufd to get this buffer written. We have to unlock the buffer
    * to allow the xfsbufd to write it, too.
    */
    -STATIC void
    +STATIC bool
    xfs_buf_item_pushbuf(
    struct xfs_log_item *lip)
    {
    @@ -646,6 +646,7 @@ xfs_buf_item_pushbuf(

    xfs_buf_delwri_promote(bp);
    xfs_buf_relse(bp);
    + return true;
    }

    STATIC void
    diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
    index b1e88d5..391044c 100644
    --- a/fs/xfs/xfs_inode_item.c
    +++ b/fs/xfs/xfs_inode_item.c
    @@ -713,13 +713,14 @@ xfs_inode_item_committed(
    * marked delayed write. If that's the case, we'll promote it and that will
    * allow the caller to write the buffer by triggering the xfsbufd to run.
    */
    -STATIC void
    +STATIC bool
    xfs_inode_item_pushbuf(
    struct xfs_log_item *lip)
    {
    struct xfs_inode_log_item *iip = INODE_ITEM(lip);
    struct xfs_inode *ip = iip->ili_inode;
    struct xfs_buf *bp;
    + bool ret = true;

    ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED));

    @@ -730,7 +731,7 @@ xfs_inode_item_pushbuf(
    if (completion_done(&ip->i_flush) ||
    !(lip->li_flags & XFS_LI_IN_AIL)) {
    xfs_iunlock(ip, XFS_ILOCK_SHARED);
    - return;
    + return true;
    }

    bp = xfs_incore(ip->i_mount->m_ddev_targp, iip->ili_format.ilf_blkno,
    @@ -738,10 +739,13 @@ xfs_inode_item_pushbuf(

    xfs_iunlock(ip, XFS_ILOCK_SHARED);
    if (!bp)
    - return;
    + return true;
    if (XFS_BUF_ISDELAYWRITE(bp))
    xfs_buf_delwri_promote(bp);
    + if (XFS_BUF_ISPINNED(bp))
    + ret = false;
    xfs_buf_relse(bp);
    + return ret;
    }

    /*
    diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c
    index c83f63b..efc147f 100644
    --- a/fs/xfs/xfs_trans.c
    +++ b/fs/xfs/xfs_trans.c
    @@ -1426,6 +1426,7 @@ xfs_trans_committed(
    static inline void
    xfs_log_item_batch_insert(
    struct xfs_ail *ailp,
    + struct xfs_ail_cursor *cur,
    struct xfs_log_item **log_items,
    int nr_items,
    xfs_lsn_t commit_lsn)
    @@ -1434,7 +1435,7 @@ xfs_log_item_batch_insert(

    spin_lock(&ailp->xa_lock);
    /* xfs_trans_ail_update_bulk drops ailp->xa_lock */
    - xfs_trans_ail_update_bulk(ailp, log_items, nr_items, commit_lsn);
    + xfs_trans_ail_update_bulk(ailp, cur, log_items, nr_items, commit_lsn);

    for (i = 0; i < nr_items; i++)
    IOP_UNPIN(log_items[i], 0);
    @@ -1452,6 +1453,13 @@ xfs_log_item_batch_insert(
    * as an iclog write error even though we haven't started any IO yet. Hence in
    * this case all we need to do is IOP_COMMITTED processing, followed by an
    * IOP_UNPIN(aborted) call.
    + *
    + * The AIL cursor is used to optimise the insert process. If commit_lsn is not
    + * at the end of the AIL, the insert cursor avoids the need to walk
    + * the AIL to find the insertion point on every xfs_log_item_batch_insert()
    + * call. This saves a lot of needless list walking and is a net win, even
    + * though it slightly increases that amount of AIL lock traffic to set it up
    + * and tear it down.
    */
    void
    xfs_trans_committed_bulk(
    @@ -1463,8 +1471,13 @@ xfs_trans_committed_bulk(
    #define LOG_ITEM_BATCH_SIZE 32
    struct xfs_log_item *log_items[LOG_ITEM_BATCH_SIZE];
    struct xfs_log_vec *lv;
    + struct xfs_ail_cursor cur;
    int i = 0;

    + spin_lock(&ailp->xa_lock);
    + xfs_trans_ail_cursor_last(ailp, &cur, commit_lsn);
    + spin_unlock(&ailp->xa_lock);
    +
    /* unpin all the log items */
    for (lv = log_vector; lv; lv = lv->lv_next ) {
    struct xfs_log_item *lip = lv->lv_item;
    @@ -1493,7 +1506,9 @@ xfs_trans_committed_bulk(
    /*
    * Not a bulk update option due to unusual item_lsn.
    * Push into AIL immediately, rechecking the lsn once
    - * we have the ail lock. Then unpin the item.
    + * we have the ail lock. Then unpin the item. This does
    + * not affect the AIL cursor the bulk insert path is
    + * using.
    */
    spin_lock(&ailp->xa_lock);
    if (XFS_LSN_CMP(item_lsn, lip->li_lsn) > 0)
    @@ -1507,7 +1522,7 @@ xfs_trans_committed_bulk(
    /* Item is a candidate for bulk AIL insert. */
    log_items[i++] = lv->lv_item;
    if (i >= LOG_ITEM_BATCH_SIZE) {
    - xfs_log_item_batch_insert(ailp, log_items,
    + xfs_log_item_batch_insert(ailp, &cur, log_items,
    LOG_ITEM_BATCH_SIZE, commit_lsn);
    i = 0;
    }
    @@ -1515,7 +1530,11 @@ xfs_trans_committed_bulk(

    /* make sure we insert the remainder! */
    if (i)
    - xfs_log_item_batch_insert(ailp, log_items, i, commit_lsn);
    + xfs_log_item_batch_insert(ailp, &cur, log_items, i, commit_lsn);
    +
    + spin_lock(&ailp->xa_lock);
    + xfs_trans_ail_cursor_done(ailp, &cur);
    + spin_unlock(&ailp->xa_lock);
    }

    /*
    diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
    index 06a9759..53597f4 100644
    --- a/fs/xfs/xfs_trans.h
    +++ b/fs/xfs/xfs_trans.h
    @@ -350,7 +350,7 @@ typedef struct xfs_item_ops {
    void (*iop_unlock)(xfs_log_item_t *);
    xfs_lsn_t (*iop_committed)(xfs_log_item_t *, xfs_lsn_t);
    void (*iop_push)(xfs_log_item_t *);
    - void (*iop_pushbuf)(xfs_log_item_t *);
    + bool (*iop_pushbuf)(xfs_log_item_t *);
    void (*iop_committing)(xfs_log_item_t *, xfs_lsn_t);
    } xfs_item_ops_t;

    diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c
    index 5fc2380..a4c281b 100644
    --- a/fs/xfs/xfs_trans_ail.c
    +++ b/fs/xfs/xfs_trans_ail.c
    @@ -28,8 +28,6 @@
    #include "xfs_trans_priv.h"
    #include "xfs_error.h"

    -struct workqueue_struct *xfs_ail_wq; /* AIL workqueue */
    -
    #ifdef DEBUG
    /*
    * Check that the list is sorted as it should be.
    @@ -272,9 +270,9 @@ xfs_trans_ail_cursor_clear(
    }

    /*
    - * Return the item in the AIL with the current lsn.
    - * Return the current tree generation number for use
    - * in calls to xfs_trans_next_ail().
    + * Initialise the cursor to the first item in the AIL with the given @lsn.
    + * This searches the list from lowest LSN to highest. Pass a @lsn of zero
    + * to initialise the cursor to the first item in the AIL.
    */
    xfs_log_item_t *
    xfs_trans_ail_cursor_first(
    @@ -300,31 +298,97 @@ out:
    }

    /*
    - * splice the log item list into the AIL at the given LSN.
    + * Initialise the cursor to the last item in the AIL with the given @lsn.
    + * This searches the list from highest LSN to lowest. If there is no item with
    + * the value of @lsn, then it sets the cursor to the last item with an LSN lower
    + * than @lsn.
    + */
    +static struct xfs_log_item *
    +__xfs_trans_ail_cursor_last(
    + struct xfs_ail *ailp,
    + xfs_lsn_t lsn)
    +{
    + xfs_log_item_t *lip;
    +
    + list_for_each_entry_reverse(lip, &ailp->xa_ail, li_ail) {
    + if (XFS_LSN_CMP(lip->li_lsn, lsn) <= 0)
    + return lip;
    + }
    + return NULL;
    +}
    +
    +/*
    + * Initialise the cursor to the last item in the AIL with the given @lsn.
    + * This searches the list from highest LSN to lowest.
    + */
    +struct xfs_log_item *
    +xfs_trans_ail_cursor_last(
    + struct xfs_ail *ailp,
    + struct xfs_ail_cursor *cur,
    + xfs_lsn_t lsn)
    +{
    + xfs_trans_ail_cursor_init(ailp, cur);
    + cur->item = __xfs_trans_ail_cursor_last(ailp, lsn);
    + return cur->item;
    +}
    +
    +/*
    + * splice the log item list into the AIL at the given LSN. We splice to the
    + * tail of the given LSN to maintain insert order for push traversals. The
    + * cursor is optional, allowing repeated updates to the same LSN to avoid
    + * repeated traversals.
    */
    static void
    xfs_ail_splice(
    - struct xfs_ail *ailp,
    - struct list_head *list,
    - xfs_lsn_t lsn)
    + struct xfs_ail *ailp,
    + struct xfs_ail_cursor *cur,
    + struct list_head *list,
    + xfs_lsn_t lsn)
    {
    - xfs_log_item_t *next_lip;
    + struct xfs_log_item *lip = cur ? cur->item : NULL;
    + struct xfs_log_item *next_lip;

    - /* If the list is empty, just insert the item. */
    - if (list_empty(&ailp->xa_ail)) {
    - list_splice(list, &ailp->xa_ail);
    - return;
    - }
    + /*
    + * Get a new cursor if we don't have a placeholder or the existing one
    + * has been invalidated.
    + */
    + if (!lip || (__psint_t)lip & 1) {
    + lip = __xfs_trans_ail_cursor_last(ailp, lsn);

    - list_for_each_entry_reverse(next_lip, &ailp->xa_ail, li_ail) {
    - if (XFS_LSN_CMP(next_lip->li_lsn, lsn) <= 0)
    - break;
    + if (!lip) {
    + /* The list is empty, so just splice and return. */
    + if (cur)
    + cur->item = NULL;
    + list_splice(list, &ailp->xa_ail);
    + return;
    + }
    }

    - ASSERT(&next_lip->li_ail == &ailp->xa_ail ||
    - XFS_LSN_CMP(next_lip->li_lsn, lsn) <= 0);
    -
    - list_splice_init(list, &next_lip->li_ail);
    + /*
    + * Our cursor points to the item we want to insert _after_, so we have
    + * to update the cursor to point to the end of the list we are splicing
    + * in so that it points to the correct location for the next splice.
    + * i.e. before the splice
    + *
    + * lsn -> lsn -> lsn + x -> lsn + x ...
    + * ^
    + * | cursor points here
    + *
    + * After the splice we have:
    + *
    + * lsn -> lsn -> lsn -> lsn -> .... -> lsn -> lsn + x -> lsn + x ...
    + * ^ ^
    + * | cursor points here | needs to move here
    + *
    + * So we set the cursor to the last item in the list to be spliced
    + * before we execute the splice, resulting in the cursor pointing to
    + * the correct item after the splice occurs.
    + */
    + if (cur) {
    + next_lip = list_entry(list->prev, struct xfs_log_item, li_ail);
    + cur->item = next_lip;
    + }
    + list_splice(list, &lip->li_ail);
    }

    /*
    @@ -340,16 +404,10 @@ xfs_ail_delete(
    xfs_trans_ail_cursor_clear(ailp, lip);
    }

    -/*
    - * xfs_ail_worker does the work of pushing on the AIL. It will requeue itself
    - * to run at a later time if there is more work to do to complete the push.
    - */
    -STATIC void
    -xfs_ail_worker(
    - struct work_struct *work)
    +static long
    +xfsaild_push(
    + struct xfs_ail *ailp)
    {
    - struct xfs_ail *ailp = container_of(to_delayed_work(work),
    - struct xfs_ail, xa_work);
    xfs_mount_t *mp = ailp->xa_mount;
    struct xfs_ail_cursor *cur = &ailp->xa_cursors;
    xfs_log_item_t *lip;
    @@ -412,8 +470,13 @@ xfs_ail_worker(

    case XFS_ITEM_PUSHBUF:
    XFS_STATS_INC(xs_push_ail_pushbuf);
    - IOP_PUSHBUF(lip);
    - ailp->xa_last_pushed_lsn = lsn;
    +
    + if (!IOP_PUSHBUF(lip)) {
    + stuck++;
    + flush_log = 1;
    + } else {
    + ailp->xa_last_pushed_lsn = lsn;
    + }
    push_xfsbufd = 1;
    break;

    @@ -425,7 +488,6 @@ xfs_ail_worker(

    case XFS_ITEM_LOCKED:
    XFS_STATS_INC(xs_push_ail_locked);
    - ailp->xa_last_pushed_lsn = lsn;
    stuck++;
    break;

    @@ -486,20 +548,6 @@ out_done:
    /* We're past our target or empty, so idle */
    ailp->xa_last_pushed_lsn = 0;

    - /*
    - * We clear the XFS_AIL_PUSHING_BIT first before checking
    - * whether the target has changed. If the target has changed,
    - * this pushes the requeue race directly onto the result of the
    - * atomic test/set bit, so we are guaranteed that either the
    - * the pusher that changed the target or ourselves will requeue
    - * the work (but not both).
    - */
    - clear_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags);
    - smp_rmb();
    - if (XFS_LSN_CMP(ailp->xa_target, target) == 0 ||
    - test_and_set_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags))
    - return;
    -
    tout = 50;
    } else if (XFS_LSN_CMP(lsn, target) >= 0) {
    /*
    @@ -522,9 +570,30 @@ out_done:
    tout = 20;
    }

    - /* There is more to do, requeue us. */
    - queue_delayed_work(xfs_syncd_wq, &ailp->xa_work,
    - msecs_to_jiffies(tout));
    + return tout;
    +}
    +
    +static int
    +xfsaild(
    + void *data)
    +{
    + struct xfs_ail *ailp = data;
    + long tout = 0; /* milliseconds */
    +
    + while (!kthread_should_stop()) {
    + if (tout && tout <= 20)
    + __set_current_state(TASK_KILLABLE);
    + else
    + __set_current_state(TASK_INTERRUPTIBLE);
    + schedule_timeout(tout ?
    + msecs_to_jiffies(tout) : MAX_SCHEDULE_TIMEOUT);
    +
    + try_to_freeze();
    +
    + tout = xfsaild_push(ailp);
    + }
    +
    + return 0;
    }

    /*
    @@ -559,8 +628,9 @@ xfs_ail_push(
    */
    smp_wmb();
    xfs_trans_ail_copy_lsn(ailp, &ailp->xa_target, &threshold_lsn);
    - if (!test_and_set_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags))
    - queue_delayed_work(xfs_syncd_wq, &ailp->xa_work, 0);
    + smp_wmb();
    +
    + wake_up_process(ailp->xa_task);
    }

    /*
    @@ -645,6 +715,7 @@ xfs_trans_unlocked_item(
    void
    xfs_trans_ail_update_bulk(
    struct xfs_ail *ailp,
    + struct xfs_ail_cursor *cur,
    struct xfs_log_item **log_items,
    int nr_items,
    xfs_lsn_t lsn) __releases(ailp->xa_lock)
    @@ -674,7 +745,7 @@ xfs_trans_ail_update_bulk(
    list_add(&lip->li_ail, &tmp);
    }

    - xfs_ail_splice(ailp, &tmp, lsn);
    + xfs_ail_splice(ailp, cur, &tmp, lsn);

    if (!mlip_changed) {
    spin_unlock(&ailp->xa_lock);
    @@ -794,9 +865,18 @@ xfs_trans_ail_init(
    ailp->xa_mount = mp;
    INIT_LIST_HEAD(&ailp->xa_ail);
    spin_lock_init(&ailp->xa_lock);
    - INIT_DELAYED_WORK(&ailp->xa_work, xfs_ail_worker);
    +
    + ailp->xa_task = kthread_run(xfsaild, ailp, "xfsaild/%s",
    + ailp->xa_mount->m_fsname);
    + if (IS_ERR(ailp->xa_task))
    + goto out_free_ailp;
    +
    mp->m_ail = ailp;
    return 0;
    +
    +out_free_ailp:
    + kmem_free(ailp);
    + return ENOMEM;
    }

    void
    @@ -805,6 +885,6 @@ xfs_trans_ail_destroy(
    {
    struct xfs_ail *ailp = mp->m_ail;

    - cancel_delayed_work_sync(&ailp->xa_work);
    + kthread_stop(ailp->xa_task);
    kmem_free(ailp);
    }
    diff --git a/fs/xfs/xfs_trans_priv.h b/fs/xfs/xfs_trans_priv.h
    index 6b164e9..fe2e3cb 100644
    --- a/fs/xfs/xfs_trans_priv.h
    +++ b/fs/xfs/xfs_trans_priv.h
    @@ -64,24 +64,19 @@ struct xfs_ail_cursor {
    */
    struct xfs_ail {
    struct xfs_mount *xa_mount;
    + struct task_struct *xa_task;
    struct list_head xa_ail;
    xfs_lsn_t xa_target;
    struct xfs_ail_cursor xa_cursors;
    spinlock_t xa_lock;
    - struct delayed_work xa_work;
    xfs_lsn_t xa_last_pushed_lsn;
    - unsigned long xa_flags;
    };

    -#define XFS_AIL_PUSHING_BIT 0
    -
    /*
    * From xfs_trans_ail.c
    */
    -
    -extern struct workqueue_struct *xfs_ail_wq; /* AIL workqueue */
    -
    void xfs_trans_ail_update_bulk(struct xfs_ail *ailp,
    + struct xfs_ail_cursor *cur,
    struct xfs_log_item **log_items, int nr_items,
    xfs_lsn_t lsn) __releases(ailp->xa_lock);
    static inline void
    @@ -90,7 +85,7 @@ xfs_trans_ail_update(
    struct xfs_log_item *lip,
    xfs_lsn_t lsn) __releases(ailp->xa_lock)
    {
    - xfs_trans_ail_update_bulk(ailp, &lip, 1, lsn);
    + xfs_trans_ail_update_bulk(ailp, NULL, &lip, 1, lsn);
    }

    void xfs_trans_ail_delete_bulk(struct xfs_ail *ailp,
    @@ -111,10 +106,13 @@ xfs_lsn_t xfs_ail_min_lsn(struct xfs_ail *ailp);
    void xfs_trans_unlocked_item(struct xfs_ail *,
    xfs_log_item_t *);

    -struct xfs_log_item *xfs_trans_ail_cursor_first(struct xfs_ail *ailp,
    +struct xfs_log_item * xfs_trans_ail_cursor_first(struct xfs_ail *ailp,
    + struct xfs_ail_cursor *cur,
    + xfs_lsn_t lsn);
    +struct xfs_log_item * xfs_trans_ail_cursor_last(struct xfs_ail *ailp,
    struct xfs_ail_cursor *cur,
    xfs_lsn_t lsn);
    -struct xfs_log_item *xfs_trans_ail_cursor_next(struct xfs_ail *ailp,
    +struct xfs_log_item * xfs_trans_ail_cursor_next(struct xfs_ail *ailp,
    struct xfs_ail_cursor *cur);
    void xfs_trans_ail_cursor_done(struct xfs_ail *ailp,
    struct xfs_ail_cursor *cur);
    diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c
    index c8008dd..640ded8 100644
    --- a/kernel/posix-cpu-timers.c
    +++ b/kernel/posix-cpu-timers.c
    @@ -274,9 +274,7 @@ void thread_group_cputimer(struct task_struct *tsk, struct task_cputime *times)
    struct task_cputime sum;
    unsigned long flags;

    - spin_lock_irqsave(&cputimer->lock, flags);
    if (!cputimer->running) {
    - cputimer->running = 1;
    /*
    * The POSIX timer interface allows for absolute time expiry
    * values through the TIMER_ABSTIME flag, therefore we have
    @@ -284,8 +282,11 @@ void thread_group_cputimer(struct task_struct *tsk, struct task_cputime *times)
    * it.
    */
    thread_group_cputime(tsk, &sum);
    + spin_lock_irqsave(&cputimer->lock, flags);
    + cputimer->running = 1;
    update_gt_cputime(&cputimer->cputime, &sum);
    - }
    + } else
    + spin_lock_irqsave(&cputimer->lock, flags);
    *times = cputimer->cputime;
    spin_unlock_irqrestore(&cputimer->lock, flags);
    }
    diff --git a/kernel/sys.c b/kernel/sys.c
    index 5c942cf..f88dadc 100644
    --- a/kernel/sys.c
    +++ b/kernel/sys.c
    @@ -1135,7 +1135,7 @@ DECLARE_RWSEM(uts_sem);
    static int override_release(char __user *release, int len)
    {
    int ret = 0;
    - char buf[len];
    + char buf[65];

    if (current->personality & UNAME26) {
    char *rest = UTS_RELEASE;
    diff --git a/mm/migrate.c b/mm/migrate.c
    index 666e4e6..14d0a6a 100644
    --- a/mm/migrate.c
    +++ b/mm/migrate.c
    @@ -120,10 +120,10 @@ static int remove_migration_pte(struct page *new, struct vm_area_struct *vma,

    ptep = pte_offset_map(pmd, addr);

    - if (!is_swap_pte(*ptep)) {
    - pte_unmap(ptep);
    - goto out;
    - }
    + /*
    + * Peek to check is_swap_pte() before taking ptlock? No, we
    + * can race mremap's move_ptes(), which skips anon_vma lock.
    + */

    ptl = pte_lockptr(mm, pmd);
    }
    diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
    index 4680b1e..373e14f 100644
    --- a/net/x25/af_x25.c
    +++ b/net/x25/af_x25.c
    @@ -295,7 +295,8 @@ static struct sock *x25_find_listener(struct x25_address *addr,
    * Found a listening socket, now check the incoming
    * call user data vs this sockets call user data
    */
    - if(skb->len > 0 && x25_sk(s)->cudmatchlength > 0) {
    + if (x25_sk(s)->cudmatchlength > 0 &&
    + skb->len >= x25_sk(s)->cudmatchlength) {
    if((memcmp(x25_sk(s)->calluserdata.cuddata,
    skb->data,
    x25_sk(s)->cudmatchlength)) == 0) {
    diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
    index 486f6de..981b6fd 100644
    --- a/sound/pci/hda/hda_intel.c
    +++ b/sound/pci/hda/hda_intel.c
    @@ -2352,6 +2352,7 @@ static struct snd_pci_quirk position_fix_list[] __devinitdata = {
    SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB),
    SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_LPIB),
    SND_PCI_QUIRK(0x1028, 0x01f6, "Dell Latitude 131L", POS_FIX_LPIB),
    + SND_PCI_QUIRK(0x1028, 0x02c6, "Dell Inspiron 1010", POS_FIX_LPIB),
    SND_PCI_QUIRK(0x1028, 0x0470, "Dell Inspiron 1120", POS_FIX_LPIB),
    SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB),
    SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB),
    diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
    index 7bbc5f2..cf1fa36 100644
    --- a/sound/pci/hda/patch_conexant.c
    +++ b/sound/pci/hda/patch_conexant.c
    @@ -3097,6 +3097,7 @@ static const struct snd_pci_quirk cxt5066_cfg_tbl[] = {
    SND_PCI_QUIRK(0x17aa, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD),
    SND_PCI_QUIRK(0x17aa, 0x21c6, "Thinkpad Edge 13", CXT5066_ASUS),
    SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD),
    + SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520 & W520", CXT5066_AUTO),
    SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT5066_THINKPAD),
    SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT5066_THINKPAD),
    SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo U350", CXT5066_ASUS),

    \
     
     \ /
      Last update: 2011-10-25 07:23    [W:0.122 / U:0.152 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site