[patch 00/73] 2.6.23-stable review - Kernel

This is a discussion on [patch 00/73] 2.6.23-stable review - Kernel ; 2.6.23-stable review patch. If anyone has any objections, please let us know. ------------------ From: Thomas Gleixner patch cdc6f27d9e3c2f7ca1a3e19c6eabb1ad6a2add5d in mainline. A previous version of the code did the reprogramming of the broadcast device in the return from idle code. This ...

+ Reply to Thread
Page 3 of 4 FirstFirst 1 2 3 4 LastLast
Results 41 to 60 of 66

Thread: [patch 00/73] 2.6.23-stable review

  1. [patch 40/73] clockevents: fix reprogramming decision in oneshot broadcast

    2.6.23-stable review patch. If anyone has any objections, please let us know.
    ------------------
    From: Thomas Gleixner

    patch cdc6f27d9e3c2f7ca1a3e19c6eabb1ad6a2add5d in mainline.

    A previous version of the code did the reprogramming of the broadcast
    device in the return from idle code. This was removed, but the logic in
    tick_handle_oneshot_broadcast() was kept the same.

    When a broadcast interrupt happens we signal the expiry to all CPUs
    which have an expired event. If none of the CPUs has an expired event,
    which can happen in dyntick mode, then we reprogram the broadcast
    device. We do not reprogram otherwise, but this is only correct if all
    CPUs, which are in the idle broadcast state have been woken up.

    The code ignores, that there might be pending not yet expired events on
    other CPUs, which are in the idle broadcast state. So the delivery of
    those events can be delayed for quite a time.

    Change the tick_handle_oneshot_broadcast() function to check for CPUs,
    which are in broadcast state and are not woken up by the current event,
    and enforce the rearming of the broadcast device for those CPUs.

    Signed-off-by: Thomas Gleixner
    Signed-off-by: Ingo Molnar

    ---
    kernel/time/tick-broadcast.c | 56 ++++++++++++++++---------------------------
    1 file changed, 21 insertions(+), 35 deletions(-)

    --- a/kernel/time/tick-broadcast.c
    +++ b/kernel/time/tick-broadcast.c
    @@ -387,45 +387,19 @@ int tick_resume_broadcast_oneshot(struct
    }

    /*
    - * Reprogram the broadcast device:
    - *
    - * Called with tick_broadcast_lock held and interrupts disabled.
    - */
    -static int tick_broadcast_reprogram(void)
    -{
    - ktime_t expires = { .tv64 = KTIME_MAX };
    - struct tick_device *td;
    - int cpu;
    -
    - /*
    - * Find the event which expires next:
    - */
    - for (cpu = first_cpu(tick_broadcast_oneshot_mask); cpu != NR_CPUS;
    - cpu = next_cpu(cpu, tick_broadcast_oneshot_mask)) {
    - td = &per_cpu(tick_cpu_device, cpu);
    - if (td->evtdev->next_event.tv64 < expires.tv64)
    - expires = td->evtdev->next_event;
    - }
    -
    - if (expires.tv64 == KTIME_MAX)
    - return 0;
    -
    - return tick_broadcast_set_event(expires, 0);
    -}
    -
    -/*
    * Handle oneshot mode broadcasting
    */
    static void tick_handle_oneshot_broadcast(struct clock_event_device *dev)
    {
    struct tick_device *td;
    cpumask_t mask;
    - ktime_t now;
    + ktime_t now, next_event;
    int cpu;

    spin_lock(&tick_broadcast_lock);
    again:
    dev->next_event.tv64 = KTIME_MAX;
    + next_event.tv64 = KTIME_MAX;
    mask = CPU_MASK_NONE;
    now = ktime_get();
    /* Find all expired events */
    @@ -434,19 +408,31 @@ again:
    td = &per_cpu(tick_cpu_device, cpu);
    if (td->evtdev->next_event.tv64 <= now.tv64)
    cpu_set(cpu, mask);
    + else if (td->evtdev->next_event.tv64 < next_event.tv64)
    + next_event.tv64 = td->evtdev->next_event.tv64;
    }

    /*
    - * Wakeup the cpus which have an expired event. The broadcast
    - * device is reprogrammed in the return from idle code.
    + * Wakeup the cpus which have an expired event.
    + */
    + tick_do_broadcast(mask);
    +
    + /*
    + * Two reasons for reprogram:
    + *
    + * - The global event did not expire any CPU local
    + * events. This happens in dyntick mode, as the maximum PIT
    + * delta is quite small.
    + *
    + * - There are pending events on sleeping CPUs which were not
    + * in the event mask
    */
    - if (!tick_do_broadcast(mask)) {
    + if (next_event.tv64 != KTIME_MAX) {
    /*
    - * The global event did not expire any CPU local
    - * events. This happens in dyntick mode, as the
    - * maximum PIT delta is quite small.
    + * Rearm the broadcast device. If event expired,
    + * repeat the above
    */
    - if (tick_broadcast_reprogram())
    + if (tick_broadcast_set_event(next_event, 0))
    goto again;
    }
    spin_unlock(&tick_broadcast_lock);

    --
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  2. [patch 56/73] VM/Security: add security hook to do_brk (CVE-2007-6434)

    2.6.23-stable review patch. If anyone has any objections, please let us know.
    ------------------
    From: Eric Paris

    patch ecaf18c15aac8bb9bed7b7aa0e382fe252e275d5 in mainline.

    VM/Security: add security hook to do_brk

    Given a specifically crafted binary do_brk() can be used to get low pages
    available in userspace virtual memory and can thus be used to circumvent
    the mmap_min_addr low memory protection. Add security checks in do_brk().

    Signed-off-by: Eric Paris
    Acked-by: Alan Cox
    Cc: Stephen Smalley
    Cc: James Morris
    Cc: Chris Wright
    Cc: maximilian attems
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds
    Signed-off-by: Greg Kroah-Hartman

    ---
    mm/mmap.c | 4 ++++
    1 file changed, 4 insertions(+)

    --- a/mm/mmap.c
    +++ b/mm/mmap.c
    @@ -1938,6 +1938,10 @@ unsigned long do_brk(unsigned long addr,
    if (is_hugepage_only_range(mm, addr, len))
    return -EINVAL;

    + error = security_file_mmap(0, 0, 0, 0, addr, 1);
    + if (error)
    + return error;
    +
    flags = VM_DATA_DEFAULT_FLAGS | VM_ACCOUNT | mm->def_flags;

    error = arch_mmap_check(addr, len, flags);

    --
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  3. [patch 57/73] security: protect from stack expantion into low vm addresses

    2.6.23-stable review patch. If anyone has any objections, please let us know.
    ------------------
    From: Eric Paris

    patch 8869477a49c3e99def1fcdadd6bbc407fea14b45 in mainline.

    Add security checks to make sure we are not attempting to expand the
    stack into memory protected by mmap_min_addr

    Signed-off-by: Eric Paris
    Signed-off-by: James Morris
    Signed-off-by: Greg Kroah-Hartman

    ---
    mm/mmap.c | 8 ++++++--
    1 file changed, 6 insertions(+), 2 deletions(-)

    --- a/mm/mmap.c
    +++ b/mm/mmap.c
    @@ -1619,6 +1619,12 @@ static inline int expand_downwards(struc
    */
    if (unlikely(anon_vma_prepare(vma)))
    return -ENOMEM;
    +
    + address &= PAGE_MASK;
    + error = security_file_mmap(0, 0, 0, 0, address, 1);
    + if (error)
    + return error;
    +
    anon_vma_lock(vma);

    /*
    @@ -1626,8 +1632,6 @@ static inline int expand_downwards(struc
    * is required to hold the mmap_sem in read mode. We need the
    * anon_vma lock to serialize against concurrent expand_stacks.
    */
    - address &= PAGE_MASK;
    - error = 0;

    /* Somebody else might have raced and expanded it already */
    if (address < vma->vm_start) {

    --
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  4. [patch 60/73] vm audit: add VM_DONTEXPAND to mmap for drivers that need it (CVE-2008-0007)

    2.6.23-stable review patch. If anyone has any objections, please let us know.
    ------------------
    From: Nick Piggin

    Drivers that register a ->fault handler, but do not range-check the
    offset argument, must set VM_DONTEXPAND in the vm_flags in order to
    prevent an expanding mremap from overflowing the resource.

    I've audited the tree and attempted to fix these problems (usually by
    adding VM_DONTEXPAND where it is not obvious).

    Signed-off-by: Nick Piggin
    Signed-off-by: Linus Torvalds
    Signed-off-by: Greg Kroah-Hartman

    ---
    drivers/char/drm/drm_vm.c | 2 ++
    drivers/char/mspec.c | 2 +-
    fs/ncpfs/mmap.c | 4 ----
    kernel/relay.c | 1 +
    mm/mmap.c | 2 +-
    sound/oss/via82cxxx_audio.c | 14 ++++++--------
    sound/usb/usx2y/usX2Yhwdep.c | 2 +-
    sound/usb/usx2y/usx2yhwdeppcm.c | 2 +-
    8 files changed, 13 insertions(+), 16 deletions(-)

    --- a/drivers/char/drm/drm_vm.c
    +++ b/drivers/char/drm/drm_vm.c
    @@ -506,6 +506,7 @@ static int drm_mmap_dma(struct file *fil
    vma->vm_ops = &drm_vm_dma_ops;

    vma->vm_flags |= VM_RESERVED; /* Don't swap */
    + vma->vm_flags |= VM_DONTEXPAND;

    vma->vm_file = filp; /* Needed for drm_vm_open() */
    drm_vm_open_locked(vma);
    @@ -655,6 +656,7 @@ static int drm_mmap_locked(struct file *
    return -EINVAL; /* This should never happen. */
    }
    vma->vm_flags |= VM_RESERVED; /* Don't swap */
    + vma->vm_flags |= VM_DONTEXPAND;

    vma->vm_file = filp; /* Needed for drm_vm_open() */
    drm_vm_open_locked(vma);
    --- a/drivers/char/mspec.c
    +++ b/drivers/char/mspec.c
    @@ -283,7 +283,7 @@ mspec_mmap(struct file *file, struct vm_
    vdata->refcnt = ATOMIC_INIT(1);
    vma->vm_private_data = vdata;

    - vma->vm_flags |= (VM_IO | VM_RESERVED | VM_PFNMAP);
    + vma->vm_flags |= (VM_IO | VM_RESERVED | VM_PFNMAP | VM_DONTEXPAND);
    if (vdata->type == MSPEC_FETCHOP || vdata->type == MSPEC_UNCACHED)
    vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
    vma->vm_ops = &mspec_vm_ops;
    --- a/fs/ncpfs/mmap.c
    +++ b/fs/ncpfs/mmap.c
    @@ -50,10 +50,6 @@ static int ncp_file_mmap_fault(struct vm
    pos = vmf->pgoff << PAGE_SHIFT;

    count = PAGE_SIZE;
    - if ((unsigned long)vmf->virtual_address + PAGE_SIZE > area->vm_end) {
    - WARN_ON(1); /* shouldn't happen? */
    - count = area->vm_end - (unsigned long)vmf->virtual_address;
    - }
    /* what we can read in one go */
    bufsize = NCP_SERVER(inode)->buffer_size;

    --- a/kernel/relay.c
    +++ b/kernel/relay.c
    @@ -92,6 +92,7 @@ static int relay_mmap_buf(struct rchan_b
    return -EINVAL;

    vma->vm_ops = &relay_file_mmap_ops;
    + vma->vm_flags |= VM_DONTEXPAND;
    vma->vm_private_data = buf;
    buf->chan->cb->buf_mapped(buf, filp);

    --- a/mm/mmap.c
    +++ b/mm/mmap.c
    @@ -2217,7 +2217,7 @@ int install_special_mapping(struct mm_st
    vma->vm_start = addr;
    vma->vm_end = addr + len;

    - vma->vm_flags = vm_flags | mm->def_flags;
    + vma->vm_flags = vm_flags | mm->def_flags | VM_DONTEXPAND;
    vma->vm_page_prot = protection_map[vma->vm_flags & 7];

    vma->vm_ops = &special_mapping_vmops;
    --- a/sound/oss/via82cxxx_audio.c
    +++ b/sound/oss/via82cxxx_audio.c
    @@ -2104,6 +2104,7 @@ static struct page * via_mm_nopage (stru
    {
    struct via_info *card = vma->vm_private_data;
    struct via_channel *chan = &card->ch_out;
    + unsigned long max_bufs;
    struct page *dmapage;
    unsigned long pgoff;
    int rd, wr;
    @@ -2127,14 +2128,11 @@ static struct page * via_mm_nopage (stru
    rd = card->ch_in.is_mapped;
    wr = card->ch_out.is_mapped;

    -#ifndef VIA_NDEBUG
    - {
    - unsigned long max_bufs = chan->frag_number;
    - if (rd && wr) max_bufs *= 2;
    - /* via_dsp_mmap() should ensure this */
    - assert (pgoff < max_bufs);
    - }
    -#endif
    + max_bufs = chan->frag_number;
    + if (rd && wr)
    + max_bufs *= 2;
    + if (pgoff >= max_bufs)
    + return NOPAGE_SIGBUS;

    /* if full-duplex (read+write) and we have two sets of bufs,
    * then the playback buffers come first, sez soundcard.c */
    --- a/sound/usb/usx2y/usX2Yhwdep.c
    +++ b/sound/usb/usx2y/usX2Yhwdep.c
    @@ -88,7 +88,7 @@ static int snd_us428ctls_mmap(struct snd
    us428->us428ctls_sharedmem->CtlSnapShotLast = -2;
    }
    area->vm_ops = &us428ctls_vm_ops;
    - area->vm_flags |= VM_RESERVED;
    + area->vm_flags |= VM_RESERVED | VM_DONTEXPAND;
    area->vm_private_data = hw->private_data;
    return 0;
    }
    --- a/sound/usb/usx2y/usx2yhwdeppcm.c
    +++ b/sound/usb/usx2y/usx2yhwdeppcm.c
    @@ -728,7 +728,7 @@ static int snd_usX2Y_hwdep_pcm_mmap(stru
    return -ENODEV;
    }
    area->vm_ops = &snd_usX2Y_hwdep_pcm_vm_ops;
    - area->vm_flags |= VM_RESERVED;
    + area->vm_flags |= VM_RESERVED | VM_DONTEXPAND;
    area->vm_private_data = hw->private_data;
    return 0;
    }

    --
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  5. [patch 53/73] Input: fix open count handling in input interfaces

    2.6.23-stable review patch. If anyone has any objections, please let us know.
    ------------------
    From: Oliver Neukum

    patch 064450140f1eab959bd0eca0245f449993216074 in mainline.

    If input_open_device() fails we should not leave interfaces marked
    as opened.

    Signed-off-by: Oliver Neukum
    Cc: Al Viro
    Signed-off-by: Dmitry Torokhov
    Signed-off-by: Greg Kroah-Hartman

    ---
    drivers/input/evdev.c | 5 ++++-
    drivers/input/joydev.c | 5 ++++-
    drivers/input/mousedev.c | 5 ++++-
    drivers/input/tsdev.c | 5 ++++-
    4 files changed, 16 insertions(+), 4 deletions(-)

    --- a/drivers/input/evdev.c
    +++ b/drivers/input/evdev.c
    @@ -192,8 +192,11 @@ static int evdev_open_device(struct evde

    if (!evdev->exist)
    retval = -ENODEV;
    - else if (!evdev->open++)
    + else if (!evdev->open++) {
    retval = input_open_device(&evdev->handle);
    + if (retval)
    + evdev->open--;
    + }

    mutex_unlock(&evdev->mutex);
    return retval;
    --- a/drivers/input/joydev.c
    +++ b/drivers/input/joydev.c
    @@ -205,8 +205,11 @@ static int joydev_open_device(struct joy

    if (!joydev->exist)
    retval = -ENODEV;
    - else if (!joydev->open++)
    + else if (!joydev->open++) {
    retval = input_open_device(&joydev->handle);
    + if (retval)
    + joydev->open--;
    + }

    mutex_unlock(&joydev->mutex);
    return retval;
    --- a/drivers/input/mousedev.c
    +++ b/drivers/input/mousedev.c
    @@ -428,8 +428,11 @@ static int mousedev_open_device(struct m
    mixdev_open_devices();
    else if (!mousedev->exist)
    retval = -ENODEV;
    - else if (!mousedev->open++)
    + else if (!mousedev->open++) {
    retval = input_open_device(&mousedev->handle);
    + if (retval)
    + mousedev->open--;
    + }

    mutex_unlock(&mousedev->mutex);
    return retval;
    --- a/drivers/input/tsdev.c
    +++ b/drivers/input/tsdev.c
    @@ -185,8 +185,11 @@ static int tsdev_open_device(struct tsde

    if (!tsdev->exist)
    retval = -ENODEV;
    - else if (!tsdev->open++)
    + else if (!tsdev->open++) {
    retval = input_open_device(&tsdev->handle);
    + if (retval)
    + tsdev->open--;
    + }

    mutex_unlock(&tsdev->mutex);
    return retval;

    --
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  6. [patch 50/73] Input: mousedev - implement proper locking

    2.6.23-stable review patch. If anyone has any objections, please let us know.
    ------------------
    From: Dmitry Torokhov

    patch 464b241575f3700e14492e34f26bcd1794280f55 in mainline.

    Signed-off-by: Dmitry Torokhov
    Cc: Al Viro
    Signed-off-by: Greg Kroah-Hartman

    ---
    drivers/input/mousedev.c | 742 +++++++++++++++++++++++++++++------------------
    1 file changed, 470 insertions(+), 272 deletions(-)

    --- a/drivers/input/mousedev.c
    +++ b/drivers/input/mousedev.c
    @@ -61,9 +61,11 @@ struct mousedev {
    int open;
    int minor;
    char name[16];
    + struct input_handle handle;
    wait_queue_head_t wait;
    struct list_head client_list;
    - struct input_handle handle;
    + spinlock_t client_lock; /* protects client_list */
    + struct mutex mutex;
    struct device dev;

    struct list_head mixdev_node;
    @@ -113,108 +115,137 @@ static unsigned char mousedev_imex_seq[]
    static struct input_handler mousedev_handler;

    static struct mousedev *mousedev_table[MOUSEDEV_MINORS];
    +static DEFINE_MUTEX(mousedev_table_mutex);
    static struct mousedev *mousedev_mix;
    static LIST_HEAD(mousedev_mix_list);

    +static void mixdev_open_devices(void);
    +static void mixdev_close_devices(void);
    +
    #define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03])
    #define fy(i) (mousedev->old_y[(mousedev->pkt_count - (i)) & 03])

    -static void mousedev_touchpad_event(struct input_dev *dev, struct mousedev *mousedev, unsigned int code, int value)
    +static void mousedev_touchpad_event(struct input_dev *dev,
    + struct mousedev *mousedev,
    + unsigned int code, int value)
    {
    int size, tmp;
    enum { FRACTION_DENOM = 128 };

    switch (code) {
    - case ABS_X:
    - fx(0) = value;
    - if (mousedev->touch && mousedev->pkt_count >= 2) {
    - size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
    - if (size == 0)
    - size = 256 * 2;
    - tmp = ((value - fx(2)) * (256 * FRACTION_DENOM)) / size;
    - tmp += mousedev->frac_dx;
    - mousedev->packet.dx = tmp / FRACTION_DENOM;
    - mousedev->frac_dx = tmp - mousedev->packet.dx * FRACTION_DENOM;
    - }
    - break;

    - case ABS_Y:
    - fy(0) = value;
    - if (mousedev->touch && mousedev->pkt_count >= 2) {
    - /* use X size to keep the same scale */
    - size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
    - if (size == 0)
    - size = 256 * 2;
    - tmp = -((value - fy(2)) * (256 * FRACTION_DENOM)) / size;
    - tmp += mousedev->frac_dy;
    - mousedev->packet.dy = tmp / FRACTION_DENOM;
    - mousedev->frac_dy = tmp - mousedev->packet.dy * FRACTION_DENOM;
    - }
    - break;
    + case ABS_X:
    + fx(0) = value;
    + if (mousedev->touch && mousedev->pkt_count >= 2) {
    + size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
    + if (size == 0)
    + size = 256 * 2;
    + tmp = ((value - fx(2)) * 256 * FRACTION_DENOM) / size;
    + tmp += mousedev->frac_dx;
    + mousedev->packet.dx = tmp / FRACTION_DENOM;
    + mousedev->frac_dx =
    + tmp - mousedev->packet.dx * FRACTION_DENOM;
    + }
    + break;
    +
    + case ABS_Y:
    + fy(0) = value;
    + if (mousedev->touch && mousedev->pkt_count >= 2) {
    + /* use X size to keep the same scale */
    + size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
    + if (size == 0)
    + size = 256 * 2;
    + tmp = -((value - fy(2)) * 256 * FRACTION_DENOM) / size;
    + tmp += mousedev->frac_dy;
    + mousedev->packet.dy = tmp / FRACTION_DENOM;
    + mousedev->frac_dy = tmp -
    + mousedev->packet.dy * FRACTION_DENOM;
    + }
    + break;
    }
    }

    -static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev, unsigned int code, int value)
    +static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev,
    + unsigned int code, int value)
    {
    int size;

    switch (code) {
    - case ABS_X:
    - size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
    - if (size == 0)
    - size = xres ? : 1;
    - if (value > dev->absmax[ABS_X])
    - value = dev->absmax[ABS_X];
    - if (value < dev->absmin[ABS_X])
    - value = dev->absmin[ABS_X];
    - mousedev->packet.x = ((value - dev->absmin[ABS_X]) * xres) / size;
    - mousedev->packet.abs_event = 1;
    - break;

    - case ABS_Y:
    - size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y];
    - if (size == 0)
    - size = yres ? : 1;
    - if (value > dev->absmax[ABS_Y])
    - value = dev->absmax[ABS_Y];
    - if (value < dev->absmin[ABS_Y])
    - value = dev->absmin[ABS_Y];
    - mousedev->packet.y = yres - ((value - dev->absmin[ABS_Y]) * yres) / size;
    - mousedev->packet.abs_event = 1;
    - break;
    + case ABS_X:
    + size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
    + if (size == 0)
    + size = xres ? : 1;
    + if (value > dev->absmax[ABS_X])
    + value = dev->absmax[ABS_X];
    + if (value < dev->absmin[ABS_X])
    + value = dev->absmin[ABS_X];
    + mousedev->packet.x =
    + ((value - dev->absmin[ABS_X]) * xres) / size;
    + mousedev->packet.abs_event = 1;
    + break;
    +
    + case ABS_Y:
    + size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y];
    + if (size == 0)
    + size = yres ? : 1;
    + if (value > dev->absmax[ABS_Y])
    + value = dev->absmax[ABS_Y];
    + if (value < dev->absmin[ABS_Y])
    + value = dev->absmin[ABS_Y];
    + mousedev->packet.y = yres -
    + ((value - dev->absmin[ABS_Y]) * yres) / size;
    + mousedev->packet.abs_event = 1;
    + break;
    }
    }

    -static void mousedev_rel_event(struct mousedev *mousedev, unsigned int code, int value)
    +static void mousedev_rel_event(struct mousedev *mousedev,
    + unsigned int code, int value)
    {
    switch (code) {
    - case REL_X: mousedev->packet.dx += value; break;
    - case REL_Y: mousedev->packet.dy -= value; break;
    - case REL_WHEEL: mousedev->packet.dz -= value; break;
    + case REL_X:
    + mousedev->packet.dx += value;
    + break;
    +
    + case REL_Y:
    + mousedev->packet.dy -= value;
    + break;
    +
    + case REL_WHEEL:
    + mousedev->packet.dz -= value;
    + break;
    }
    }

    -static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int value)
    +static void mousedev_key_event(struct mousedev *mousedev,
    + unsigned int code, int value)
    {
    int index;

    switch (code) {
    - case BTN_TOUCH:
    - case BTN_0:
    - case BTN_LEFT: index = 0; break;
    - case BTN_STYLUS:
    - case BTN_1:
    - case BTN_RIGHT: index = 1; break;
    - case BTN_2:
    - case BTN_FORWARD:
    - case BTN_STYLUS2:
    - case BTN_MIDDLE: index = 2; break;
    - case BTN_3:
    - case BTN_BACK:
    - case BTN_SIDE: index = 3; break;
    - case BTN_4:
    - case BTN_EXTRA: index = 4; break;
    - default: return;
    +
    + case BTN_TOUCH:
    + case BTN_0:
    + case BTN_LEFT: index = 0; break;
    +
    + case BTN_STYLUS:
    + case BTN_1:
    + case BTN_RIGHT: index = 1; break;
    +
    + case BTN_2:
    + case BTN_FORWARD:
    + case BTN_STYLUS2:
    + case BTN_MIDDLE: index = 2; break;
    +
    + case BTN_3:
    + case BTN_BACK:
    + case BTN_SIDE: index = 3; break;
    +
    + case BTN_4:
    + case BTN_EXTRA: index = 4; break;
    +
    + default: return;
    }

    if (value) {
    @@ -226,19 +257,22 @@ static void mousedev_key_event(struct mo
    }
    }

    -static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_hw_data *packet)
    +static void mousedev_notify_readers(struct mousedev *mousedev,
    + struct mousedev_hw_data *packet)
    {
    struct mousedev_client *client;
    struct mousedev_motion *p;
    - unsigned long flags;
    + unsigned int new_head;
    int wake_readers = 0;

    - list_for_each_entry(client, &mousedev->client_list, node) {
    - spin_lock_irqsave(&client->packet_lock, flags);
    + list_for_each_entry_rcu(client, &mousedev->client_list, node) {
    +
    + /* Just acquire the lock, interrupts already disabled */
    + spin_lock(&client->packet_lock);

    p = &client->packets[client->head];
    if (client->ready && p->buttons != mousedev->packet.buttons) {
    - unsigned int new_head = (client->head + 1) % PACKET_QUEUE_LEN;
    + new_head = (client->head + 1) % PACKET_QUEUE_LEN;
    if (new_head != client->tail) {
    p = &client->packets[client->head = new_head];
    memset(p, 0, sizeof(struct mousedev_motion));
    @@ -253,19 +287,22 @@ static void mousedev_notify_readers(stru
    }

    client->pos_x += packet->dx;
    - client->pos_x = client->pos_x < 0 ? 0 : (client->pos_x >= xres ? xres : client->pos_x);
    + client->pos_x = client->pos_x < 0 ?
    + 0 : (client->pos_x >= xres ? xres : client->pos_x);
    client->pos_y += packet->dy;
    - client->pos_y = client->pos_y < 0 ? 0 : (client->pos_y >= yres ? yres : client->pos_y);
    + client->pos_y = client->pos_y < 0 ?
    + 0 : (client->pos_y >= yres ? yres : client->pos_y);

    p->dx += packet->dx;
    p->dy += packet->dy;
    p->dz += packet->dz;
    p->buttons = mousedev->packet.buttons;

    - if (p->dx || p->dy || p->dz || p->buttons != client->last_buttons)
    + if (p->dx || p->dy || p->dz ||
    + p->buttons != client->last_buttons)
    client->ready = 1;

    - spin_unlock_irqrestore(&client->packet_lock, flags);
    + spin_unlock(&client->packet_lock);

    if (client->ready) {
    kill_fasync(&client->fasync, SIGIO, POLL_IN);
    @@ -281,7 +318,8 @@ static void mousedev_touchpad_touch(stru
    {
    if (!value) {
    if (mousedev->touch &&
    - time_before(jiffies, mousedev->touch + msecs_to_jiffies(tap_time))) {
    + time_before(jiffies,
    + mousedev->touch + msecs_to_jiffies(tap_time))) {
    /*
    * Toggle left button to emulate tap.
    * We rely on the fact that mousedev_mix always has 0
    @@ -290,7 +328,8 @@ static void mousedev_touchpad_touch(stru
    set_bit(0, &mousedev->packet.buttons);
    set_bit(0, &mousedev_mix->packet.buttons);
    mousedev_notify_readers(mousedev, &mousedev_mix->packet);
    - mousedev_notify_readers(mousedev_mix, &mousedev_mix->packet);
    + mousedev_notify_readers(mousedev_mix,
    + &mousedev_mix->packet);
    clear_bit(0, &mousedev->packet.buttons);
    clear_bit(0, &mousedev_mix->packet.buttons);
    }
    @@ -302,54 +341,61 @@ static void mousedev_touchpad_touch(stru
    mousedev->touch = jiffies;
    }

    -static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
    +static void mousedev_event(struct input_handle *handle,
    + unsigned int type, unsigned int code, int value)
    {
    struct mousedev *mousedev = handle->private;

    switch (type) {
    - case EV_ABS:
    - /* Ignore joysticks */
    - if (test_bit(BTN_TRIGGER, handle->dev->keybit))
    - return;

    - if (test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
    - mousedev_touchpad_event(handle->dev, mousedev, code, value);
    + case EV_ABS:
    + /* Ignore joysticks */
    + if (test_bit(BTN_TRIGGER, handle->dev->keybit))
    + return;
    +
    + if (test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
    + mousedev_touchpad_event(handle->dev,
    + mousedev, code, value);
    + else
    + mousedev_abs_event(handle->dev, mousedev, code, value);
    +
    + break;
    +
    + case EV_REL:
    + mousedev_rel_event(mousedev, code, value);
    + break;
    +
    + case EV_KEY:
    + if (value != 2) {
    + if (code == BTN_TOUCH &&
    + test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
    + mousedev_touchpad_touch(mousedev, value);
    else
    - mousedev_abs_event(handle->dev, mousedev, code, value);
    -
    - break;
    -
    - case EV_REL:
    - mousedev_rel_event(mousedev, code, value);
    - break;
    + mousedev_key_event(mousedev, code, value);
    + }
    + break;

    - case EV_KEY:
    - if (value != 2) {
    - if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
    - mousedev_touchpad_touch(mousedev, value);
    - else
    - mousedev_key_event(mousedev, code, value);
    + case EV_SYN:
    + if (code == SYN_REPORT) {
    + if (mousedev->touch) {
    + mousedev->pkt_count++;
    + /*
    + * Input system eats duplicate events,
    + * but we need all of them to do correct
    + * averaging so apply present one forward
    + */
    + fx(0) = fx(1);
    + fy(0) = fy(1);
    }
    - break;
    -
    - case EV_SYN:
    - if (code == SYN_REPORT) {
    - if (mousedev->touch) {
    - mousedev->pkt_count++;
    - /* Input system eats duplicate events, but we need all of them
    - * to do correct averaging so apply present one forward
    - */
    - fx(0) = fx(1);
    - fy(0) = fy(1);
    - }

    - mousedev_notify_readers(mousedev, &mousedev->packet);
    - mousedev_notify_readers(mousedev_mix, &mousedev->packet);
    + mousedev_notify_readers(mousedev, &mousedev->packet);
    + mousedev_notify_readers(mousedev_mix, &mousedev->packet);

    - mousedev->packet.dx = mousedev->packet.dy = mousedev->packet.dz = 0;
    - mousedev->packet.abs_event = 0;
    - }
    - break;
    + mousedev->packet.dx = mousedev->packet.dy =
    + mousedev->packet.dz = 0;
    + mousedev->packet.abs_event = 0;
    + }
    + break;
    }
    }

    @@ -367,41 +413,45 @@ static void mousedev_free(struct device
    {
    struct mousedev *mousedev = container_of(dev, struct mousedev, dev);

    - mousedev_table[mousedev->minor] = NULL;
    kfree(mousedev);
    }

    -static int mixdev_add_device(struct mousedev *mousedev)
    +static int mousedev_open_device(struct mousedev *mousedev)
    {
    - int error;
    -
    - if (mousedev_mix->open) {
    - error = input_open_device(&mousedev->handle);
    - if (error)
    - return error;
    + int retval;

    - mousedev->open++;
    - mousedev->mixdev_open = 1;
    - }
    + retval = mutex_lock_interruptible(&mousedev->mutex);
    + if (retval)
    + return retval;

    - get_device(&mousedev->dev);
    - list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list);
    + if (mousedev->minor == MOUSEDEV_MIX)
    + mixdev_open_devices();
    + else if (!mousedev->exist)
    + retval = -ENODEV;
    + else if (!mousedev->open++)
    + retval = input_open_device(&mousedev->handle);

    - return 0;
    + mutex_unlock(&mousedev->mutex);
    + return retval;
    }

    -static void mixdev_remove_device(struct mousedev *mousedev)
    +static void mousedev_close_device(struct mousedev *mousedev)
    {
    - if (mousedev->mixdev_open) {
    - mousedev->mixdev_open = 0;
    - if (!--mousedev->open && mousedev->exist)
    - input_close_device(&mousedev->handle);
    - }
    + mutex_lock(&mousedev->mutex);

    - list_del_init(&mousedev->mixdev_node);
    - put_device(&mousedev->dev);
    + if (mousedev->minor == MOUSEDEV_MIX)
    + mixdev_close_devices();
    + else if (mousedev->exist && !--mousedev->open)
    + input_close_device(&mousedev->handle);
    +
    + mutex_unlock(&mousedev->mutex);
    }

    +/*
    + * Open all available devices so they can all be multiplexed in one.
    + * stream. Note that this function is called with mousedev_mix->mutex
    + * held.
    + */
    static void mixdev_open_devices(void)
    {
    struct mousedev *mousedev;
    @@ -411,16 +461,19 @@ static void mixdev_open_devices(void)

    list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
    if (!mousedev->mixdev_open) {
    - if (!mousedev->open && mousedev->exist)
    - if (input_open_device(&mousedev->handle))
    - continue;
    + if (mousedev_open_device(mousedev))
    + continue;

    - mousedev->open++;
    mousedev->mixdev_open = 1;
    }
    }
    }

    +/*
    + * Close all devices that were opened as part of multiplexed
    + * device. Note that this function is called with mousedev_mix->mutex
    + * held.
    + */
    static void mixdev_close_devices(void)
    {
    struct mousedev *mousedev;
    @@ -431,33 +484,50 @@ static void mixdev_close_devices(void)
    list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
    if (mousedev->mixdev_open) {
    mousedev->mixdev_open = 0;
    - if (!--mousedev->open && mousedev->exist)
    - input_close_device(&mousedev->handle);
    + mousedev_close_device(mousedev);
    }
    }
    }

    +
    +static void mousedev_attach_client(struct mousedev *mousedev,
    + struct mousedev_client *client)
    +{
    + spin_lock(&mousedev->client_lock);
    + list_add_tail_rcu(&client->node, &mousedev->client_list);
    + spin_unlock(&mousedev->client_lock);
    + /*
    + * We don't use synchronize_rcu() here because read-side
    + * critical section is protected by a spinlock (dev->event_lock)
    + * instead of rcu_read_lock().
    + */
    + synchronize_sched();
    +}
    +
    +static void mousedev_detach_client(struct mousedev *mousedev,
    + struct mousedev_client *client)
    +{
    + spin_lock(&mousedev->client_lock);
    + list_del_rcu(&client->node);
    + spin_unlock(&mousedev->client_lock);
    + synchronize_sched();
    +}
    +
    static int mousedev_release(struct inode *inode, struct file *file)
    {
    struct mousedev_client *client = file->private_data;
    struct mousedev *mousedev = client->mousedev;

    mousedev_fasync(-1, file, 0);
    -
    - list_del(&client->node);
    + mousedev_detach_client(mousedev, client);
    kfree(client);

    - if (mousedev->minor == MOUSEDEV_MIX)
    - mixdev_close_devices();
    - else if (!--mousedev->open && mousedev->exist)
    - input_close_device(&mousedev->handle);
    -
    + mousedev_close_device(mousedev);
    put_device(&mousedev->dev);

    return 0;
    }

    -
    static int mousedev_open(struct inode *inode, struct file *file)
    {
    struct mousedev_client *client;
    @@ -475,12 +545,17 @@ static int mousedev_open(struct inode *i
    if (i >= MOUSEDEV_MINORS)
    return -ENODEV;

    + error = mutex_lock_interruptible(&mousedev_table_mutex);
    + if (error)
    + return error;
    mousedev = mousedev_table[i];
    + if (mousedev)
    + get_device(&mousedev->dev);
    + mutex_unlock(&mousedev_table_mutex);
    +
    if (!mousedev)
    return -ENODEV;

    - get_device(&mousedev->dev);
    -
    client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL);
    if (!client) {
    error = -ENOMEM;
    @@ -491,21 +566,17 @@ static int mousedev_open(struct inode *i
    client->pos_x = xres / 2;
    client->pos_y = yres / 2;
    client->mousedev = mousedev;
    - list_add_tail(&client->node, &mousedev->client_list);
    + mousedev_attach_client(mousedev, client);

    - if (mousedev->minor == MOUSEDEV_MIX)
    - mixdev_open_devices();
    - else if (!mousedev->open++ && mousedev->exist) {
    - error = input_open_device(&mousedev->handle);
    - if (error)
    - goto err_free_client;
    - }
    + error = mousedev_open_device(mousedev);
    + if (error)
    + goto err_free_client;

    file->private_data = client;
    return 0;

    err_free_client:
    - list_del(&client->node);
    + mousedev_detach_client(mousedev, client);
    kfree(client);
    err_put_mousedev:
    put_device(&mousedev->dev);
    @@ -517,41 +588,41 @@ static inline int mousedev_limit_delta(i
    return delta > limit ? limit : (delta < -limit ? -limit : delta);
    }

    -static void mousedev_packet(struct mousedev_client *client, signed char *ps2_data)
    +static void mousedev_packet(struct mousedev_client *client,
    + signed char *ps2_data)
    {
    - struct mousedev_motion *p;
    - unsigned long flags;
    -
    - spin_lock_irqsave(&client->packet_lock, flags);
    - p = &client->packets[client->tail];
    + struct mousedev_motion *p = &client->packets[client->tail];

    - ps2_data[0] = 0x08 | ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07);
    + ps2_data[0] = 0x08 |
    + ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07);
    ps2_data[1] = mousedev_limit_delta(p->dx, 127);
    ps2_data[2] = mousedev_limit_delta(p->dy, 127);
    p->dx -= ps2_data[1];
    p->dy -= ps2_data[2];

    switch (client->mode) {
    - case MOUSEDEV_EMUL_EXPS:
    - ps2_data[3] = mousedev_limit_delta(p->dz, 7);
    - p->dz -= ps2_data[3];
    - ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1);
    - client->bufsiz = 4;
    - break;
    -
    - case MOUSEDEV_EMUL_IMPS:
    - ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
    - ps2_data[3] = mousedev_limit_delta(p->dz, 127);
    - p->dz -= ps2_data[3];
    - client->bufsiz = 4;
    - break;
    -
    - case MOUSEDEV_EMUL_PS2:
    - default:
    - ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
    - p->dz = 0;
    - client->bufsiz = 3;
    - break;
    + case MOUSEDEV_EMUL_EXPS:
    + ps2_data[3] = mousedev_limit_delta(p->dz, 7);
    + p->dz -= ps2_data[3];
    + ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1);
    + client->bufsiz = 4;
    + break;
    +
    + case MOUSEDEV_EMUL_IMPS:
    + ps2_data[0] |=
    + ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
    + ps2_data[3] = mousedev_limit_delta(p->dz, 127);
    + p->dz -= ps2_data[3];
    + client->bufsiz = 4;
    + break;
    +
    + case MOUSEDEV_EMUL_PS2:
    + default:
    + ps2_data[0] |=
    + ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
    + p->dz = 0;
    + client->bufsiz = 3;
    + break;
    }

    if (!p->dx && !p->dy && !p->dz) {
    @@ -561,12 +632,56 @@ static void mousedev_packet(struct mouse
    } else
    client->tail = (client->tail + 1) % PACKET_QUEUE_LEN;
    }
    -
    - spin_unlock_irqrestore(&client->packet_lock, flags);
    }

    +static void mousedev_generate_response(struct mousedev_client *client,
    + int command)
    +{
    + client->ps2[0] = 0xfa; /* ACK */
    +
    + switch (command) {

    -static ssize_t mousedev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
    + case 0xeb: /* Poll */
    + mousedev_packet(client, &client->ps2[1]);
    + client->bufsiz++; /* account for leading ACK */
    + break;
    +
    + case 0xf2: /* Get ID */
    + switch (client->mode) {
    + case MOUSEDEV_EMUL_PS2:
    + client->ps2[1] = 0;
    + break;
    + case MOUSEDEV_EMUL_IMPS:
    + client->ps2[1] = 3;
    + break;
    + case MOUSEDEV_EMUL_EXPS:
    + client->ps2[1] = 4;
    + break;
    + }
    + client->bufsiz = 2;
    + break;
    +
    + case 0xe9: /* Get info */
    + client->ps2[1] = 0x60; client->ps2[2] = 3; client->ps2[3] = 200;
    + client->bufsiz = 4;
    + break;
    +
    + case 0xff: /* Reset */
    + client->impsseq = client->imexseq = 0;
    + client->mode = MOUSEDEV_EMUL_PS2;
    + client->ps2[1] = 0xaa; client->ps2[2] = 0x00;
    + client->bufsiz = 3;
    + break;
    +
    + default:
    + client->bufsiz = 1;
    + break;
    + }
    + client->buffer = client->bufsiz;
    +}
    +
    +static ssize_t mousedev_write(struct file *file, const char __user *buffer,
    + size_t count, loff_t *ppos)
    {
    struct mousedev_client *client = file->private_data;
    unsigned char c;
    @@ -577,6 +692,8 @@ static ssize_t mousedev_write(struct fil
    if (get_user(c, buffer + i))
    return -EFAULT;

    + spin_lock_irq(&client->packet_lock);
    +
    if (c == mousedev_imex_seq[client->imexseq]) {
    if (++client->imexseq == MOUSEDEV_SEQ_LEN) {
    client->imexseq = 0;
    @@ -593,68 +710,39 @@ static ssize_t mousedev_write(struct fil
    } else
    client->impsseq = 0;

    - client->ps2[0] = 0xfa;
    -
    - switch (c) {
    -
    - case 0xeb: /* Poll */
    - mousedev_packet(client, &client->ps2[1]);
    - client->bufsiz++; /* account for leading ACK */
    - break;
    -
    - case 0xf2: /* Get ID */
    - switch (client->mode) {
    - case MOUSEDEV_EMUL_PS2: client->ps2[1] = 0; break;
    - case MOUSEDEV_EMUL_IMPS: client->ps2[1] = 3; break;
    - case MOUSEDEV_EMUL_EXPS: client->ps2[1] = 4; break;
    - }
    - client->bufsiz = 2;
    - break;
    -
    - case 0xe9: /* Get info */
    - client->ps2[1] = 0x60; client->ps2[2] = 3; client->ps2[3] = 200;
    - client->bufsiz = 4;
    - break;
    -
    - case 0xff: /* Reset */
    - client->impsseq = client->imexseq = 0;
    - client->mode = MOUSEDEV_EMUL_PS2;
    - client->ps2[1] = 0xaa; client->ps2[2] = 0x00;
    - client->bufsiz = 3;
    - break;
    -
    - default:
    - client->bufsiz = 1;
    - break;
    - }
    + mousedev_generate_response(client, c);

    - client->buffer = client->bufsiz;
    + spin_unlock_irq(&client->packet_lock);
    }

    kill_fasync(&client->fasync, SIGIO, POLL_IN);
    -
    wake_up_interruptible(&client->mousedev->wait);

    return count;
    }

    -static ssize_t mousedev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
    +static ssize_t mousedev_read(struct file *file, char __user *buffer,
    + size_t count, loff_t *ppos)
    {
    struct mousedev_client *client = file->private_data;
    + struct mousedev *mousedev = client->mousedev;
    + signed char data[sizeof(client->ps2)];
    int retval = 0;

    - if (!client->ready && !client->buffer && (file->f_flags & O_NONBLOCK))
    + if (!client->ready && !client->buffer && mousedev->exist &&
    + (file->f_flags & O_NONBLOCK))
    return -EAGAIN;

    - retval = wait_event_interruptible(client->mousedev->wait,
    - !client->mousedev->exist || client->ready || client->buffer);
    -
    + retval = wait_event_interruptible(mousedev->wait,
    + !mousedev->exist || client->ready || client->buffer);
    if (retval)
    return retval;

    - if (!client->mousedev->exist)
    + if (!mousedev->exist)
    return -ENODEV;

    + spin_lock_irq(&client->packet_lock);
    +
    if (!client->buffer && client->ready) {
    mousedev_packet(client, client->ps2);
    client->buffer = client->bufsiz;
    @@ -663,9 +751,12 @@ static ssize_t mousedev_read(struct file
    if (count > client->buffer)
    count = client->buffer;

    + memcpy(data, client->ps2 + client->bufsiz - client->buffer, count);
    client->buffer -= count;

    - if (copy_to_user(buffer, client->ps2 + client->bufsiz - client->buffer - count, count))
    + spin_unlock_irq(&client->packet_lock);
    +
    + if (copy_to_user(buffer, data, count))
    return -EFAULT;

    return count;
    @@ -692,6 +783,60 @@ static const struct file_operations mous
    .fasync = mousedev_fasync,
    };

    +static int mousedev_install_chrdev(struct mousedev *mousedev)
    +{
    + mousedev_table[mousedev->minor] = mousedev;
    + return 0;
    +}
    +
    +static void mousedev_remove_chrdev(struct mousedev *mousedev)
    +{
    + mutex_lock(&mousedev_table_mutex);
    + mousedev_table[mousedev->minor] = NULL;
    + mutex_unlock(&mousedev_table_mutex);
    +}
    +
    +/*
    + * Mark device non-existent. This disables writes, ioctls and
    + * prevents new users from opening the device. Already posted
    + * blocking reads will stay, however new ones will fail.
    + */
    +static void mousedev_mark_dead(struct mousedev *mousedev)
    +{
    + mutex_lock(&mousedev->mutex);
    + mousedev->exist = 0;
    + mutex_unlock(&mousedev->mutex);
    +}
    +
    +/*
    + * Wake up users waiting for IO so they can disconnect from
    + * dead device.
    + */
    +static void mousedev_hangup(struct mousedev *mousedev)
    +{
    + struct mousedev_client *client;
    +
    + spin_lock(&mousedev->client_lock);
    + list_for_each_entry(client, &mousedev->client_list, node)
    + kill_fasync(&client->fasync, SIGIO, POLL_HUP);
    + spin_unlock(&mousedev->client_lock);
    +
    + wake_up_interruptible(&mousedev->wait);
    +}
    +
    +static void mousedev_cleanup(struct mousedev *mousedev)
    +{
    + struct input_handle *handle = &mousedev->handle;
    +
    + mousedev_mark_dead(mousedev);
    + mousedev_hangup(mousedev);
    + mousedev_remove_chrdev(mousedev);
    +
    + /* mousedev is marked dead so no one else accesses mousedev->open */
    + if (mousedev->open)
    + input_close_device(handle);
    +}
    +
    static struct mousedev *mousedev_create(struct input_dev *dev,
    struct input_handler *handler,
    int minor)
    @@ -707,6 +852,10 @@ static struct mousedev *mousedev_create(

    INIT_LIST_HEAD(&mousedev->client_list);
    INIT_LIST_HEAD(&mousedev->mixdev_node);
    + spin_lock_init(&mousedev->client_lock);
    + mutex_init(&mousedev->mutex);
    + lockdep_set_subclass(&mousedev->mutex,
    + minor == MOUSEDEV_MIX ? MOUSEDEV_MIX : 0);
    init_waitqueue_head(&mousedev->wait);

    if (minor == MOUSEDEV_MIX)
    @@ -731,14 +880,27 @@ static struct mousedev *mousedev_create(
    mousedev->dev.release = mousedev_free;
    device_initialize(&mousedev->dev);

    - mousedev_table[minor] = mousedev;
    + if (minor != MOUSEDEV_MIX) {
    + error = input_register_handle(&mousedev->handle);
    + if (error)
    + goto err_free_mousedev;
    + }
    +
    + error = mousedev_install_chrdev(mousedev);
    + if (error)
    + goto err_unregister_handle;

    error = device_add(&mousedev->dev);
    if (error)
    - goto err_free_mousedev;
    + goto err_cleanup_mousedev;

    return mousedev;

    + err_cleanup_mousedev:
    + mousedev_cleanup(mousedev);
    + err_unregister_handle:
    + if (minor != MOUSEDEV_MIX)
    + input_unregister_handle(&mousedev->handle);
    err_free_mousedev:
    put_device(&mousedev->dev);
    err_out:
    @@ -747,29 +909,64 @@ static struct mousedev *mousedev_create(

    static void mousedev_destroy(struct mousedev *mousedev)
    {
    - struct mousedev_client *client;
    -
    device_del(&mousedev->dev);
    - mousedev->exist = 0;
    + mousedev_cleanup(mousedev);
    + if (mousedev->minor != MOUSEDEV_MIX)
    + input_unregister_handle(&mousedev->handle);
    + put_device(&mousedev->dev);
    +}

    - if (mousedev->open) {
    - input_close_device(&mousedev->handle);
    - list_for_each_entry(client, &mousedev->client_list, node)
    - kill_fasync(&client->fasync, SIGIO, POLL_HUP);
    - wake_up_interruptible(&mousedev->wait);
    +static int mixdev_add_device(struct mousedev *mousedev)
    +{
    + int retval;
    +
    + retval = mutex_lock_interruptible(&mousedev_mix->mutex);
    + if (retval)
    + return retval;
    +
    + if (mousedev_mix->open) {
    + retval = mousedev_open_device(mousedev);
    + if (retval)
    + goto out;
    +
    + mousedev->mixdev_open = 1;
    }

    + get_device(&mousedev->dev);
    + list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list);
    +
    + out:
    + mutex_unlock(&mousedev_mix->mutex);
    + return retval;
    +}
    +
    +static void mixdev_remove_device(struct mousedev *mousedev)
    +{
    + mutex_lock(&mousedev_mix->mutex);
    +
    + if (mousedev->mixdev_open) {
    + mousedev->mixdev_open = 0;
    + mousedev_close_device(mousedev);
    + }
    +
    + list_del_init(&mousedev->mixdev_node);
    + mutex_unlock(&mousedev_mix->mutex);
    +
    put_device(&mousedev->dev);
    }

    -static int mousedev_connect(struct input_handler *handler, struct input_dev *dev,
    +static int mousedev_connect(struct input_handler *handler,
    + struct input_dev *dev,
    const struct input_device_id *id)
    {
    struct mousedev *mousedev;
    int minor;
    int error;

    - for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++);
    + for (minor = 0; minor < MOUSEDEV_MINORS; minor++)
    + if (!mousedev_table[minor])
    + break;
    +
    if (minor == MOUSEDEV_MINORS) {
    printk(KERN_ERR "mousedev: no more free mousedev devices\n");
    return -ENFILE;
    @@ -779,21 +976,13 @@ static int mousedev_connect(struct input
    if (IS_ERR(mousedev))
    return PTR_ERR(mousedev);

    - error = input_register_handle(&mousedev->handle);
    - if (error)
    - goto err_delete_mousedev;
    -
    error = mixdev_add_device(mousedev);
    - if (error)
    - goto err_unregister_handle;
    + if (error) {
    + mousedev_destroy(mousedev);
    + return error;
    + }

    return 0;
    -
    - err_unregister_handle:
    - input_unregister_handle(&mousedev->handle);
    - err_delete_mousedev:
    - device_unregister(&mousedev->dev);
    - return error;
    }

    static void mousedev_disconnect(struct input_handle *handle)
    @@ -801,33 +990,42 @@ static void mousedev_disconnect(struct i
    struct mousedev *mousedev = handle->private;

    mixdev_remove_device(mousedev);
    - input_unregister_handle(handle);
    mousedev_destroy(mousedev);
    }

    static const struct input_device_id mousedev_ids[] = {
    {
    - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT,
    + .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
    + INPUT_DEVICE_ID_MATCH_KEYBIT |
    + INPUT_DEVICE_ID_MATCH_RELBIT,
    .evbit = { BIT(EV_KEY) | BIT(EV_REL) },
    .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) },
    .relbit = { BIT(REL_X) | BIT(REL_Y) },
    - }, /* A mouse like device, at least one button, two relative axes */
    + }, /* A mouse like device, at least one button,
    + two relative axes */
    {
    - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_RELBIT,
    + .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
    + INPUT_DEVICE_ID_MATCH_RELBIT,
    .evbit = { BIT(EV_KEY) | BIT(EV_REL) },
    .relbit = { BIT(REL_WHEEL) },
    }, /* A separate scrollwheel */
    {
    - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
    + .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
    + INPUT_DEVICE_ID_MATCH_KEYBIT |
    + INPUT_DEVICE_ID_MATCH_ABSBIT,
    .evbit = { BIT(EV_KEY) | BIT(EV_ABS) },
    .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) },
    .absbit = { BIT(ABS_X) | BIT(ABS_Y) },
    - }, /* A tablet like device, at least touch detection, two absolute axes */
    + }, /* A tablet like device, at least touch detection,
    + two absolute axes */
    {
    - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
    + .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
    + INPUT_DEVICE_ID_MATCH_KEYBIT |
    + INPUT_DEVICE_ID_MATCH_ABSBIT,
    .evbit = { BIT(EV_KEY) | BIT(EV_ABS) },
    .keybit = { [LONG(BTN_TOOL_FINGER)] = BIT(BTN_TOOL_FINGER) },
    - .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_TOOL_WIDTH) },
    + .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) |
    + BIT(ABS_TOOL_WIDTH) },
    }, /* A touchpad */

    { }, /* Terminating entry */

    --
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  7. [patch 61/73] sata_promise: ASIC PRD table bug workaround

    2.6.23-stable review patch. If anyone has any objections, please let us know.
    ------------------
    From: Mikael Pettersson

    patch 03116d67e0973bb493fe9307e28973a24a272bcc in mainline.

    Second-generation Promise SATA controllers have an ASIC bug
    which can trigger if the last PRD entry is larger than 164 bytes,
    resulting in intermittent errors and possible data corruption.

    Work around this by replacing calls to ata_qc_prep() with a
    private version that fills the PRD, checks the size of the
    last entry, and if necessary splits it to avoid the bug.
    Also reduce sg_tablesize by 1 to accommodate the new entry.

    Tested on the second-generation SATA300 TX4 and SATA300 TX2plus,
    and the first-generation PDC20378.

    Thanks to Alexander Sabourenkov for verifying the bug by
    studying the vendor driver, and for writing the initial patch
    upon which this one is based.

    Signed-off-by: Mikael Pettersson
    Signed-off-by: Greg Kroah-Hartman

    ---
    drivers/ata/sata_promise.c | 87 ++++++++++++++++++++++++++++++++++++++++++---
    1 file changed, 83 insertions(+), 4 deletions(-)

    --- a/drivers/ata/sata_promise.c
    +++ b/drivers/ata/sata_promise.c
    @@ -50,6 +50,7 @@
    enum {
    PDC_MAX_PORTS = 4,
    PDC_MMIO_BAR = 3,
    + PDC_MAX_PRD = LIBATA_MAX_PRD - 1, /* -1 for ASIC PRD bug workaround */

    /* register offsets */
    PDC_FEATURE = 0x04, /* Feature/Error reg (per port) */
    @@ -155,7 +156,7 @@ static struct scsi_host_template pdc_ata
    .queuecommand = ata_scsi_queuecmd,
    .can_queue = ATA_DEF_QUEUE,
    .this_id = ATA_SHT_THIS_ID,
    - .sg_tablesize = LIBATA_MAX_PRD,
    + .sg_tablesize = PDC_MAX_PRD,
    .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
    .emulated = ATA_SHT_EMULATED,
    .use_clustering = ATA_SHT_USE_CLUSTERING,
    @@ -527,6 +528,84 @@ static void pdc_atapi_pkt(struct ata_que
    memcpy(buf+31, cdb, cdb_len);
    }

    +/**
    + * pdc_fill_sg - Fill PCI IDE PRD table
    + * @qc: Metadata associated with taskfile to be transferred
    + *
    + * Fill PCI IDE PRD (scatter-gather) table with segments
    + * associated with the current disk command.
    + * Make sure hardware does not choke on it.
    + *
    + * LOCKING:
    + * spin_lock_irqsave(host lock)
    + *
    + */
    +static void pdc_fill_sg(struct ata_queued_cmd *qc)
    +{
    + struct ata_port *ap = qc->ap;
    + struct scatterlist *sg;
    + unsigned int idx;
    + const u32 SG_COUNT_ASIC_BUG = 41*4;
    +
    + if (!(qc->flags & ATA_QCFLAG_DMAMAP))
    + return;
    +
    + WARN_ON(qc->__sg == NULL);
    + WARN_ON(qc->n_elem == 0 && qc->pad_len == 0);
    +
    + idx = 0;
    + ata_for_each_sg(sg, qc) {
    + u32 addr, offset;
    + u32 sg_len, len;
    +
    + /* determine if physical DMA addr spans 64K boundary.
    + * Note h/w doesn't support 64-bit, so we unconditionally
    + * truncate dma_addr_t to u32.
    + */
    + addr = (u32) sg_dma_address(sg);
    + sg_len = sg_dma_len(sg);
    +
    + while (sg_len) {
    + offset = addr & 0xffff;
    + len = sg_len;
    + if ((offset + sg_len) > 0x10000)
    + len = 0x10000 - offset;
    +
    + ap->prd[idx].addr = cpu_to_le32(addr);
    + ap->prd[idx].flags_len = cpu_to_le32(len & 0xffff);
    + VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len);
    +
    + idx++;
    + sg_len -= len;
    + addr += len;
    + }
    + }
    +
    + if (idx) {
    + u32 len = le32_to_cpu(ap->prd[idx - 1].flags_len);
    +
    + if (len > SG_COUNT_ASIC_BUG) {
    + u32 addr;
    +
    + VPRINTK("Splitting last PRD.\n");
    +
    + addr = le32_to_cpu(ap->prd[idx - 1].addr);
    + ap->prd[idx - 1].flags_len = cpu_to_le32(len - SG_COUNT_ASIC_BUG);
    + VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx - 1, addr, SG_COUNT_ASIC_BUG);
    +
    + addr = addr + len - SG_COUNT_ASIC_BUG;
    + len = SG_COUNT_ASIC_BUG;
    + ap->prd[idx].addr = cpu_to_le32(addr);
    + ap->prd[idx].flags_len = cpu_to_le32(len);
    + VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len);
    +
    + idx++;
    + }
    +
    + ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
    + }
    +}
    +
    static void pdc_qc_prep(struct ata_queued_cmd *qc)
    {
    struct pdc_port_priv *pp = qc->ap->private_data;
    @@ -536,7 +615,7 @@ static void pdc_qc_prep(struct ata_queue

    switch (qc->tf.protocol) {
    case ATA_PROT_DMA:
    - ata_qc_prep(qc);
    + pdc_fill_sg(qc);
    /* fall through */

    case ATA_PROT_NODATA:
    @@ -552,11 +631,11 @@ static void pdc_qc_prep(struct ata_queue
    break;

    case ATA_PROT_ATAPI:
    - ata_qc_prep(qc);
    + pdc_fill_sg(qc);
    break;

    case ATA_PROT_ATAPI_DMA:
    - ata_qc_prep(qc);
    + pdc_fill_sg(qc);
    /*FALLTHROUGH*/
    case ATA_PROT_ATAPI_NODATA:
    pdc_atapi_pkt(qc);

    --
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  8. [patch 54/73] CIFS: Respect umask when using POSIX mkdir

    2.6.23-stable review patch. If anyone has any objections, please let us know.
    ------------------
    From: Steve French

    patch a8cd925f74c3b1b6d1192f9e75f9d12cc2ab148a in mainline.

    [CIFS] Respect umask when using POSIX mkdir

    When making a directory with POSIX mkdir calls, cifs_mkdir does not
    respect the umask. This patch causes the new POSIX mkdir to create with
    the right mode

    Signed-off-by: Jeff Layton
    Signed-off-by: Steve French
    Cc: maximilian attems
    Signed-off-by: Greg Kroah-Hartman

    ---
    fs/cifs/inode.c | 1 +
    1 file changed, 1 insertion(+)

    --- a/fs/cifs/inode.c
    +++ b/fs/cifs/inode.c
    @@ -919,6 +919,7 @@ int cifs_mkdir(struct inode *inode, stru
    goto mkdir_out;
    }

    + mode &= ~current->fs->umask;
    rc = CIFSPOSIXCreate(xid, pTcon, SMB_O_DIRECTORY | SMB_O_CREAT,
    mode, NULL /* netfid */, pInfo, &oplock,
    full_path, cifs_sb->local_nls,

    --
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  9. [patch 63/73] Fix unbalanced helper_lock in kernel/kmod.c


    2.6.23-stable review patch. If anyone has any objections, please let us know.
    ------------------
    From: Nigel Cunningham

    patch 784680336b616dcc4c17cbd25add3b49c555cdeb in mainline.

    call_usermodehelper_exec() has an exit path that can leave the
    helper_lock() call at the top of the routine unbalanced. The attached
    patch fixes this issue.

    Signed-off-by: Nigel Cunningham
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds
    Signed-off-by: Greg Kroah-Hartman

    ---
    kernel/kmod.c | 13 ++++++-------
    1 file changed, 6 insertions(+), 7 deletions(-)

    --- a/kernel/kmod.c
    +++ b/kernel/kmod.c
    @@ -451,13 +451,11 @@ int call_usermodehelper_exec(struct subp
    enum umh_wait wait)
    {
    DECLARE_COMPLETION_ONSTACK(done);
    - int retval;
    + int retval = 0;

    helper_lock();
    - if (sub_info->path[0] == '\0') {
    - retval = 0;
    + if (sub_info->path[0] == '\0')
    goto out;
    - }

    if (!khelper_wq || usermodehelper_disabled) {
    retval = -EBUSY;
    @@ -468,13 +466,14 @@ int call_usermodehelper_exec(struct subp
    sub_info->wait = wait;

    queue_work(khelper_wq, &sub_info->work);
    - if (wait == UMH_NO_WAIT) /* task has freed sub_info */
    - return 0;
    + if (wait == UMH_NO_WAIT) /* task has freed sub_info */
    + goto unlock;
    wait_for_completion(&done);
    retval = sub_info->retval;

    - out:
    +out:
    call_usermodehelper_freeinfo(sub_info);
    +unlock:
    helper_unlock();
    return retval;
    }

    --
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  10. [patch 64/73] spi: omap2_mcspi PIO RX fix


    2.6.23-stable review patch. If anyone has any objections, please let us know.
    ------------------
    From: Kalle Valo

    patch feed9bab7b14b77be8d796bcee95e2343fb82955 in mainline.

    Before transmission of the last word in PIO RX_ONLY mode rx+tx mode
    is enabled:

    /* prevent last RX_ONLY read from triggering
    * more word i/o: switch to rx+tx
    */
    if (c == 0 && tx == NULL)
    mcspi_write_cs_reg(spi,
    OMAP2_MCSPI_CHCONF0, l);

    But because c is decremented after the test, c will never be zero and
    rx+tx will not be enabled. This breaks RX_ONLY mode PIO transfers.

    Fix it by decrementing c in the beginning of the various I/O loops.

    Signed-off-by: Kalle Valo
    Signed-off-by: David Brownell
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds
    Signed-off-by: Greg Kroah-Hartman

    ---
    drivers/spi/omap2_mcspi.c | 6 +++---
    1 file changed, 3 insertions(+), 3 deletions(-)

    --- a/drivers/spi/omap2_mcspi.c
    +++ b/drivers/spi/omap2_mcspi.c
    @@ -350,6 +350,7 @@ omap2_mcspi_txrx_pio(struct spi_device *
    tx = xfer->tx_buf;

    do {
    + c -= 1;
    if (tx != NULL) {
    if (mcspi_wait_for_reg_bit(chstat_reg,
    OMAP2_MCSPI_CHSTAT_TXS) < 0) {
    @@ -380,7 +381,6 @@ omap2_mcspi_txrx_pio(struct spi_device *
    word_len, *(rx - 1));
    #endif
    }
    - c -= 1;
    } while (c);
    } else if (word_len <= 16) {
    u16 *rx;
    @@ -389,6 +389,7 @@ omap2_mcspi_txrx_pio(struct spi_device *
    rx = xfer->rx_buf;
    tx = xfer->tx_buf;
    do {
    + c -= 2;
    if (tx != NULL) {
    if (mcspi_wait_for_reg_bit(chstat_reg,
    OMAP2_MCSPI_CHSTAT_TXS) < 0) {
    @@ -419,7 +420,6 @@ omap2_mcspi_txrx_pio(struct spi_device *
    word_len, *(rx - 1));
    #endif
    }
    - c -= 2;
    } while (c);
    } else if (word_len <= 32) {
    u32 *rx;
    @@ -428,6 +428,7 @@ omap2_mcspi_txrx_pio(struct spi_device *
    rx = xfer->rx_buf;
    tx = xfer->tx_buf;
    do {
    + c -= 4;
    if (tx != NULL) {
    if (mcspi_wait_for_reg_bit(chstat_reg,
    OMAP2_MCSPI_CHSTAT_TXS) < 0) {
    @@ -458,7 +459,6 @@ omap2_mcspi_txrx_pio(struct spi_device *
    word_len, *(rx - 1));
    #endif
    }
    - c -= 4;
    } while (c);
    }


    --
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  11. [patch 52/73] Input: tsdev - implement proper locking

    2.6.23-stable review patch. If anyone has any objections, please let us know.
    ------------------
    From: Dmitry Torokhov

    patch b9d2d110b10f7b4788d0fdd328cf57e34b767817 in mainline.

    Signed-off-by: Dmitry Torokhov
    Cc: Al Viro
    Signed-off-by: Greg Kroah-Hartman

    ---
    drivers/input/tsdev.c | 392 +++++++++++++++++++++++++++++++++++---------------
    1 file changed, 278 insertions(+), 114 deletions(-)

    --- a/drivers/input/tsdev.c
    +++ b/drivers/input/tsdev.c
    @@ -112,6 +112,8 @@ struct tsdev {
    struct input_handle handle;
    wait_queue_head_t wait;
    struct list_head client_list;
    + spinlock_t client_lock; /* protects client_list */
    + struct mutex mutex;
    struct device dev;

    int x, y, pressure;
    @@ -122,8 +124,9 @@ struct tsdev_client {
    struct fasync_struct *fasync;
    struct list_head node;
    struct tsdev *tsdev;
    + struct ts_event buffer[TSDEV_BUFFER_SIZE];
    int head, tail;
    - struct ts_event event[TSDEV_BUFFER_SIZE];
    + spinlock_t buffer_lock; /* protects access to buffer, head and tail */
    int raw;
    };

    @@ -137,6 +140,7 @@ struct tsdev_client {
    #define TS_SET_CAL _IOW(IOC_H3600_TS_MAGIC, 11, struct ts_calibration)

    static struct tsdev *tsdev_table[TSDEV_MINORS/2];
    +static DEFINE_MUTEX(tsdev_table_mutex);

    static int tsdev_fasync(int fd, struct file *file, int on)
    {
    @@ -144,9 +148,91 @@ static int tsdev_fasync(int fd, struct f
    int retval;

    retval = fasync_helper(fd, file, on, &client->fasync);
    +
    return retval < 0 ? retval : 0;
    }

    +static void tsdev_free(struct device *dev)
    +{
    + struct tsdev *tsdev = container_of(dev, struct tsdev, dev);
    +
    + kfree(tsdev);
    +}
    +
    +static void tsdev_attach_client(struct tsdev *tsdev, struct tsdev_client *client)
    +{
    + spin_lock(&tsdev->client_lock);
    + list_add_tail_rcu(&client->node, &tsdev->client_list);
    + spin_unlock(&tsdev->client_lock);
    + synchronize_sched();
    +}
    +
    +static void tsdev_detach_client(struct tsdev *tsdev, struct tsdev_client *client)
    +{
    + spin_lock(&tsdev->client_lock);
    + list_del_rcu(&client->node);
    + spin_unlock(&tsdev->client_lock);
    + synchronize_sched();
    +}
    +
    +static int tsdev_open_device(struct tsdev *tsdev)
    +{
    + int retval;
    +
    + retval = mutex_lock_interruptible(&tsdev->mutex);
    + if (retval)
    + return retval;
    +
    + if (!tsdev->exist)
    + retval = -ENODEV;
    + else if (!tsdev->open++)
    + retval = input_open_device(&tsdev->handle);
    +
    + mutex_unlock(&tsdev->mutex);
    + return retval;
    +}
    +
    +static void tsdev_close_device(struct tsdev *tsdev)
    +{
    + mutex_lock(&tsdev->mutex);
    +
    + if (tsdev->exist && !--tsdev->open)
    + input_close_device(&tsdev->handle);
    +
    + mutex_unlock(&tsdev->mutex);
    +}
    +
    +/*
    + * Wake up users waiting for IO so they can disconnect from
    + * dead device.
    + */
    +static void tsdev_hangup(struct tsdev *tsdev)
    +{
    + struct tsdev_client *client;
    +
    + spin_lock(&tsdev->client_lock);
    + list_for_each_entry(client, &tsdev->client_list, node)
    + kill_fasync(&client->fasync, SIGIO, POLL_HUP);
    + spin_unlock(&tsdev->client_lock);
    +
    + wake_up_interruptible(&tsdev->wait);
    +}
    +
    +static int tsdev_release(struct inode *inode, struct file *file)
    +{
    + struct tsdev_client *client = file->private_data;
    + struct tsdev *tsdev = client->tsdev;
    +
    + tsdev_fasync(-1, file, 0);
    + tsdev_detach_client(tsdev, client);
    + kfree(client);
    +
    + tsdev_close_device(tsdev);
    + put_device(&tsdev->dev);
    +
    + return 0;
    +}
    +
    static int tsdev_open(struct inode *inode, struct file *file)
    {
    int i = iminor(inode) - TSDEV_MINOR_BASE;
    @@ -161,11 +247,16 @@ static int tsdev_open(struct inode *inod
    if (i >= TSDEV_MINORS)
    return -ENODEV;

    + error = mutex_lock_interruptible(&tsdev_table_mutex);
    + if (error)
    + return error;
    tsdev = tsdev_table[i & TSDEV_MINOR_MASK];
    - if (!tsdev || !tsdev->exist)
    - return -ENODEV;
    + if (tsdev)
    + get_device(&tsdev->dev);
    + mutex_unlock(&tsdev_table_mutex);

    - get_device(&tsdev->dev);
    + if (!tsdev)
    + return -ENODEV;

    client = kzalloc(sizeof(struct tsdev_client), GFP_KERNEL);
    if (!client) {
    @@ -173,51 +264,42 @@ static int tsdev_open(struct inode *inod
    goto err_put_tsdev;
    }

    + spin_lock_init(&client->buffer_lock);
    client->tsdev = tsdev;
    - client->raw = (i >= TSDEV_MINORS / 2) ? 1 : 0;
    - list_add_tail(&client->node, &tsdev->client_list);
    + client->raw = i >= TSDEV_MINORS / 2;
    + tsdev_attach_client(tsdev, client);

    - if (!tsdev->open++ && tsdev->exist) {
    - error = input_open_device(&tsdev->handle);
    - if (error)
    - goto err_free_client;
    - }
    + error = tsdev_open_device(tsdev);
    + if (error)
    + goto err_free_client;

    file->private_data = client;
    return 0;

    err_free_client:
    - list_del(&client->node);
    + tsdev_detach_client(tsdev, client);
    kfree(client);
    err_put_tsdev:
    put_device(&tsdev->dev);
    return error;
    }

    -static void tsdev_free(struct device *dev)
    +static int tsdev_fetch_next_event(struct tsdev_client *client,
    + struct ts_event *event)
    {
    - struct tsdev *tsdev = container_of(dev, struct tsdev, dev);
    + int have_event;

    - tsdev_table[tsdev->minor] = NULL;
    - kfree(tsdev);
    -}
    -
    -static int tsdev_release(struct inode *inode, struct file *file)
    -{
    - struct tsdev_client *client = file->private_data;
    - struct tsdev *tsdev = client->tsdev;
    -
    - tsdev_fasync(-1, file, 0);
    + spin_lock_irq(&client->buffer_lock);

    - list_del(&client->node);
    - kfree(client);
    -
    - if (!--tsdev->open && tsdev->exist)
    - input_close_device(&tsdev->handle);
    + have_event = client->head != client->tail;
    + if (have_event) {
    + *event = client->buffer[client->tail++];
    + client->tail &= TSDEV_BUFFER_SIZE - 1;
    + }

    - put_device(&tsdev->dev);
    + spin_unlock_irq(&client->buffer_lock);

    - return 0;
    + return have_event;
    }

    static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count,
    @@ -225,9 +307,11 @@ static ssize_t tsdev_read(struct file *f
    {
    struct tsdev_client *client = file->private_data;
    struct tsdev *tsdev = client->tsdev;
    - int retval = 0;
    + struct ts_event event;
    + int retval;

    - if (client->head == client->tail && tsdev->exist && (file->f_flags & O_NONBLOCK))
    + if (client->head == client->tail && tsdev->exist &&
    + (file->f_flags & O_NONBLOCK))
    return -EAGAIN;

    retval = wait_event_interruptible(tsdev->wait,
    @@ -238,13 +322,14 @@ static ssize_t tsdev_read(struct file *f
    if (!tsdev->exist)
    return -ENODEV;

    - while (client->head != client->tail &&
    - retval + sizeof (struct ts_event) <= count) {
    - if (copy_to_user (buffer + retval, client->event + client->tail,
    - sizeof (struct ts_event)))
    + while (retval + sizeof(struct ts_event) <= count &&
    + tsdev_fetch_next_event(client, &event)) {
    +
    + if (copy_to_user(buffer + retval, &event,
    + sizeof(struct ts_event)))
    return -EFAULT;
    - client->tail = (client->tail + 1) & (TSDEV_BUFFER_SIZE - 1);
    - retval += sizeof (struct ts_event);
    +
    + retval += sizeof(struct ts_event);
    }

    return retval;
    @@ -261,14 +346,23 @@ static unsigned int tsdev_poll(struct fi
    (tsdev->exist ? 0 : (POLLHUP | POLLERR));
    }

    -static int tsdev_ioctl(struct inode *inode, struct file *file,
    - unsigned int cmd, unsigned long arg)
    +static long tsdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
    {
    struct tsdev_client *client = file->private_data;
    struct tsdev *tsdev = client->tsdev;
    int retval = 0;

    + retval = mutex_lock_interruptible(&tsdev->mutex);
    + if (retval)
    + return retval;
    +
    + if (!tsdev->exist) {
    + retval = -ENODEV;
    + goto out;
    + }
    +
    switch (cmd) {
    +
    case TS_GET_CAL:
    if (copy_to_user((void __user *)arg, &tsdev->cal,
    sizeof (struct ts_calibration)))
    @@ -277,7 +371,7 @@ static int tsdev_ioctl(struct inode *ino

    case TS_SET_CAL:
    if (copy_from_user(&tsdev->cal, (void __user *)arg,
    - sizeof (struct ts_calibration)))
    + sizeof(struct ts_calibration)))
    retval = -EFAULT;
    break;

    @@ -286,29 +380,79 @@ static int tsdev_ioctl(struct inode *ino
    break;
    }

    + out:
    + mutex_unlock(&tsdev->mutex);
    return retval;
    }

    static const struct file_operations tsdev_fops = {
    - .owner = THIS_MODULE,
    - .open = tsdev_open,
    - .release = tsdev_release,
    - .read = tsdev_read,
    - .poll = tsdev_poll,
    - .fasync = tsdev_fasync,
    - .ioctl = tsdev_ioctl,
    + .owner = THIS_MODULE,
    + .open = tsdev_open,
    + .release = tsdev_release,
    + .read = tsdev_read,
    + .poll = tsdev_poll,
    + .fasync = tsdev_fasync,
    + .unlocked_ioctl = tsdev_ioctl,
    };

    +static void tsdev_pass_event(struct tsdev *tsdev, struct tsdev_client *client,
    + int x, int y, int pressure, int millisecs)
    +{
    + struct ts_event *event;
    + int tmp;
    +
    + /* Interrupts are already disabled, just acquire the lock */
    + spin_lock(&client->buffer_lock);
    +
    + event = &client->buffer[client->head++];
    + client->head &= TSDEV_BUFFER_SIZE - 1;
    +
    + /* Calibration */
    + if (!client->raw) {
    + x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans;
    + y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans;
    + if (tsdev->cal.xyswap) {
    + tmp = x; x = y; y = tmp;
    + }
    + }
    +
    + event->millisecs = millisecs;
    + event->x = x;
    + event->y = y;
    + event->pressure = pressure;
    +
    + spin_unlock(&client->buffer_lock);
    +
    + kill_fasync(&client->fasync, SIGIO, POLL_IN);
    +}
    +
    +static void tsdev_distribute_event(struct tsdev *tsdev)
    +{
    + struct tsdev_client *client;
    + struct timeval time;
    + int millisecs;
    +
    + do_gettimeofday(&time);
    + millisecs = time.tv_usec / 1000;
    +
    + list_for_each_entry_rcu(client, &tsdev->client_list, node)
    + tsdev_pass_event(tsdev, client,
    + tsdev->x, tsdev->y,
    + tsdev->pressure, millisecs);
    +}
    +
    static void tsdev_event(struct input_handle *handle, unsigned int type,
    unsigned int code, int value)
    {
    struct tsdev *tsdev = handle->private;
    - struct tsdev_client *client;
    - struct timeval time;
    + struct input_dev *dev = handle->dev;
    + int wake_up_readers = 0;

    switch (type) {
    +
    case EV_ABS:
    switch (code) {
    +
    case ABS_X:
    tsdev->x = value;
    break;
    @@ -318,9 +462,9 @@ static void tsdev_event(struct input_han
    break;

    case ABS_PRESSURE:
    - if (value > handle->dev->absmax[ABS_PRESSURE])
    - value = handle->dev->absmax[ABS_PRESSURE];
    - value -= handle->dev->absmin[ABS_PRESSURE];
    + if (value > dev->absmax[ABS_PRESSURE])
    + value = dev->absmax[ABS_PRESSURE];
    + value -= dev->absmin[ABS_PRESSURE];
    if (value < 0)
    value = 0;
    tsdev->pressure = value;
    @@ -330,6 +474,7 @@ static void tsdev_event(struct input_han

    case EV_REL:
    switch (code) {
    +
    case REL_X:
    tsdev->x += value;
    if (tsdev->x < 0)
    @@ -351,6 +496,7 @@ static void tsdev_event(struct input_han
    case EV_KEY:
    if (code == BTN_TOUCH || code == BTN_MOUSE) {
    switch (value) {
    +
    case 0:
    tsdev->pressure = 0;
    break;
    @@ -362,49 +508,71 @@ static void tsdev_event(struct input_han
    }
    }
    break;
    +
    + case EV_SYN:
    + if (code == SYN_REPORT) {
    + tsdev_distribute_event(tsdev);
    + wake_up_readers = 1;
    + }
    + break;
    }

    - if (type != EV_SYN || code != SYN_REPORT)
    - return;
    + if (wake_up_readers)
    + wake_up_interruptible(&tsdev->wait);
    +}

    - list_for_each_entry(client, &tsdev->client_list, node) {
    - int x, y, tmp;
    +static int tsdev_install_chrdev(struct tsdev *tsdev)
    +{
    + tsdev_table[tsdev->minor] = tsdev;
    + return 0;
    +}

    - do_gettimeofday(&time);
    - client->event[client->head].millisecs = time.tv_usec / 1000;
    - client->event[client->head].pressure = tsdev->pressure;
    -
    - x = tsdev->x;
    - y = tsdev->y;
    -
    - /* Calibration */
    - if (!client->raw) {
    - x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans;
    - y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans;
    - if (tsdev->cal.xyswap) {
    - tmp = x; x = y; y = tmp;
    - }
    - }
    +static void tsdev_remove_chrdev(struct tsdev *tsdev)
    +{
    + mutex_lock(&tsdev_table_mutex);
    + tsdev_table[tsdev->minor] = NULL;
    + mutex_unlock(&tsdev_table_mutex);
    +}

    - client->event[client->head].x = x;
    - client->event[client->head].y = y;
    - client->head = (client->head + 1) & (TSDEV_BUFFER_SIZE - 1);
    - kill_fasync(&client->fasync, SIGIO, POLL_IN);
    - }
    - wake_up_interruptible(&tsdev->wait);
    +/*
    + * Mark device non-existant. This disables writes, ioctls and
    + * prevents new users from opening the device. Already posted
    + * blocking reads will stay, however new ones will fail.
    + */
    +static void tsdev_mark_dead(struct tsdev *tsdev)
    +{
    + mutex_lock(&tsdev->mutex);
    + tsdev->exist = 0;
    + mutex_unlock(&tsdev->mutex);
    +}
    +
    +static void tsdev_cleanup(struct tsdev *tsdev)
    +{
    + struct input_handle *handle = &tsdev->handle;
    +
    + tsdev_mark_dead(tsdev);
    + tsdev_hangup(tsdev);
    + tsdev_remove_chrdev(tsdev);
    +
    + /* tsdev is marked dead so noone else accesses tsdev->open */
    + if (tsdev->open)
    + input_close_device(handle);
    }

    static int tsdev_connect(struct input_handler *handler, struct input_dev *dev,
    const struct input_device_id *id)
    {
    struct tsdev *tsdev;
    - int minor, delta;
    + int delta;
    + int minor;
    int error;

    - for (minor = 0; minor < TSDEV_MINORS / 2 && tsdev_table[minor]; minor++);
    - if (minor >= TSDEV_MINORS / 2) {
    - printk(KERN_ERR
    - "tsdev: You have way too many touchscreens\n");
    + for (minor = 0; minor < TSDEV_MINORS / 2; minor++)
    + if (!tsdev_table[minor])
    + break;
    +
    + if (minor == TSDEV_MINORS) {
    + printk(KERN_ERR "tsdev: no more free tsdev devices\n");
    return -ENFILE;
    }

    @@ -413,15 +581,18 @@ static int tsdev_connect(struct input_ha
    return -ENOMEM;

    INIT_LIST_HEAD(&tsdev->client_list);
    + spin_lock_init(&tsdev->client_lock);
    + mutex_init(&tsdev->mutex);
    init_waitqueue_head(&tsdev->wait);

    + snprintf(tsdev->name, sizeof(tsdev->name), "ts%d", minor);
    tsdev->exist = 1;
    tsdev->minor = minor;
    +
    tsdev->handle.dev = dev;
    tsdev->handle.name = tsdev->name;
    tsdev->handle.handler = handler;
    tsdev->handle.private = tsdev;
    - snprintf(tsdev->name, sizeof(tsdev->name), "ts%d", minor);

    /* Precompute the rough calibration matrix */
    delta = dev->absmax [ABS_X] - dev->absmin [ABS_X] + 1;
    @@ -436,28 +607,31 @@ static int tsdev_connect(struct input_ha
    tsdev->cal.yscale = (yres << 8) / delta;
    tsdev->cal.ytrans = - ((dev->absmin [ABS_Y] * tsdev->cal.yscale) >> 8);

    - snprintf(tsdev->dev.bus_id, sizeof(tsdev->dev.bus_id),
    - "ts%d", minor);
    + strlcpy(tsdev->dev.bus_id, tsdev->name, sizeof(tsdev->dev.bus_id));
    + tsdev->dev.devt = MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor);
    tsdev->dev.class = &input_class;
    tsdev->dev.parent = &dev->dev;
    - tsdev->dev.devt = MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor);
    tsdev->dev.release = tsdev_free;
    device_initialize(&tsdev->dev);

    - tsdev_table[minor] = tsdev;
    -
    - error = device_add(&tsdev->dev);
    + error = input_register_handle(&tsdev->handle);
    if (error)
    goto err_free_tsdev;

    - error = input_register_handle(&tsdev->handle);
    + error = tsdev_install_chrdev(tsdev);
    if (error)
    - goto err_delete_tsdev;
    + goto err_unregister_handle;
    +
    + error = device_add(&tsdev->dev);
    + if (error)
    + goto err_cleanup_tsdev;

    return 0;

    - err_delete_tsdev:
    - device_del(&tsdev->dev);
    + err_cleanup_tsdev:
    + tsdev_cleanup(tsdev);
    + err_unregister_handle:
    + input_unregister_handle(&tsdev->handle);
    err_free_tsdev:
    put_device(&tsdev->dev);
    return error;
    @@ -466,20 +640,10 @@ static int tsdev_connect(struct input_ha
    static void tsdev_disconnect(struct input_handle *handle)
    {
    struct tsdev *tsdev = handle->private;
    - struct tsdev_client *client;

    - input_unregister_handle(handle);
    device_del(&tsdev->dev);
    -
    - tsdev->exist = 0;
    -
    - if (tsdev->open) {
    - input_close_device(handle);
    - list_for_each_entry(client, &tsdev->client_list, node)
    - kill_fasync(&client->fasync, SIGIO, POLL_HUP);
    - wake_up_interruptible(&tsdev->wait);
    - }
    -
    + tsdev_cleanup(tsdev);
    + input_unregister_handle(handle);
    put_device(&tsdev->dev);
    }

    @@ -510,13 +674,13 @@ static const struct input_device_id tsde
    MODULE_DEVICE_TABLE(input, tsdev_ids);

    static struct input_handler tsdev_handler = {
    - .event = tsdev_event,
    - .connect = tsdev_connect,
    - .disconnect = tsdev_disconnect,
    - .fops = &tsdev_fops,
    - .minor = TSDEV_MINOR_BASE,
    - .name = "tsdev",
    - .id_table = tsdev_ids,
    + .event = tsdev_event,
    + .connect = tsdev_connect,
    + .disconnect = tsdev_disconnect,
    + .fops = &tsdev_fops,
    + .minor = TSDEV_MINOR_BASE,
    + .name = "tsdev",
    + .id_table = tsdev_ids,
    };

    static int __init tsdev_init(void)

    --
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  12. [patch 59/73] knfsd: Allow NFSv2/3 WRITE calls to succeed when krb5i etc is used.


    2.6.23-stable review patch. If anyone has any objections, please let us know.
    ------------------
    From: NeilBrown

    patch ba67a39efde8312e386c6f603054f8945433d91f in mainline.

    When RPCSEC/GSS and krb5i is used, requests are padded, typically to a multiple
    of 8 bytes. This can make the request look slightly longer than it
    really is.

    As of

    f34b95689d2ce001c "The NFSv2/NFSv3 server does not handle zero
    length WRITE request correctly",

    the xdr decode routines for NFSv2 and NFSv3 reject requests that aren't
    the right length, so krb5i (for example) WRITE requests can get lost.

    This patch relaxes the appropriate test and enhances the related comment.

    Signed-off-by: Neil Brown
    Signed-off-by: J. Bruce Fields
    Cc: Peter Staubach
    Signed-off-by: Linus Torvalds
    Signed-off-by: Greg Kroah-Hartman

    ---
    fs/nfsd/nfs3xdr.c | 5 ++++-
    fs/nfsd/nfsxdr.c | 5 ++++-
    2 files changed, 8 insertions(+), 2 deletions(-)

    --- a/fs/nfsd/nfs3xdr.c
    +++ b/fs/nfsd/nfs3xdr.c
    @@ -396,8 +396,11 @@ nfs3svc_decode_writeargs(struct svc_rqst
    * Round the length of the data which was specified up to
    * the next multiple of XDR units and then compare that
    * against the length which was actually received.
    + * Note that when RPCSEC/GSS (for example) is used, the
    + * data buffer can be padded so dlen might be larger
    + * than required. It must never be smaller.
    */
    - if (dlen != XDR_QUADLEN(len)*4)
    + if (dlen < XDR_QUADLEN(len)*4)
    return 0;

    if (args->count > max_blocksize) {
    --- a/fs/nfsd/nfsxdr.c
    +++ b/fs/nfsd/nfsxdr.c
    @@ -313,8 +313,11 @@ nfssvc_decode_writeargs(struct svc_rqst
    * Round the length of the data which was specified up to
    * the next multiple of XDR units and then compare that
    * against the length which was actually received.
    + * Note that when RPCSEC/GSS (for example) is used, the
    + * data buffer can be padded so dlen might be larger
    + * than required. It must never be smaller.
    */
    - if (dlen != XDR_QUADLEN(len)*4)
    + if (dlen < XDR_QUADLEN(len)*4)
    return 0;

    rqstp->rq_vec[0].iov_base = (void*)p;

    --
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  13. [patch 62/73] ia64: Fix unaligned handler for floating point instructions with base update

    2.6.23-stable review patch. If anyone has any objections, please let us know.
    ------------------
    From: Luck, Tony

    commit 1a499150e4ec1299232e24389f648d059ce5617a in mainline.

    [IA64] Fix unaligned handler for floating point instructions with base update

    The compiler team did the hard work for this distilling a problem in
    large fortran application which showed up when applied to a 290MB input
    data set down to this instruction:

    ldfd f34=[r17],-8

    Which they noticed incremented r17 by 0x10 rather than decrementing it
    by 8 when the value in r17 caused an unaligned data fault. I tracked
    it down to some bad instruction decoding in unaligned.c. The code
    assumes that the 'x' bit can determine whether the instruction is
    an "ldf" or "ldfp" ... which it is for opcode=6 (see table 4-29 on
    page 3:302 of the SDM). But for opcode=7 the 'x' bit is irrelevent,
    all variants are "ldf" instructions (see table 4-36 on page 3:306).

    Note also that interpreting the instruction as "ldfp" means that the
    "paired" floating point register (f35 in the example here) will also
    be corrupted.

    Signed-off-by: Tony Luck
    Signed-off-by: Greg Kroah-Hartman

    ---
    arch/ia64/kernel/unaligned.c | 11 +++++++----
    1 file changed, 7 insertions(+), 4 deletions(-)

    --- a/arch/ia64/kernel/unaligned.c
    +++ b/arch/ia64/kernel/unaligned.c
    @@ -1487,16 +1487,19 @@ ia64_handle_unaligned (unsigned long ifa
    case LDFA_OP:
    case LDFCCLR_OP:
    case LDFCNC_OP:
    - case LDF_IMM_OP:
    - case LDFA_IMM_OP:
    - case LDFCCLR_IMM_OP:
    - case LDFCNC_IMM_OP:
    if (u.insn.x)
    ret = emulate_load_floatpair(ifa, u.insn, regs);
    else
    ret = emulate_load_float(ifa, u.insn, regs);
    break;

    + case LDF_IMM_OP:
    + case LDFA_IMM_OP:
    + case LDFCCLR_IMM_OP:
    + case LDFCNC_IMM_OP:
    + ret = emulate_load_float(ifa, u.insn, regs);
    + break;
    +
    case STF_OP:
    case STF_IMM_OP:
    ret = emulate_store_float(ifa, u.insn, regs);

    --
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  14. [patch 55/73] m68k: Export cachectl.h

    2.6.23-stable review patch. If anyone has any objections, please let us know.
    ------------------
    From: Matthew Wilcox

    patch e92042e5c009d84ba741ec4a978a13f260e6ee24 in mainline.

    m68k: Export cachectl.h

    libffi in GCC 4.2 needs cachectl.h to do its cache flushing. But we
    don't currently export it. I believe this patch should do the trick.

    Signed-off-by: Matthew Wilcox
    Cc: maximilian attems
    Signed-off-by: Geert Uytterhoeven
    Signed-off-by: Linus Torvalds
    Signed-off-by: Greg Kroah-Hartman

    ---
    include/asm-m68k/Kbuild | 1 +
    1 file changed, 1 insertion(+)

    --- a/include/asm-m68k/Kbuild
    +++ b/include/asm-m68k/Kbuild
    @@ -1 +1,2 @@
    include include/asm-generic/Kbuild.asm
    +header-y += cachectl.h

    --
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  15. [patch 58/73] md: fix data corruption when a degraded raid5 array is reshaped

    2.6.23-stable review patch. If anyone has any objections, please let us know.
    ------------------
    From: Dan Williams

    patch 0f94e87cdeaaac9f0f9a28a5dd2a5070b87cd3e8 in mainline.

    We currently do not wait for the block from the missing device to be
    computed from parity before copying data to the new stripe layout.

    The change in the raid6 code is not techincally needed as we don't delay
    data block recovery in the same way for raid6 yet. But making the change
    now is safer long-term.

    This bug exists in 2.6.23 and 2.6.24-rc

    Signed-off-by: Dan Williams
    Acked-by: Neil Brown
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds
    Signed-off-by: Greg Kroah-Hartman

    ---
    drivers/md/raid5.c | 6 ++++--
    1 file changed, 4 insertions(+), 2 deletions(-)

    --- a/drivers/md/raid5.c
    +++ b/drivers/md/raid5.c
    @@ -2875,7 +2875,8 @@ static void handle_stripe5(struct stripe
    md_done_sync(conf->mddev, STRIPE_SECTORS, 1);
    }

    - if (s.expanding && s.locked == 0)
    + if (s.expanding && s.locked == 0 &&
    + !test_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.pending))
    handle_stripe_expansion(conf, sh, NULL);

    if (sh->ops.count)
    @@ -3077,7 +3078,8 @@ static void handle_stripe6(struct stripe
    md_done_sync(conf->mddev, STRIPE_SECTORS, 1);
    }

    - if (s.expanding && s.locked == 0)
    + if (s.expanding && s.locked == 0 &&
    + !test_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.pending))
    handle_stripe_expansion(conf, sh, &r6s);

    spin_unlock(&sh->lock);

    --
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  16. [patch 68/73] Netfilter: bridge-netfilter: fix net_device refcnt leaks


    2.6.23-stable review patch. If anyone has any objections, please let us know.
    ------------------
    From: Patrick McHardy

    [NETFILTER]: bridge-netfilter: fix net_device refcnt leaks

    Upstream commit 2dc2f207fb251666d2396fe1a69272b307ecc333

    When packets are flood-forwarded to multiple output devices, the
    bridge-netfilter code reuses skb->nf_bridge for each clone to store
    the bridge port. When queueing packets using NFQUEUE netfilter takes
    a reference to skb->nf_bridge->physoutdev, which is overwritten
    when the packet is forwarded to the second port. This causes
    refcount unterflows for the first device and refcount leaks for all
    others. Additionally this provides incorrect data to the iptables
    physdev match.

    Unshare skb->nf_bridge by copying it if it is shared before assigning
    the physoutdev device.

    Reported, tested and based on initial patch by
    Jan Christoph Nordholz .

    Signed-off-by: Patrick McHardy
    Signed-off-by: David S. Miller
    Signed-off-by: Greg Kroah-Hartman

    ---
    net/bridge/br_netfilter.c | 27 +++++++++++++++++++++++++++
    1 file changed, 27 insertions(+)

    --- a/net/bridge/br_netfilter.c
    +++ b/net/bridge/br_netfilter.c
    @@ -142,6 +142,23 @@ static inline struct nf_bridge_info *nf_
    return skb->nf_bridge;
    }

    +static inline struct nf_bridge_info *nf_bridge_unshare(struct sk_buff *skb)
    +{
    + struct nf_bridge_info *nf_bridge = skb->nf_bridge;
    +
    + if (atomic_read(&nf_bridge->use) > 1) {
    + struct nf_bridge_info *tmp = nf_bridge_alloc(skb);
    +
    + if (tmp) {
    + memcpy(tmp, nf_bridge, sizeof(struct nf_bridge_info));
    + atomic_set(&tmp->use, 1);
    + nf_bridge_put(nf_bridge);
    + }
    + nf_bridge = tmp;
    + }
    + return nf_bridge;
    +}
    +
    static inline void nf_bridge_push_encap_header(struct sk_buff *skb)
    {
    unsigned int len = nf_bridge_encap_header_len(skb);
    @@ -644,6 +661,11 @@ static unsigned int br_nf_forward_ip(uns
    if (!skb->nf_bridge)
    return NF_ACCEPT;

    + /* Need exclusive nf_bridge_info since we might have multiple
    + * different physoutdevs. */
    + if (!nf_bridge_unshare(skb))
    + return NF_DROP;
    +
    parent = bridge_parent(out);
    if (!parent)
    return NF_DROP;
    @@ -727,6 +749,11 @@ static unsigned int br_nf_local_out(unsi
    if (!skb->nf_bridge)
    return NF_ACCEPT;

    + /* Need exclusive nf_bridge_info since we might have multiple
    + * different physoutdevs. */
    + if (!nf_bridge_unshare(skb))
    + return NF_DROP;
    +
    nf_bridge = skb->nf_bridge;
    if (!(nf_bridge->mask & BRNF_BRIDGED_DNAT))
    return NF_ACCEPT;

    --
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  17. [patch 65/73] libata: port and host should be stopped before hardware resources are released

    2.6.23-stable review patch. If anyone has any objections, please let us know.
    ------------------
    From: Tejun Heo

    This is backport of 32ebbc0c0d5d18c0135b55d1eb0029f48c54aff0 and fixes
    oops on driver module unload.

    Port / host stop calls used to be made from ata_host_release() which
    is called after all hardware resources acquired after host allocation
    are released. This is wrong as port and host stop routines often
    access the hardware.

    Add separate devres for port / host stop which is invoked right after
    IRQ is released but with all other hardware resources intact. The
    devres is added iff ->host_stop and/or ->port_stop exist.

    This problem has been spotted by Mark Lord.

    Signed-off-by: Tejun Heo
    Cc: Mark Lord
    Signed-off-by: Jeff Garzik
    Signed-off-by: Greg Kroah-Hartman

    ---
    drivers/ata/libata-core.c | 52 ++++++++++++++++++++++++++++++++++------------
    1 file changed, 39 insertions(+), 13 deletions(-)

    --- a/drivers/ata/libata-core.c
    +++ b/drivers/ata/libata-core.c
    @@ -6121,19 +6121,6 @@ static void ata_host_release(struct devi
    if (!ap)
    continue;

    - if ((host->flags & ATA_HOST_STARTED) && ap->ops->port_stop)
    - ap->ops->port_stop(ap);
    - }
    -
    - if ((host->flags & ATA_HOST_STARTED) && host->ops->host_stop)
    - host->ops->host_stop(host);
    -
    - for (i = 0; i < host->n_ports; i++) {
    - struct ata_port *ap = host->ports[i];
    -
    - if (!ap)
    - continue;
    -
    if (ap->scsi_host)
    scsi_host_put(ap->scsi_host);

    @@ -6258,6 +6245,24 @@ struct ata_host *ata_host_alloc_pinfo(st
    return host;
    }

    +static void ata_host_stop(struct device *gendev, void *res)
    +{
    + struct ata_host *host = dev_get_drvdata(gendev);
    + int i;
    +
    + WARN_ON(!(host->flags & ATA_HOST_STARTED));
    +
    + for (i = 0; i < host->n_ports; i++) {
    + struct ata_port *ap = host->ports[i];
    +
    + if (ap->ops->port_stop)
    + ap->ops->port_stop(ap);
    + }
    +
    + if (host->ops->host_stop)
    + host->ops->host_stop(host);
    +}
    +
    /**
    * ata_host_start - start and freeze ports of an ATA host
    * @host: ATA host to start ports for
    @@ -6276,6 +6281,8 @@ struct ata_host *ata_host_alloc_pinfo(st
    */
    int ata_host_start(struct ata_host *host)
    {
    + int have_stop = 0;
    + void *start_dr = NULL;
    int i, rc;

    if (host->flags & ATA_HOST_STARTED)
    @@ -6287,6 +6294,22 @@ int ata_host_start(struct ata_host *host
    if (!host->ops && !ata_port_is_dummy(ap))
    host->ops = ap->ops;

    + if (ap->ops->port_stop)
    + have_stop = 1;
    + }
    +
    + if (host->ops->host_stop)
    + have_stop = 1;
    +
    + if (have_stop) {
    + start_dr = devres_alloc(ata_host_stop, 0, GFP_KERNEL);
    + if (!start_dr)
    + return -ENOMEM;
    + }
    +
    + for (i = 0; i < host->n_ports; i++) {
    + struct ata_port *ap = host->ports[i];
    +
    if (ap->ops->port_start) {
    rc = ap->ops->port_start(ap);
    if (rc) {
    @@ -6299,6 +6322,8 @@ int ata_host_start(struct ata_host *host
    ata_eh_freeze_port(ap);
    }

    + if (start_dr)
    + devres_add(host->dev, start_dr);
    host->flags |= ATA_HOST_STARTED;
    return 0;

    @@ -6309,6 +6334,7 @@ int ata_host_start(struct ata_host *host
    if (ap->ops->port_stop)
    ap->ops->port_stop(ap);
    }
    + devres_free(start_dr);
    return rc;
    }


    --
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  18. [patch 51/73] Input: joydev - implement proper locking

    2.6.23-stable review patch. If anyone has any objections, please let us know.
    ------------------
    From: Dmitry Torokhov

    patch b126207ccdfe492fbc339c18d4898b1b5353fc6b in mainline.

    Signed-off-by: Dmitry Torokhov
    Cc: Al Viro
    Signed-off-by: Greg Kroah-Hartman

    ---
    drivers/input/joydev.c | 745 ++++++++++++++++++++++++++++++++-----------------
    1 file changed, 493 insertions(+), 252 deletions(-)

    --- a/drivers/input/joydev.c
    +++ b/drivers/input/joydev.c
    @@ -43,6 +43,8 @@ struct joydev {
    struct input_handle handle;
    wait_queue_head_t wait;
    struct list_head client_list;
    + spinlock_t client_lock; /* protects client_list */
    + struct mutex mutex;
    struct device dev;

    struct js_corr corr[ABS_MAX + 1];
    @@ -61,31 +63,61 @@ struct joydev_client {
    int head;
    int tail;
    int startup;
    + spinlock_t buffer_lock; /* protects access to buffer, head and tail */
    struct fasync_struct *fasync;
    struct joydev *joydev;
    struct list_head node;
    };

    static struct joydev *joydev_table[JOYDEV_MINORS];
    +static DEFINE_MUTEX(joydev_table_mutex);

    static int joydev_correct(int value, struct js_corr *corr)
    {
    switch (corr->type) {
    - case JS_CORR_NONE:
    - break;
    - case JS_CORR_BROKEN:
    - value = value > corr->coef[0] ? (value < corr->coef[1] ? 0 :
    - ((corr->coef[3] * (value - corr->coef[1])) >> 14)) :
    - ((corr->coef[2] * (value - corr->coef[0])) >> 14);
    - break;
    - default:
    - return 0;
    +
    + case JS_CORR_NONE:
    + break;
    +
    + case JS_CORR_BROKEN:
    + value = value > corr->coef[0] ? (value < corr->coef[1] ? 0 :
    + ((corr->coef[3] * (value - corr->coef[1])) >> 14)) :
    + ((corr->coef[2] * (value - corr->coef[0])) >> 14);
    + break;
    +
    + default:
    + return 0;
    }

    return value < -32767 ? -32767 : (value > 32767 ? 32767 : value);
    }

    -static void joydev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
    +static void joydev_pass_event(struct joydev_client *client,
    + struct js_event *event)
    +{
    + struct joydev *joydev = client->joydev;
    +
    + /*
    + * IRQs already disabled, just acquire the lock
    + */
    + spin_lock(&client->buffer_lock);
    +
    + client->buffer[client->head] = *event;
    +
    + if (client->startup == joydev->nabs + joydev->nkey) {
    + client->head++;
    + client->head &= JOYDEV_BUFFER_SIZE - 1;
    + if (client->tail == client->head)
    + client->startup = 0;
    + }
    +
    + spin_unlock(&client->buffer_lock);
    +
    + kill_fasync(&client->fasync, SIGIO, POLL_IN);
    +}
    +
    +static void joydev_event(struct input_handle *handle,
    + unsigned int type, unsigned int code, int value)
    {
    struct joydev *joydev = handle->private;
    struct joydev_client *client;
    @@ -93,39 +125,32 @@ static void joydev_event(struct input_ha

    switch (type) {

    - case EV_KEY:
    - if (code < BTN_MISC || value == 2)
    - return;
    - event.type = JS_EVENT_BUTTON;
    - event.number = joydev->keymap[code - BTN_MISC];
    - event.value = value;
    - break;
    -
    - case EV_ABS:
    - event.type = JS_EVENT_AXIS;
    - event.number = joydev->absmap[code];
    - event.value = joydev_correct(value, joydev->corr + event.number);
    - if (event.value == joydev->abs[event.number])
    - return;
    - joydev->abs[event.number] = event.value;
    - break;
    + case EV_KEY:
    + if (code < BTN_MISC || value == 2)
    + return;
    + event.type = JS_EVENT_BUTTON;
    + event.number = joydev->keymap[code - BTN_MISC];
    + event.value = value;
    + break;

    - default:
    + case EV_ABS:
    + event.type = JS_EVENT_AXIS;
    + event.number = joydev->absmap[code];
    + event.value = joydev_correct(value,
    + &joydev->corr[event.number]);
    + if (event.value == joydev->abs[event.number])
    return;
    + joydev->abs[event.number] = event.value;
    + break;
    +
    + default:
    + return;
    }

    event.time = jiffies_to_msecs(jiffies);

    - list_for_each_entry(client, &joydev->client_list, node) {
    -
    - memcpy(client->buffer + client->head, &event, sizeof(struct js_event));
    -
    - if (client->startup == joydev->nabs + joydev->nkey)
    - if (client->tail == (client->head = (client->head + 1) & (JOYDEV_BUFFER_SIZE - 1)))
    - client->startup = 0;
    -
    - kill_fasync(&client->fasync, SIGIO, POLL_IN);
    - }
    + list_for_each_entry_rcu(client, &joydev->client_list, node)
    + joydev_pass_event(client, &event);

    wake_up_interruptible(&joydev->wait);
    }
    @@ -144,23 +169,85 @@ static void joydev_free(struct device *d
    {
    struct joydev *joydev = container_of(dev, struct joydev, dev);

    - joydev_table[joydev->minor] = NULL;
    kfree(joydev);
    }

    +static void joydev_attach_client(struct joydev *joydev,
    + struct joydev_client *client)
    +{
    + spin_lock(&joydev->client_lock);
    + list_add_tail_rcu(&client->node, &joydev->client_list);
    + spin_unlock(&joydev->client_lock);
    + /*
    + * We don't use synchronize_rcu() here because read-side
    + * critical section is protected by a spinlock (dev->event_lock)
    + * instead of rcu_read_lock().
    + */
    + synchronize_sched();
    +}
    +
    +static void joydev_detach_client(struct joydev *joydev,
    + struct joydev_client *client)
    +{
    + spin_lock(&joydev->client_lock);
    + list_del_rcu(&client->node);
    + spin_unlock(&joydev->client_lock);
    + synchronize_sched();
    +}
    +
    +static int joydev_open_device(struct joydev *joydev)
    +{
    + int retval;
    +
    + retval = mutex_lock_interruptible(&joydev->mutex);
    + if (retval)
    + return retval;
    +
    + if (!joydev->exist)
    + retval = -ENODEV;
    + else if (!joydev->open++)
    + retval = input_open_device(&joydev->handle);
    +
    + mutex_unlock(&joydev->mutex);
    + return retval;
    +}
    +
    +static void joydev_close_device(struct joydev *joydev)
    +{
    + mutex_lock(&joydev->mutex);
    +
    + if (joydev->exist && !--joydev->open)
    + input_close_device(&joydev->handle);
    +
    + mutex_unlock(&joydev->mutex);
    +}
    +
    +/*
    + * Wake up users waiting for IO so they can disconnect from
    + * dead device.
    + */
    +static void joydev_hangup(struct joydev *joydev)
    +{
    + struct joydev_client *client;
    +
    + spin_lock(&joydev->client_lock);
    + list_for_each_entry(client, &joydev->client_list, node)
    + kill_fasync(&client->fasync, SIGIO, POLL_HUP);
    + spin_unlock(&joydev->client_lock);
    +
    + wake_up_interruptible(&joydev->wait);
    +}
    +
    static int joydev_release(struct inode *inode, struct file *file)
    {
    struct joydev_client *client = file->private_data;
    struct joydev *joydev = client->joydev;

    joydev_fasync(-1, file, 0);
    -
    - list_del(&client->node);
    + joydev_detach_client(joydev, client);
    kfree(client);

    - if (!--joydev->open && joydev->exist)
    - input_close_device(&joydev->handle);
    -
    + joydev_close_device(joydev);
    put_device(&joydev->dev);

    return 0;
    @@ -176,11 +263,16 @@ static int joydev_open(struct inode *ino
    if (i >= JOYDEV_MINORS)
    return -ENODEV;

    + error = mutex_lock_interruptible(&joydev_table_mutex);
    + if (error)
    + return error;
    joydev = joydev_table[i];
    - if (!joydev || !joydev->exist)
    - return -ENODEV;
    + if (joydev)
    + get_device(&joydev->dev);
    + mutex_unlock(&joydev_table_mutex);

    - get_device(&joydev->dev);
    + if (!joydev)
    + return -ENODEV;

    client = kzalloc(sizeof(struct joydev_client), GFP_KERNEL);
    if (!client) {
    @@ -188,37 +280,129 @@ static int joydev_open(struct inode *ino
    goto err_put_joydev;
    }

    + spin_lock_init(&client->buffer_lock);
    client->joydev = joydev;
    - list_add_tail(&client->node, &joydev->client_list);
    + joydev_attach_client(joydev, client);

    - if (!joydev->open++ && joydev->exist) {
    - error = input_open_device(&joydev->handle);
    - if (error)
    - goto err_free_client;
    - }
    + error = joydev_open_device(joydev);
    + if (error)
    + goto err_free_client;

    file->private_data = client;
    return 0;

    err_free_client:
    - list_del(&client->node);
    + joydev_detach_client(joydev, client);
    kfree(client);
    err_put_joydev:
    put_device(&joydev->dev);
    return error;
    }

    -static ssize_t joydev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
    +static int joydev_generate_startup_event(struct joydev_client *client,
    + struct input_dev *input,
    + struct js_event *event)
    {
    - return -EINVAL;
    + struct joydev *joydev = client->joydev;
    + int have_event;
    +
    + spin_lock_irq(&client->buffer_lock);
    +
    + have_event = client->startup < joydev->nabs + joydev->nkey;
    +
    + if (have_event) {
    +
    + event->time = jiffies_to_msecs(jiffies);
    + if (client->startup < joydev->nkey) {
    + event->type = JS_EVENT_BUTTON | JS_EVENT_INIT;
    + event->number = client->startup;
    + event->value = !!test_bit(joydev->keypam[event->number],
    + input->key);
    + } else {
    + event->type = JS_EVENT_AXIS | JS_EVENT_INIT;
    + event->number = client->startup - joydev->nkey;
    + event->value = joydev->abs[event->number];
    + }
    + client->startup++;
    + }
    +
    + spin_unlock_irq(&client->buffer_lock);
    +
    + return have_event;
    +}
    +
    +static int joydev_fetch_next_event(struct joydev_client *client,
    + struct js_event *event)
    +{
    + int have_event;
    +
    + spin_lock_irq(&client->buffer_lock);
    +
    + have_event = client->head != client->tail;
    + if (have_event) {
    + *event = client->buffer[client->tail++];
    + client->tail &= JOYDEV_BUFFER_SIZE - 1;
    + }
    +
    + spin_unlock_irq(&client->buffer_lock);
    +
    + return have_event;
    }

    -static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
    +/*
    + * Old joystick interface
    + */
    +static ssize_t joydev_0x_read(struct joydev_client *client,
    + struct input_dev *input,
    + char __user *buf)
    +{
    + struct joydev *joydev = client->joydev;
    + struct JS_DATA_TYPE data;
    + int i;
    +
    + spin_lock_irq(&input->event_lock);
    +
    + /*
    + * Get device state
    + */
    + for (data.buttons = i = 0; i < 32 && i < joydev->nkey; i++)
    + data.buttons |=
    + test_bit(joydev->keypam[i], input->key) ? (1 << i) : 0;
    + data.x = (joydev->abs[0] / 256 + 128) >> joydev->glue.JS_CORR.x;
    + data.y = (joydev->abs[1] / 256 + 128) >> joydev->glue.JS_CORR.y;
    +
    + /*
    + * Reset reader's event queue
    + */
    + spin_lock(&client->buffer_lock);
    + client->startup = 0;
    + client->tail = client->head;
    + spin_unlock(&client->buffer_lock);
    +
    + spin_unlock_irq(&input->event_lock);
    +
    + if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE)))
    + return -EFAULT;
    +
    + return sizeof(struct JS_DATA_TYPE);
    +}
    +
    +static inline int joydev_data_pending(struct joydev_client *client)
    +{
    + struct joydev *joydev = client->joydev;
    +
    + return client->startup < joydev->nabs + joydev->nkey ||
    + client->head != client->tail;
    +}
    +
    +static ssize_t joydev_read(struct file *file, char __user *buf,
    + size_t count, loff_t *ppos)
    {
    struct joydev_client *client = file->private_data;
    struct joydev *joydev = client->joydev;
    struct input_dev *input = joydev->handle.dev;
    - int retval = 0;
    + struct js_event event;
    + int retval;

    if (!joydev->exist)
    return -ENODEV;
    @@ -226,68 +410,35 @@ static ssize_t joydev_read(struct file *
    if (count < sizeof(struct js_event))
    return -EINVAL;

    - if (count == sizeof(struct JS_DATA_TYPE)) {
    -
    - struct JS_DATA_TYPE data;
    - int i;
    -
    - for (data.buttons = i = 0; i < 32 && i < joydev->nkey; i++)
    - data.buttons |= test_bit(joydev->keypam[i], input->key) ? (1 << i) : 0;
    - data.x = (joydev->abs[0] / 256 + 128) >> joydev->glue.JS_CORR.x;
    - data.y = (joydev->abs[1] / 256 + 128) >> joydev->glue.JS_CORR.y;
    -
    - if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE)))
    - return -EFAULT;
    -
    - client->startup = 0;
    - client->tail = client->head;
    -
    - return sizeof(struct JS_DATA_TYPE);
    - }
    + if (count == sizeof(struct JS_DATA_TYPE))
    + return joydev_0x_read(client, input, buf);

    - if (client->startup == joydev->nabs + joydev->nkey &&
    - client->head == client->tail && (file->f_flags & O_NONBLOCK))
    + if (!joydev_data_pending(client) && (file->f_flags & O_NONBLOCK))
    return -EAGAIN;

    retval = wait_event_interruptible(joydev->wait,
    - !joydev->exist ||
    - client->startup < joydev->nabs + joydev->nkey ||
    - client->head != client->tail);
    + !joydev->exist || joydev_data_pending(client));
    if (retval)
    return retval;

    if (!joydev->exist)
    return -ENODEV;

    - while (client->startup < joydev->nabs + joydev->nkey && retval + sizeof(struct js_event) <= count) {
    -
    - struct js_event event;
    -
    - event.time = jiffies_to_msecs(jiffies);
    -
    - if (client->startup < joydev->nkey) {
    - event.type = JS_EVENT_BUTTON | JS_EVENT_INIT;
    - event.number = client->startup;
    - event.value = !!test_bit(joydev->keypam[event.number], input->key);
    - } else {
    - event.type = JS_EVENT_AXIS | JS_EVENT_INIT;
    - event.number = client->startup - joydev->nkey;
    - event.value = joydev->abs[event.number];
    - }
    + while (retval + sizeof(struct js_event) <= count &&
    + joydev_generate_startup_event(client, input, &event)) {

    if (copy_to_user(buf + retval, &event, sizeof(struct js_event)))
    return -EFAULT;

    - client->startup++;
    retval += sizeof(struct js_event);
    }

    - while (client->head != client->tail && retval + sizeof(struct js_event) <= count) {
    + while (retval + sizeof(struct js_event) <= count &&
    + joydev_fetch_next_event(client, &event)) {

    - if (copy_to_user(buf + retval, client->buffer + client->tail, sizeof(struct js_event)))
    + if (copy_to_user(buf + retval, &event, sizeof(struct js_event)))
    return -EFAULT;

    - client->tail = (client->tail + 1) & (JOYDEV_BUFFER_SIZE - 1);
    retval += sizeof(struct js_event);
    }

    @@ -301,126 +452,144 @@ static unsigned int joydev_poll(struct f
    struct joydev *joydev = client->joydev;

    poll_wait(file, &joydev->wait, wait);
    - return ((client->head != client->tail || client->startup < joydev->nabs + joydev->nkey) ?
    - (POLLIN | POLLRDNORM) : 0) | (joydev->exist ? 0 : (POLLHUP | POLLERR));
    + return (joydev_data_pending(client) ? (POLLIN | POLLRDNORM) : 0) |
    + (joydev->exist ? 0 : (POLLHUP | POLLERR));
    }

    -static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __user *argp)
    +static int joydev_ioctl_common(struct joydev *joydev,
    + unsigned int cmd, void __user *argp)
    {
    struct input_dev *dev = joydev->handle.dev;
    int i, j;

    switch (cmd) {

    - case JS_SET_CAL:
    - return copy_from_user(&joydev->glue.JS_CORR, argp,
    + case JS_SET_CAL:
    + return copy_from_user(&joydev->glue.JS_CORR, argp,
    sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0;

    - case JS_GET_CAL:
    - return copy_to_user(argp, &joydev->glue.JS_CORR,
    + case JS_GET_CAL:
    + return copy_to_user(argp, &joydev->glue.JS_CORR,
    sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0;

    - case JS_SET_TIMEOUT:
    - return get_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
    + case JS_SET_TIMEOUT:
    + return get_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);

    - case JS_GET_TIMEOUT:
    - return put_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
    + case JS_GET_TIMEOUT:
    + return put_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);

    - case JSIOCGVERSION:
    - return put_user(JS_VERSION, (__u32 __user *) argp);
    + case JSIOCGVERSION:
    + return put_user(JS_VERSION, (__u32 __user *) argp);

    - case JSIOCGAXES:
    - return put_user(joydev->nabs, (__u8 __user *) argp);
    -
    - case JSIOCGBUTTONS:
    - return put_user(joydev->nkey, (__u8 __user *) argp);
    -
    - case JSIOCSCORR:
    - if (copy_from_user(joydev->corr, argp,
    - sizeof(joydev->corr[0]) * joydev->nabs))
    - return -EFAULT;
    - for (i = 0; i < joydev->nabs; i++) {
    - j = joydev->abspam[i];
    - joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i);
    - }
    - return 0;
    -
    - case JSIOCGCORR:
    - return copy_to_user(argp, joydev->corr,
    - sizeof(joydev->corr[0]) * joydev->nabs) ? -EFAULT : 0;
    + case JSIOCGAXES:
    + return put_user(joydev->nabs, (__u8 __user *) argp);
    +
    + case JSIOCGBUTTONS:
    + return put_user(joydev->nkey, (__u8 __user *) argp);
    +
    + case JSIOCSCORR:
    + if (copy_from_user(joydev->corr, argp,
    + sizeof(joydev->corr[0]) * joydev->nabs))
    + return -EFAULT;
    +
    + for (i = 0; i < joydev->nabs; i++) {
    + j = joydev->abspam[i];
    + joydev->abs[i] = joydev_correct(dev->abs[j],
    + &joydev->corr[i]);
    + }
    + return 0;

    - case JSIOCSAXMAP:
    - if (copy_from_user(joydev->abspam, argp, sizeof(__u8) * (ABS_MAX + 1)))
    - return -EFAULT;
    - for (i = 0; i < joydev->nabs; i++) {
    - if (joydev->abspam[i] > ABS_MAX)
    - return -EINVAL;
    - joydev->absmap[joydev->abspam[i]] = i;
    - }
    - return 0;
    -
    - case JSIOCGAXMAP:
    - return copy_to_user(argp, joydev->abspam,
    - sizeof(__u8) * (ABS_MAX + 1)) ? -EFAULT : 0;
    + case JSIOCGCORR:
    + return copy_to_user(argp, joydev->corr,
    + sizeof(joydev->corr[0]) * joydev->nabs) ? -EFAULT : 0;
    +
    + case JSIOCSAXMAP:
    + if (copy_from_user(joydev->abspam, argp,
    + sizeof(__u8) * (ABS_MAX + 1)))
    + return -EFAULT;
    +
    + for (i = 0; i < joydev->nabs; i++) {
    + if (joydev->abspam[i] > ABS_MAX)
    + return -EINVAL;
    + joydev->absmap[joydev->abspam[i]] = i;
    + }
    + return 0;
    +
    + case JSIOCGAXMAP:
    + return copy_to_user(argp, joydev->abspam,
    + sizeof(__u8) * (ABS_MAX + 1)) ? -EFAULT : 0;
    +
    + case JSIOCSBTNMAP:
    + if (copy_from_user(joydev->keypam, argp,
    + sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)))
    + return -EFAULT;
    +
    + for (i = 0; i < joydev->nkey; i++) {
    + if (joydev->keypam[i] > KEY_MAX ||
    + joydev->keypam[i] < BTN_MISC)
    + return -EINVAL;
    + joydev->keymap[joydev->keypam[i] - BTN_MISC] = i;
    + }

    - case JSIOCSBTNMAP:
    - if (copy_from_user(joydev->keypam, argp, sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)))
    + return 0;
    +
    + case JSIOCGBTNMAP:
    + return copy_to_user(argp, joydev->keypam,
    + sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)) ? -EFAULT : 0;
    +
    + default:
    + if ((cmd & ~IOCSIZE_MASK) == JSIOCGNAME(0)) {
    + int len;
    + if (!dev->name)
    + return 0;
    + len = strlen(dev->name) + 1;
    + if (len > _IOC_SIZE(cmd))
    + len = _IOC_SIZE(cmd);
    + if (copy_to_user(argp, dev->name, len))
    return -EFAULT;
    - for (i = 0; i < joydev->nkey; i++) {
    - if (joydev->keypam[i] > KEY_MAX || joydev->keypam[i] < BTN_MISC)
    - return -EINVAL;
    - joydev->keymap[joydev->keypam[i] - BTN_MISC] = i;
    - }
    - return 0;
    -
    - case JSIOCGBTNMAP:
    - return copy_to_user(argp, joydev->keypam,
    - sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)) ? -EFAULT : 0;
    -
    - default:
    - if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) {
    - int len;
    - if (!dev->name)
    - return 0;
    - len = strlen(dev->name) + 1;
    - if (len > _IOC_SIZE(cmd))
    - len = _IOC_SIZE(cmd);
    - if (copy_to_user(argp, dev->name, len))
    - return -EFAULT;
    - return len;
    - }
    + return len;
    + }
    }
    return -EINVAL;
    }

    #ifdef CONFIG_COMPAT
    -static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
    +static long joydev_compat_ioctl(struct file *file,
    + unsigned int cmd, unsigned long arg)
    {
    struct joydev_client *client = file->private_data;
    struct joydev *joydev = client->joydev;
    void __user *argp = (void __user *)arg;
    s32 tmp32;
    struct JS_DATA_SAVE_TYPE_32 ds32;
    - int err;
    + int retval;

    - if (!joydev->exist)
    - return -ENODEV;
    + retval = mutex_lock_interruptible(&joydev->mutex);
    + if (retval)
    + return retval;
    +
    + if (!joydev->exist) {
    + retval = -ENODEV;
    + goto out;
    + }
    +
    + switch (cmd) {

    - switch(cmd) {
    case JS_SET_TIMELIMIT:
    - err = get_user(tmp32, (s32 __user *) arg);
    - if (err == 0)
    + retval = get_user(tmp32, (s32 __user *) arg);
    + if (retval == 0)
    joydev->glue.JS_TIMELIMIT = tmp32;
    break;
    +
    case JS_GET_TIMELIMIT:
    tmp32 = joydev->glue.JS_TIMELIMIT;
    - err = put_user(tmp32, (s32 __user *) arg);
    + retval = put_user(tmp32, (s32 __user *) arg);
    break;

    case JS_SET_ALL:
    - err = copy_from_user(&ds32, argp,
    - sizeof(ds32)) ? -EFAULT : 0;
    - if (err == 0) {
    + retval = copy_from_user(&ds32, argp,
    + sizeof(ds32)) ? -EFAULT : 0;
    + if (retval == 0) {
    joydev->glue.JS_TIMEOUT = ds32.JS_TIMEOUT;
    joydev->glue.BUSY = ds32.BUSY;
    joydev->glue.JS_EXPIRETIME = ds32.JS_EXPIRETIME;
    @@ -438,55 +607,119 @@ static long joydev_compat_ioctl(struct f
    ds32.JS_SAVE = joydev->glue.JS_SAVE;
    ds32.JS_CORR = joydev->glue.JS_CORR;

    - err = copy_to_user(argp, &ds32, sizeof(ds32)) ? -EFAULT : 0;
    + retval = copy_to_user(argp, &ds32, sizeof(ds32)) ? -EFAULT : 0;
    break;

    default:
    - err = joydev_ioctl_common(joydev, cmd, argp);
    + retval = joydev_ioctl_common(joydev, cmd, argp);
    + break;
    }
    - return err;
    +
    + out:
    + mutex_unlock(&joydev->mutex);
    + return retval;
    }
    #endif /* CONFIG_COMPAT */

    -static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
    +static long joydev_ioctl(struct file *file,
    + unsigned int cmd, unsigned long arg)
    {
    struct joydev_client *client = file->private_data;
    struct joydev *joydev = client->joydev;
    void __user *argp = (void __user *)arg;
    + int retval;

    - if (!joydev->exist)
    - return -ENODEV;
    + retval = mutex_lock_interruptible(&joydev->mutex);
    + if (retval)
    + return retval;
    +
    + if (!joydev->exist) {
    + retval = -ENODEV;
    + goto out;
    + }
    +
    + switch (cmd) {
    +
    + case JS_SET_TIMELIMIT:
    + retval = get_user(joydev->glue.JS_TIMELIMIT,
    + (long __user *) arg);
    + break;
    +
    + case JS_GET_TIMELIMIT:
    + retval = put_user(joydev->glue.JS_TIMELIMIT,
    + (long __user *) arg);
    + break;
    +
    + case JS_SET_ALL:
    + retval = copy_from_user(&joydev->glue, argp,
    + sizeof(joydev->glue)) ? -EFAULT: 0;
    + break;

    - switch(cmd) {
    - case JS_SET_TIMELIMIT:
    - return get_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
    - case JS_GET_TIMELIMIT:
    - return put_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
    - case JS_SET_ALL:
    - return copy_from_user(&joydev->glue, argp,
    - sizeof(joydev->glue)) ? -EFAULT : 0;
    - case JS_GET_ALL:
    - return copy_to_user(argp, &joydev->glue,
    - sizeof(joydev->glue)) ? -EFAULT : 0;
    - default:
    - return joydev_ioctl_common(joydev, cmd, argp);
    + case JS_GET_ALL:
    + retval = copy_to_user(argp, &joydev->glue,
    + sizeof(joydev->glue)) ? -EFAULT : 0;
    + break;
    +
    + default:
    + retval = joydev_ioctl_common(joydev, cmd, argp);
    + break;
    }
    + out:
    + mutex_unlock(&joydev->mutex);
    + return retval;
    }

    static const struct file_operations joydev_fops = {
    - .owner = THIS_MODULE,
    - .read = joydev_read,
    - .write = joydev_write,
    - .poll = joydev_poll,
    - .open = joydev_open,
    - .release = joydev_release,
    - .ioctl = joydev_ioctl,
    + .owner = THIS_MODULE,
    + .read = joydev_read,
    + .poll = joydev_poll,
    + .open = joydev_open,
    + .release = joydev_release,
    + .unlocked_ioctl = joydev_ioctl,
    #ifdef CONFIG_COMPAT
    - .compat_ioctl = joydev_compat_ioctl,
    + .compat_ioctl = joydev_compat_ioctl,
    #endif
    - .fasync = joydev_fasync,
    + .fasync = joydev_fasync,
    };

    +static int joydev_install_chrdev(struct joydev *joydev)
    +{
    + joydev_table[joydev->minor] = joydev;
    + return 0;
    +}
    +
    +static void joydev_remove_chrdev(struct joydev *joydev)
    +{
    + mutex_lock(&joydev_table_mutex);
    + joydev_table[joydev->minor] = NULL;
    + mutex_unlock(&joydev_table_mutex);
    +}
    +
    +/*
    + * Mark device non-existant. This disables writes, ioctls and
    + * prevents new users from opening the device. Already posted
    + * blocking reads will stay, however new ones will fail.
    + */
    +static void joydev_mark_dead(struct joydev *joydev)
    +{
    + mutex_lock(&joydev->mutex);
    + joydev->exist = 0;
    + mutex_unlock(&joydev->mutex);
    +}
    +
    +static void joydev_cleanup(struct joydev *joydev)
    +{
    + struct input_handle *handle = &joydev->handle;
    +
    + joydev_mark_dead(joydev);
    + joydev_hangup(joydev);
    + joydev_remove_chrdev(joydev);
    +
    + /* joydev is marked dead so noone else accesses joydev->open */
    + if (joydev->open)
    + input_close_device(handle);
    +}
    +
    static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
    const struct input_device_id *id)
    {
    @@ -494,7 +727,10 @@ static int joydev_connect(struct input_h
    int i, j, t, minor;
    int error;

    - for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++);
    + for (minor = 0; minor < JOYDEV_MINORS; minor++)
    + if (!joydev_table[minor])
    + break;
    +
    if (minor == JOYDEV_MINORS) {
    printk(KERN_ERR "joydev: no more free joydev devices\n");
    return -ENFILE;
    @@ -505,15 +741,19 @@ static int joydev_connect(struct input_h
    return -ENOMEM;

    INIT_LIST_HEAD(&joydev->client_list);
    + spin_lock_init(&joydev->client_lock);
    + mutex_init(&joydev->mutex);
    init_waitqueue_head(&joydev->wait);

    + snprintf(joydev->name, sizeof(joydev->name), "js%d", minor);
    + joydev->exist = 1;
    joydev->minor = minor;
    +
    joydev->exist = 1;
    joydev->handle.dev = dev;
    joydev->handle.name = joydev->name;
    joydev->handle.handler = handler;
    joydev->handle.private = joydev;
    - snprintf(joydev->name, sizeof(joydev->name), "js%d", minor);

    for (i = 0; i < ABS_MAX + 1; i++)
    if (test_bit(i, dev->absbit)) {
    @@ -545,67 +785,65 @@ static int joydev_connect(struct input_h
    }
    joydev->corr[i].type = JS_CORR_BROKEN;
    joydev->corr[i].prec = dev->absfuzz[j];
    - joydev->corr[i].coef[0] = (dev->absmax[j] + dev->absmin[j]) / 2 - dev->absflat[j];
    - joydev->corr[i].coef[1] = (dev->absmax[j] + dev->absmin[j]) / 2 + dev->absflat[j];
    - if (!(t = ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j])))
    - continue;
    - joydev->corr[i].coef[2] = (1 << 29) / t;
    - joydev->corr[i].coef[3] = (1 << 29) / t;
    + joydev->corr[i].coef[0] =
    + (dev->absmax[j] + dev->absmin[j]) / 2 - dev->absflat[j];
    + joydev->corr[i].coef[1] =
    + (dev->absmax[j] + dev->absmin[j]) / 2 + dev->absflat[j];
    +
    + t = (dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j];
    + if (t) {
    + joydev->corr[i].coef[2] = (1 << 29) / t;
    + joydev->corr[i].coef[3] = (1 << 29) / t;

    - joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i);
    + joydev->abs[i] = joydev_correct(dev->abs[j],
    + joydev->corr + i);
    + }
    }

    - snprintf(joydev->dev.bus_id, sizeof(joydev->dev.bus_id),
    - "js%d", minor);
    + strlcpy(joydev->dev.bus_id, joydev->name, sizeof(joydev->dev.bus_id));
    + joydev->dev.devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor);
    joydev->dev.class = &input_class;
    joydev->dev.parent = &dev->dev;
    - joydev->dev.devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor);
    joydev->dev.release = joydev_free;
    device_initialize(&joydev->dev);

    - joydev_table[minor] = joydev;
    -
    - error = device_add(&joydev->dev);
    + error = input_register_handle(&joydev->handle);
    if (error)
    goto err_free_joydev;

    - error = input_register_handle(&joydev->handle);
    + error = joydev_install_chrdev(joydev);
    if (error)
    - goto err_delete_joydev;
    + goto err_unregister_handle;
    +
    + error = device_add(&joydev->dev);
    + if (error)
    + goto err_cleanup_joydev;

    return 0;

    - err_delete_joydev:
    - device_del(&joydev->dev);
    + err_cleanup_joydev:
    + joydev_cleanup(joydev);
    + err_unregister_handle:
    + input_unregister_handle(&joydev->handle);
    err_free_joydev:
    put_device(&joydev->dev);
    return error;
    }

    -
    static void joydev_disconnect(struct input_handle *handle)
    {
    struct joydev *joydev = handle->private;
    - struct joydev_client *client;

    - input_unregister_handle(handle);
    device_del(&joydev->dev);
    -
    - joydev->exist = 0;
    -
    - if (joydev->open) {
    - input_close_device(handle);
    - list_for_each_entry(client, &joydev->client_list, node)
    - kill_fasync(&client->fasync, SIGIO, POLL_HUP);
    - wake_up_interruptible(&joydev->wait);
    - }
    -
    + joydev_cleanup(joydev);
    + input_unregister_handle(handle);
    put_device(&joydev->dev);
    }

    static const struct input_device_id joydev_blacklist[] = {
    {
    - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
    + .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
    + INPUT_DEVICE_ID_MATCH_KEYBIT,
    .evbit = { BIT(EV_KEY) },
    .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) },
    }, /* Avoid itouchpads, touchscreens and tablets */
    @@ -614,17 +852,20 @@ static const struct input_device_id joyd

    static const struct input_device_id joydev_ids[] = {
    {
    - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
    + .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
    + INPUT_DEVICE_ID_MATCH_ABSBIT,
    .evbit = { BIT(EV_ABS) },
    .absbit = { BIT(ABS_X) },
    },
    {
    - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
    + .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
    + INPUT_DEVICE_ID_MATCH_ABSBIT,
    .evbit = { BIT(EV_ABS) },
    .absbit = { BIT(ABS_WHEEL) },
    },
    {
    - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
    + .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
    + INPUT_DEVICE_ID_MATCH_ABSBIT,
    .evbit = { BIT(EV_ABS) },
    .absbit = { BIT(ABS_THROTTLE) },
    },
    @@ -634,14 +875,14 @@ static const struct input_device_id joyd
    MODULE_DEVICE_TABLE(input, joydev_ids);

    static struct input_handler joydev_handler = {
    - .event = joydev_event,
    - .connect = joydev_connect,
    - .disconnect = joydev_disconnect,
    - .fops = &joydev_fops,
    - .minor = JOYDEV_MINOR_BASE,
    - .name = "joydev",
    - .id_table = joydev_ids,
    - .blacklist = joydev_blacklist,
    + .event = joydev_event,
    + .connect = joydev_connect,
    + .disconnect = joydev_disconnect,
    + .fops = &joydev_fops,
    + .minor = JOYDEV_MINOR_BASE,
    + .name = "joydev",
    + .id_table = joydev_ids,
    + .blacklist = joydev_blacklist,
    };

    static int __init joydev_init(void)

    --
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  19. [patch 66/73] fix oops on rmmod capidrv

    2.6.23-stable review patch. If anyone has any objections, please let us know.
    ------------------
    From: Karsten Keil

    patch eb36f4fc019835cecf0788907f6cab774508087b in mainline.

    Fix overwriting the stack with the version string
    (it is currently 10 bytes + zero) when unloading the
    capidrv module. Safeguard against overwriting it
    should the version string grow in the future.

    Should fix Kernel Bug Tracker Bug 9696.

    Signed-off-by: Gerd v. Egidy
    Acked-by: Karsten Keil
    Signed-off-by: Linus Torvalds
    Signed-off-by: Greg Kroah-Hartman

    ---
    drivers/isdn/capi/capidrv.c | 9 +++++----
    1 file changed, 5 insertions(+), 4 deletions(-)

    --- a/drivers/isdn/capi/capidrv.c
    +++ b/drivers/isdn/capi/capidrv.c
    @@ -2306,13 +2306,14 @@ static int __init capidrv_init(void)

    static void __exit capidrv_exit(void)
    {
    - char rev[10];
    + char rev[32];
    char *p;

    if ((p = strchr(revision, ':')) != 0) {
    - strcpy(rev, p + 1);
    - p = strchr(rev, '$');
    - *p = 0;
    + strncpy(rev, p + 1, sizeof(rev));
    + rev[sizeof(rev)-1] = 0;
    + if ((p = strchr(rev, '$')) != 0)
    + *p = 0;
    } else {
    strcpy(rev, " ??? ");
    }

    --
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  20. [patch 67/73] Netfilter: bridge: fix double POST_ROUTING invocation

    2.6.23-stable review patch. If anyone has any objections, please let us know.
    ------------------
    From: Patrick McHardy

    [NETFILTER]: bridge: fix double POST_ROUTING invocation

    Upstream commit 2948d2ebbb98747b912ac6d0c864b4d02be8a6f5

    The bridge code incorrectly causes two POST_ROUTING hook invocations
    for DNATed packets that end up on the same bridge device. This
    happens because packets with a changed destination address are passed
    to dst_output() to make them go through the neighbour output function
    again to build a new destination MAC address, before they will continue
    through the IP hooks simulated by bridge netfilter.

    The resulting hook order is:
    PREROUTING (bridge netfilter)
    POSTROUTING (dst_output -> ip_output)
    FORWARD (bridge netfilter)
    POSTROUTING (bridge netfilter)

    The deferred hooks used to abort the first POST_ROUTING invocation,
    but since the only thing bridge netfilter actually really wants is
    a new MAC address, we can avoid going through the IP stack completely
    by simply calling the neighbour output function directly.

    Tested, reported and lots of data provided by: Damien Thebault

    Signed-off-by: Patrick McHardy
    Signed-off-by: David S. Miller
    Signed-off-by: Greg Kroah-Hartman

    ---
    net/bridge/br_netfilter.c | 18 ++++++++++++------
    1 file changed, 12 insertions(+), 6 deletions(-)

    --- a/net/bridge/br_netfilter.c
    +++ b/net/bridge/br_netfilter.c
    @@ -247,8 +247,9 @@ static void __br_dnat_complain(void)
    * Let us first consider the case that ip_route_input() succeeds:
    *
    * If skb->dst->dev equals the logical bridge device the packet
    - * came in on, we can consider this bridging. We then call
    - * skb->dst->output() which will make the packet enter br_nf_local_out()
    + * came in on, we can consider this bridging. The packet is passed
    + * through the neighbour output function to build a new destination
    + * MAC address, which will make the packet enter br_nf_local_out()
    * not much later. In that function it is assured that the iptables
    * FORWARD chain is traversed for the packet.
    *
    @@ -285,12 +286,17 @@ static int br_nf_pre_routing_finish_brid
    skb->nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;

    skb->dev = bridge_parent(skb->dev);
    - if (!skb->dev)
    - kfree_skb(skb);
    - else {
    + if (skb->dev) {
    + struct dst_entry *dst = skb->dst;
    +
    nf_bridge_pull_encap_header(skb);
    - skb->dst->output(skb);
    +
    + if (dst->hh)
    + return neigh_hh_output(dst->hh, skb);
    + else if (dst->neighbour)
    + return dst->neighbour->output(skb);
    }
    + kfree_skb(skb);
    return 0;
    }


    --
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

+ Reply to Thread
Page 3 of 4 FirstFirst 1 2 3 4 LastLast