]> git.karo-electronics.de Git - linux-beck.git/commitdiff
Merge branch 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 14 Nov 2009 21:03:24 +0000 (13:03 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 14 Nov 2009 21:03:24 +0000 (13:03 -0800)
* 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus:
  MIPS: SMTC: Fix lockup in smtc_distribute_timer
  MIPS: TXx9: Update rbtx49xx_defconfig
  MIPS: Make local arrays with CL_SIZE static __initdata
  MIPS: Add DMA declare coherent memory support
  MIPS: Fix emulation of 64-bit FPU on FPU-less 64-bit CPUs.

16 files changed:
arch/s390/kernel/early.c
arch/s390/kernel/entry.S
arch/s390/kernel/entry64.S
drivers/bluetooth/btusb.c
drivers/input/ff-core.c
drivers/input/ff-memless.c
drivers/input/input.c
drivers/input/keyboard/atkbd.c
drivers/input/mouse/psmouse-base.c
drivers/md/md.c
drivers/md/raid5.c
drivers/s390/char/monreader.c
drivers/s390/char/sclp_quiesce.c
fs/nfsd/nfs3xdr.c
include/linux/input.h
mm/percpu.c

index bf8b4ae7ff2d6450ac6fee0f7133e2fddc24b702..e49e9e0c69fd88278eaa707271c18466d23f70ad 100644 (file)
@@ -55,6 +55,7 @@ static void __init reset_tod_clock(void)
                disabled_wait(0);
 
        sched_clock_base_cc = TOD_UNIX_EPOCH;
+       S390_lowcore.last_update_clock = sched_clock_base_cc;
 }
 
 #ifdef CONFIG_SHARED_KERNEL
@@ -167,6 +168,14 @@ static noinline __init void create_kernel_nss(void)
                return;
        }
 
+       /* re-initialize cputime accounting. */
+       sched_clock_base_cc = get_clock();
+       S390_lowcore.last_update_clock = sched_clock_base_cc;
+       S390_lowcore.last_update_timer = 0x7fffffffffffffffULL;
+       S390_lowcore.user_timer = 0;
+       S390_lowcore.system_timer = 0;
+       asm volatile("SPT 0(%0)" : : "a" (&S390_lowcore.last_update_timer));
+
        /* re-setup boot command line with new ipl vm parms */
        ipl_update_parameters();
        setup_boot_command_line();
index f43d2ee544645a4de9eb679f9dbe095d555dfe77..48215d15762b2d3d6a3be7eaf6fe509a45268567 100644 (file)
@@ -565,10 +565,10 @@ pgm_svcper:
        lh      %r7,0x8a                # get svc number from lowcore
        l       %r9,__LC_THREAD_INFO    # load pointer to thread_info struct
        TRACE_IRQS_OFF
-       l       %r1,__TI_task(%r9)
-       mvc     __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID
-       mvc     __THREAD_per+__PER_address(4,%r1),__LC_PER_ADDRESS
-       mvc     __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID
+       l       %r8,__TI_task(%r9)
+       mvc     __THREAD_per+__PER_atmid(2,%r8),__LC_PER_ATMID
+       mvc     __THREAD_per+__PER_address(4,%r8),__LC_PER_ADDRESS
+       mvc     __THREAD_per+__PER_access_id(1,%r8),__LC_PER_ACCESS_ID
        oi      __TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
        TRACE_IRQS_ON
        stosm   __SF_EMPTY(%r15),0x03   # reenable interrupts
index a6f7b20df61687a6445de264a17bc7e0ec44bb96..9aff1d449b6e83c2be03275ad46cf6f3e3599a7c 100644 (file)
@@ -543,10 +543,10 @@ pgm_svcper:
        mvc     __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
        llgh    %r7,__LC_SVC_INT_CODE   # get svc number from lowcore
        lg      %r9,__LC_THREAD_INFO    # load pointer to thread_info struct
-       lg      %r1,__TI_task(%r9)
-       mvc     __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID
-       mvc     __THREAD_per+__PER_address(8,%r1),__LC_PER_ADDRESS
-       mvc     __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID
+       lg      %r8,__TI_task(%r9)
+       mvc     __THREAD_per+__PER_atmid(2,%r8),__LC_PER_ATMID
+       mvc     __THREAD_per+__PER_address(8,%r8),__LC_PER_ADDRESS
+       mvc     __THREAD_per+__PER_access_id(1,%r8),__LC_PER_ACCESS_ID
        oi      __TI_flags+7(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
        TRACE_IRQS_ON
        stosm   __SF_EMPTY(%r15),0x03   # reenable interrupts
index 2fb38027f3bb8773da3d380c8322cbb947c2ea57..44bc8bbabf5474948d59eb8ce15cff6bef11b819 100644 (file)
@@ -600,11 +600,13 @@ static int btusb_close(struct hci_dev *hdev)
        btusb_stop_traffic(data);
        err = usb_autopm_get_interface(data->intf);
        if (err < 0)
-               return 0;
+               goto failed;
 
        data->intf->needs_remote_wakeup = 0;
        usb_autopm_put_interface(data->intf);
 
+failed:
+       usb_scuttle_anchored_urbs(&data->deferred);
        return 0;
 }
 
index 72c63e5dd630709ddffccf8dc945147857bf41ba..38df81fcdc3a90bdb4f812a02a4d064e6d657f2d 100644 (file)
@@ -337,16 +337,16 @@ int input_ff_create(struct input_dev *dev, int max_effects)
        dev->ff = ff;
        dev->flush = flush_effects;
        dev->event = input_ff_event;
-       set_bit(EV_FF, dev->evbit);
+       __set_bit(EV_FF, dev->evbit);
 
        /* Copy "true" bits into ff device bitmap */
        for (i = 0; i <= FF_MAX; i++)
                if (test_bit(i, dev->ffbit))
-                       set_bit(i, ff->ffbit);
+                       __set_bit(i, ff->ffbit);
 
        /* we can emulate RUMBLE with periodic effects */
        if (test_bit(FF_PERIODIC, ff->ffbit))
-               set_bit(FF_RUMBLE, dev->ffbit);
+               __set_bit(FF_RUMBLE, dev->ffbit);
 
        return 0;
 }
@@ -362,12 +362,14 @@ EXPORT_SYMBOL_GPL(input_ff_create);
  */
 void input_ff_destroy(struct input_dev *dev)
 {
-       clear_bit(EV_FF, dev->evbit);
-       if (dev->ff) {
-               if (dev->ff->destroy)
-                       dev->ff->destroy(dev->ff);
-               kfree(dev->ff->private);
-               kfree(dev->ff);
+       struct ff_device *ff = dev->ff;
+
+       __clear_bit(EV_FF, dev->evbit);
+       if (ff) {
+               if (ff->destroy)
+                       ff->destroy(ff);
+               kfree(ff->private);
+               kfree(ff);
                dev->ff = NULL;
        }
 }
index 2d1415e1683467ae55de53ba3fb273996ba7a795..b483b2995fa9918ad9cec432b37f0248517c45af 100644 (file)
@@ -61,7 +61,6 @@ struct ml_device {
        struct ml_effect_state states[FF_MEMLESS_EFFECTS];
        int gain;
        struct timer_list timer;
-       spinlock_t timer_lock;
        struct input_dev *dev;
 
        int (*play_effect)(struct input_dev *dev, void *data,
@@ -368,38 +367,38 @@ static void ml_effect_timer(unsigned long timer_data)
 {
        struct input_dev *dev = (struct input_dev *)timer_data;
        struct ml_device *ml = dev->ff->private;
+       unsigned long flags;
 
        debug("timer: updating effects");
 
-       spin_lock(&ml->timer_lock);
+       spin_lock_irqsave(&dev->event_lock, flags);
        ml_play_effects(ml);
-       spin_unlock(&ml->timer_lock);
+       spin_unlock_irqrestore(&dev->event_lock, flags);
 }
 
+/*
+ * Sets requested gain for FF effects. Called with dev->event_lock held.
+ */
 static void ml_ff_set_gain(struct input_dev *dev, u16 gain)
 {
        struct ml_device *ml = dev->ff->private;
        int i;
 
-       spin_lock_bh(&ml->timer_lock);
-
        ml->gain = gain;
 
        for (i = 0; i < FF_MEMLESS_EFFECTS; i++)
                __clear_bit(FF_EFFECT_PLAYING, &ml->states[i].flags);
 
        ml_play_effects(ml);
-
-       spin_unlock_bh(&ml->timer_lock);
 }
 
+/*
+ * Start/stop specified FF effect. Called with dev->event_lock held.
+ */
 static int ml_ff_playback(struct input_dev *dev, int effect_id, int value)
 {
        struct ml_device *ml = dev->ff->private;
        struct ml_effect_state *state = &ml->states[effect_id];
-       unsigned long flags;
-
-       spin_lock_irqsave(&ml->timer_lock, flags);
 
        if (value > 0) {
                debug("initiated play");
@@ -425,8 +424,6 @@ static int ml_ff_playback(struct input_dev *dev, int effect_id, int value)
                ml_play_effects(ml);
        }
 
-       spin_unlock_irqrestore(&ml->timer_lock, flags);
-
        return 0;
 }
 
@@ -436,7 +433,7 @@ static int ml_ff_upload(struct input_dev *dev,
        struct ml_device *ml = dev->ff->private;
        struct ml_effect_state *state = &ml->states[effect->id];
 
-       spin_lock_bh(&ml->timer_lock);
+       spin_lock_irq(&dev->event_lock);
 
        if (test_bit(FF_EFFECT_STARTED, &state->flags)) {
                __clear_bit(FF_EFFECT_PLAYING, &state->flags);
@@ -448,7 +445,7 @@ static int ml_ff_upload(struct input_dev *dev,
                ml_schedule_timer(ml);
        }
 
-       spin_unlock_bh(&ml->timer_lock);
+       spin_unlock_irq(&dev->event_lock);
 
        return 0;
 }
@@ -482,7 +479,6 @@ int input_ff_create_memless(struct input_dev *dev, void *data,
        ml->private = data;
        ml->play_effect = play_effect;
        ml->gain = 0xffff;
-       spin_lock_init(&ml->timer_lock);
        setup_timer(&ml->timer, ml_effect_timer, (unsigned long)dev);
 
        set_bit(FF_GAIN, dev->ffbit);
index cc763c96fadadf0565048a2a897d0f6202d81f09..2266ecbfbc010789390c9a5ebb36b72d0960526e 100644 (file)
@@ -1292,17 +1292,24 @@ static int input_dev_uevent(struct device *device, struct kobj_uevent_env *env)
        return 0;
 }
 
-#define INPUT_DO_TOGGLE(dev, type, bits, on)                   \
-       do {                                                    \
-               int i;                                          \
-               if (!test_bit(EV_##type, dev->evbit))           \
-                       break;                                  \
-               for (i = 0; i < type##_MAX; i++) {              \
-                       if (!test_bit(i, dev->bits##bit) ||     \
-                           !test_bit(i, dev->bits))            \
-                               continue;                       \
-                       dev->event(dev, EV_##type, i, on);      \
-               }                                               \
+#define INPUT_DO_TOGGLE(dev, type, bits, on)                           \
+       do {                                                            \
+               int i;                                                  \
+               bool active;                                            \
+                                                                       \
+               if (!test_bit(EV_##type, dev->evbit))                   \
+                       break;                                          \
+                                                                       \
+               for (i = 0; i < type##_MAX; i++) {                      \
+                       if (!test_bit(i, dev->bits##bit))               \
+                               continue;                               \
+                                                                       \
+                       active = test_bit(i, dev->bits);                \
+                       if (!active && !on)                             \
+                               continue;                               \
+                                                                       \
+                       dev->event(dev, EV_##type, i, on ? active : 0); \
+               }                                                       \
        } while (0)
 
 #ifdef CONFIG_PM
index 4452eabbee6d66f14482271c35943a3125721aa6..28e6110d1ff8a51c3eed113f49f6410a1db8784d 100644 (file)
@@ -1174,6 +1174,18 @@ static int atkbd_reconnect(struct serio *serio)
                        return -1;
 
                atkbd_activate(atkbd);
+
+               /*
+                * Restore LED state and repeat rate. While input core
+                * will do this for us at resume time reconnect may happen
+                * because user requested it via sysfs or simply because
+                * keyboard was unplugged and plugged in again so we need
+                * to do it ourselves here.
+                */
+               atkbd_set_leds(atkbd);
+               if (!atkbd->softrepeat)
+                       atkbd_set_repeat_rate(atkbd);
+
        }
 
        atkbd_enable(atkbd);
@@ -1422,6 +1434,7 @@ static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count)
 
                atkbd->dev = new_dev;
                atkbd->set = atkbd_select_set(atkbd, value, atkbd->extra);
+               atkbd_reset_state(atkbd);
                atkbd_activate(atkbd);
                atkbd_set_keycode_table(atkbd);
                atkbd_set_device_attrs(atkbd);
index 690aed90543694e0c4d94cf6e8234bbef228843e..5bd64841bf1c393963f7076676aaa24f6b609387 100644 (file)
@@ -1673,7 +1673,7 @@ static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp)
 {
        int type = *((unsigned int *)kp->arg);
 
-       return sprintf(buffer, "%s\n", psmouse_protocol_by_type(type)->name);
+       return sprintf(buffer, "%s", psmouse_protocol_by_type(type)->name);
 }
 
 static int __init psmouse_init(void)
index e64c971038d14a4ddc588876d010e5b748b05d8f..b182f86a19dda9c71d12553e9d6891f2e24d0cfe 100644 (file)
@@ -944,6 +944,14 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev)
                            desc->raid_disk < mddev->raid_disks */) {
                        set_bit(In_sync, &rdev->flags);
                        rdev->raid_disk = desc->raid_disk;
+               } else if (desc->state & (1<<MD_DISK_ACTIVE)) {
+                       /* active but not in sync implies recovery up to
+                        * reshape position.  We don't know exactly where
+                        * that is, so set to zero for now */
+                       if (mddev->minor_version >= 91) {
+                               rdev->recovery_offset = 0;
+                               rdev->raid_disk = desc->raid_disk;
+                       }
                }
                if (desc->state & (1<<MD_DISK_WRITEMOSTLY))
                        set_bit(WriteMostly, &rdev->flags);
@@ -1032,8 +1040,19 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev)
        list_for_each_entry(rdev2, &mddev->disks, same_set) {
                mdp_disk_t *d;
                int desc_nr;
-               if (rdev2->raid_disk >= 0 && test_bit(In_sync, &rdev2->flags)
-                   && !test_bit(Faulty, &rdev2->flags))
+               int is_active = test_bit(In_sync, &rdev2->flags);
+
+               if (rdev2->raid_disk >= 0 &&
+                   sb->minor_version >= 91)
+                       /* we have nowhere to store the recovery_offset,
+                        * but if it is not below the reshape_position,
+                        * we can piggy-back on that.
+                        */
+                       is_active = 1;
+               if (rdev2->raid_disk < 0 ||
+                   test_bit(Faulty, &rdev2->flags))
+                       is_active = 0;
+               if (is_active)
                        desc_nr = rdev2->raid_disk;
                else
                        desc_nr = next_spare++;
@@ -1043,16 +1062,16 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev)
                d->number = rdev2->desc_nr;
                d->major = MAJOR(rdev2->bdev->bd_dev);
                d->minor = MINOR(rdev2->bdev->bd_dev);
-               if (rdev2->raid_disk >= 0 && test_bit(In_sync, &rdev2->flags)
-                   && !test_bit(Faulty, &rdev2->flags))
+               if (is_active)
                        d->raid_disk = rdev2->raid_disk;
                else
                        d->raid_disk = rdev2->desc_nr; /* compatibility */
                if (test_bit(Faulty, &rdev2->flags))
                        d->state = (1<<MD_DISK_FAULTY);
-               else if (test_bit(In_sync, &rdev2->flags)) {
+               else if (is_active) {
                        d->state = (1<<MD_DISK_ACTIVE);
-                       d->state |= (1<<MD_DISK_SYNC);
+                       if (test_bit(In_sync, &rdev2->flags))
+                               d->state |= (1<<MD_DISK_SYNC);
                        active++;
                        working++;
                } else {
@@ -1382,8 +1401,6 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev)
 
        if (rdev->raid_disk >= 0 &&
            !test_bit(In_sync, &rdev->flags)) {
-               if (mddev->curr_resync_completed > rdev->recovery_offset)
-                       rdev->recovery_offset = mddev->curr_resync_completed;
                if (rdev->recovery_offset > 0) {
                        sb->feature_map |=
                                cpu_to_le32(MD_FEATURE_RECOVERY_OFFSET);
@@ -1917,6 +1934,14 @@ static void sync_sbs(mddev_t * mddev, int nospares)
         */
        mdk_rdev_t *rdev;
 
+       /* First make sure individual recovery_offsets are correct */
+       list_for_each_entry(rdev, &mddev->disks, same_set) {
+               if (rdev->raid_disk >= 0 &&
+                   !test_bit(In_sync, &rdev->flags) &&
+                   mddev->curr_resync_completed > rdev->recovery_offset)
+                               rdev->recovery_offset = mddev->curr_resync_completed;
+
+       }       
        list_for_each_entry(rdev, &mddev->disks, same_set) {
                if (rdev->sb_events == mddev->events ||
                    (nospares &&
index dcce204b6c733bb36887ab1981e25ac35ece189b..d29215d966dadc23f4c1a6844a725dc89d6a8304 100644 (file)
@@ -4823,11 +4823,40 @@ static raid5_conf_t *setup_conf(mddev_t *mddev)
                return ERR_PTR(-ENOMEM);
 }
 
+
+static int only_parity(int raid_disk, int algo, int raid_disks, int max_degraded)
+{
+       switch (algo) {
+       case ALGORITHM_PARITY_0:
+               if (raid_disk < max_degraded)
+                       return 1;
+               break;
+       case ALGORITHM_PARITY_N:
+               if (raid_disk >= raid_disks - max_degraded)
+                       return 1;
+               break;
+       case ALGORITHM_PARITY_0_6:
+               if (raid_disk == 0 || 
+                   raid_disk == raid_disks - 1)
+                       return 1;
+               break;
+       case ALGORITHM_LEFT_ASYMMETRIC_6:
+       case ALGORITHM_RIGHT_ASYMMETRIC_6:
+       case ALGORITHM_LEFT_SYMMETRIC_6:
+       case ALGORITHM_RIGHT_SYMMETRIC_6:
+               if (raid_disk == raid_disks - 1)
+                       return 1;
+       }
+       return 0;
+}
+
 static int run(mddev_t *mddev)
 {
        raid5_conf_t *conf;
        int working_disks = 0, chunk_size;
+       int dirty_parity_disks = 0;
        mdk_rdev_t *rdev;
+       sector_t reshape_offset = 0;
 
        if (mddev->recovery_cp != MaxSector)
                printk(KERN_NOTICE "raid5: %s is not clean"
@@ -4861,6 +4890,7 @@ static int run(mddev_t *mddev)
                               "on a stripe boundary\n");
                        return -EINVAL;
                }
+               reshape_offset = here_new * mddev->new_chunk_sectors;
                /* here_new is the stripe we will write to */
                here_old = mddev->reshape_position;
                sector_div(here_old, mddev->chunk_sectors *
@@ -4916,10 +4946,51 @@ static int run(mddev_t *mddev)
        /*
         * 0 for a fully functional array, 1 or 2 for a degraded array.
         */
-       list_for_each_entry(rdev, &mddev->disks, same_set)
-               if (rdev->raid_disk >= 0 &&
-                   test_bit(In_sync, &rdev->flags))
+       list_for_each_entry(rdev, &mddev->disks, same_set) {
+               if (rdev->raid_disk < 0)
+                       continue;
+               if (test_bit(In_sync, &rdev->flags))
                        working_disks++;
+               /* This disc is not fully in-sync.  However if it
+                * just stored parity (beyond the recovery_offset),
+                * when we don't need to be concerned about the
+                * array being dirty.
+                * When reshape goes 'backwards', we never have
+                * partially completed devices, so we only need
+                * to worry about reshape going forwards.
+                */
+               /* Hack because v0.91 doesn't store recovery_offset properly. */
+               if (mddev->major_version == 0 &&
+                   mddev->minor_version > 90)
+                       rdev->recovery_offset = reshape_offset;
+                       
+               printk("%d: w=%d pa=%d pr=%d m=%d a=%d r=%d op1=%d op2=%d\n",
+                      rdev->raid_disk, working_disks, conf->prev_algo,
+                      conf->previous_raid_disks, conf->max_degraded,
+                      conf->algorithm, conf->raid_disks, 
+                      only_parity(rdev->raid_disk,
+                                  conf->prev_algo,
+                                  conf->previous_raid_disks,
+                                  conf->max_degraded),
+                      only_parity(rdev->raid_disk,
+                                  conf->algorithm,
+                                  conf->raid_disks,
+                                  conf->max_degraded));
+               if (rdev->recovery_offset < reshape_offset) {
+                       /* We need to check old and new layout */
+                       if (!only_parity(rdev->raid_disk,
+                                        conf->algorithm,
+                                        conf->raid_disks,
+                                        conf->max_degraded))
+                               continue;
+               }
+               if (!only_parity(rdev->raid_disk,
+                                conf->prev_algo,
+                                conf->previous_raid_disks,
+                                conf->max_degraded))
+                       continue;
+               dirty_parity_disks++;
+       }
 
        mddev->degraded = (max(conf->raid_disks, conf->previous_raid_disks)
                           - working_disks);
@@ -4935,7 +5006,7 @@ static int run(mddev_t *mddev)
        mddev->dev_sectors &= ~(mddev->chunk_sectors - 1);
        mddev->resync_max_sectors = mddev->dev_sectors;
 
-       if (mddev->degraded > 0 &&
+       if (mddev->degraded > dirty_parity_disks &&
            mddev->recovery_cp != MaxSector) {
                if (mddev->ok_start_degraded)
                        printk(KERN_WARNING
@@ -5361,9 +5432,11 @@ static int raid5_start_reshape(mddev_t *mddev)
                    !test_bit(Faulty, &rdev->flags)) {
                        if (raid5_add_disk(mddev, rdev) == 0) {
                                char nm[20];
-                               set_bit(In_sync, &rdev->flags);
+                               if (rdev->raid_disk >= conf->previous_raid_disks)
+                                       set_bit(In_sync, &rdev->flags);
+                               else
+                                       rdev->recovery_offset = 0;
                                added_devices++;
-                               rdev->recovery_offset = 0;
                                sprintf(nm, "rd%d", rdev->raid_disk);
                                if (sysfs_create_link(&mddev->kobj,
                                                      &rdev->kobj, nm))
index 89ece1c235aa7d4919a5efd505196137a156409c..66e21dd23154b4c5c27b0c254a3bfd348cc88d48 100644 (file)
@@ -357,6 +357,7 @@ static int mon_close(struct inode *inode, struct file *filp)
        atomic_set(&monpriv->msglim_count, 0);
        monpriv->write_index  = 0;
        monpriv->read_index   = 0;
+       dev_set_drvdata(monreader_device, NULL);
 
        for (i = 0; i < MON_MSGLIM; i++)
                kfree(monpriv->msg_array[i]);
index 84c191c1cd620fa1e5a723dcb060f9a8d4ae9175..05909a7df8b30df91009c01146acae763f110da4 100644 (file)
 
 #include "sclp.h"
 
+static void (*old_machine_restart)(char *);
+static void (*old_machine_halt)(void);
+static void (*old_machine_power_off)(void);
+
 /* Shutdown handler. Signal completion of shutdown by loading special PSW. */
-static void
-do_machine_quiesce(void)
+static void do_machine_quiesce(void)
 {
        psw_t quiesce_psw;
 
@@ -33,23 +36,48 @@ do_machine_quiesce(void)
 }
 
 /* Handler for quiesce event. Start shutdown procedure. */
-static void
-sclp_quiesce_handler(struct evbuf_header *evbuf)
+static void sclp_quiesce_handler(struct evbuf_header *evbuf)
 {
-       _machine_restart = (void *) do_machine_quiesce;
-       _machine_halt = do_machine_quiesce;
-       _machine_power_off = do_machine_quiesce;
+       if (_machine_restart != (void *) do_machine_quiesce) {
+               old_machine_restart = _machine_restart;
+               old_machine_halt = _machine_halt;
+               old_machine_power_off = _machine_power_off;
+               _machine_restart = (void *) do_machine_quiesce;
+               _machine_halt = do_machine_quiesce;
+               _machine_power_off = do_machine_quiesce;
+       }
        ctrl_alt_del();
 }
 
+/* Undo machine restart/halt/power_off modification on resume */
+static void sclp_quiesce_pm_event(struct sclp_register *reg,
+                                 enum sclp_pm_event sclp_pm_event)
+{
+       switch (sclp_pm_event) {
+       case SCLP_PM_EVENT_RESTORE:
+               if (old_machine_restart) {
+                       _machine_restart = old_machine_restart;
+                       _machine_halt = old_machine_halt;
+                       _machine_power_off = old_machine_power_off;
+                       old_machine_restart = NULL;
+                       old_machine_halt = NULL;
+                       old_machine_power_off = NULL;
+               }
+               break;
+       case SCLP_PM_EVENT_FREEZE:
+       case SCLP_PM_EVENT_THAW:
+               break;
+       }
+}
+
 static struct sclp_register sclp_quiesce_event = {
        .receive_mask = EVTYP_SIGQUIESCE_MASK,
-       .receiver_fn = sclp_quiesce_handler
+       .receiver_fn = sclp_quiesce_handler,
+       .pm_event_fn = sclp_quiesce_pm_event
 };
 
 /* Initialize quiesce driver. */
-static int __init
-sclp_quiesce_init(void)
+static int __init sclp_quiesce_init(void)
 {
        return sclp_register(&sclp_quiesce_event);
 }
index edf926e1062f8be520b4b64de72e9f26e7aaa0f6..d0a2ce1b43248a6eacbff2b4804314c57b898cbc 100644 (file)
@@ -958,7 +958,7 @@ encode_entry(struct readdir_cd *ccd, const char *name, int namlen,
                p1 = encode_entry_baggage(cd, p1, name, namlen, ino);
 
                if (plus)
-                       p = encode_entryplus_baggage(cd, p1, name, namlen);
+                       p1 = encode_entryplus_baggage(cd, p1, name, namlen);
 
                /* determine entry word length and lengths to go in pages */
                num_entry_words = p1 - tmp;
index 0ccfc30cd40f7696e0b9e863272f82fb8e42e0f0..c2b1a7d244d918f9127aaf557b6127a2b12486c7 100644 (file)
@@ -1377,6 +1377,10 @@ extern struct class input_class;
  * methods; erase() is optional. set_gain() and set_autocenter() need
  * only be implemented if driver sets up FF_GAIN and FF_AUTOCENTER
  * bits.
+ *
+ * Note that playback(), set_gain() and set_autocenter() are called with
+ * dev->event_lock spinlock held and interrupts off and thus may not
+ * sleep.
  */
 struct ff_device {
        int (*upload)(struct input_dev *dev, struct ff_effect *effect,
index d90797160c2a7fff7be950b04ac9817292208ee0..5adfc268b408936a3d18ae9014ce70e49590738d 100644 (file)
@@ -355,62 +355,86 @@ static struct pcpu_chunk *pcpu_chunk_addr_search(void *addr)
 }
 
 /**
- * pcpu_extend_area_map - extend area map for allocation
- * @chunk: target chunk
+ * pcpu_need_to_extend - determine whether chunk area map needs to be extended
+ * @chunk: chunk of interest
  *
- * Extend area map of @chunk so that it can accomodate an allocation.
- * A single allocation can split an area into three areas, so this
- * function makes sure that @chunk->map has at least two extra slots.
+ * Determine whether area map of @chunk needs to be extended to
+ * accomodate a new allocation.
  *
  * CONTEXT:
- * pcpu_alloc_mutex, pcpu_lock.  pcpu_lock is released and reacquired
- * if area map is extended.
+ * pcpu_lock.
  *
  * RETURNS:
- * 0 if noop, 1 if successfully extended, -errno on failure.
+ * New target map allocation length if extension is necessary, 0
+ * otherwise.
  */
-static int pcpu_extend_area_map(struct pcpu_chunk *chunk, unsigned long *flags)
+static int pcpu_need_to_extend(struct pcpu_chunk *chunk)
 {
        int new_alloc;
-       int *new;
-       size_t size;
 
-       /* has enough? */
        if (chunk->map_alloc >= chunk->map_used + 2)
                return 0;
 
-       spin_unlock_irqrestore(&pcpu_lock, *flags);
-
        new_alloc = PCPU_DFL_MAP_ALLOC;
        while (new_alloc < chunk->map_used + 2)
                new_alloc *= 2;
 
-       new = pcpu_mem_alloc(new_alloc * sizeof(new[0]));
-       if (!new) {
-               spin_lock_irqsave(&pcpu_lock, *flags);
+       return new_alloc;
+}
+
+/**
+ * pcpu_extend_area_map - extend area map of a chunk
+ * @chunk: chunk of interest
+ * @new_alloc: new target allocation length of the area map
+ *
+ * Extend area map of @chunk to have @new_alloc entries.
+ *
+ * CONTEXT:
+ * Does GFP_KERNEL allocation.  Grabs and releases pcpu_lock.
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+static int pcpu_extend_area_map(struct pcpu_chunk *chunk, int new_alloc)
+{
+       int *old = NULL, *new = NULL;
+       size_t old_size = 0, new_size = new_alloc * sizeof(new[0]);
+       unsigned long flags;
+
+       new = pcpu_mem_alloc(new_size);
+       if (!new)
                return -ENOMEM;
-       }
 
-       /*
-        * Acquire pcpu_lock and switch to new area map.  Only free
-        * could have happened inbetween, so map_used couldn't have
-        * grown.
-        */
-       spin_lock_irqsave(&pcpu_lock, *flags);
-       BUG_ON(new_alloc < chunk->map_used + 2);
+       /* acquire pcpu_lock and switch to new area map */
+       spin_lock_irqsave(&pcpu_lock, flags);
+
+       if (new_alloc <= chunk->map_alloc)
+               goto out_unlock;
 
-       size = chunk->map_alloc * sizeof(chunk->map[0]);
-       memcpy(new, chunk->map, size);
+       old_size = chunk->map_alloc * sizeof(chunk->map[0]);
+       memcpy(new, chunk->map, old_size);
 
        /*
         * map_alloc < PCPU_DFL_MAP_ALLOC indicates that the chunk is
         * one of the first chunks and still using static map.
         */
        if (chunk->map_alloc >= PCPU_DFL_MAP_ALLOC)
-               pcpu_mem_free(chunk->map, size);
+               old = chunk->map;
 
        chunk->map_alloc = new_alloc;
        chunk->map = new;
+       new = NULL;
+
+out_unlock:
+       spin_unlock_irqrestore(&pcpu_lock, flags);
+
+       /*
+        * pcpu_mem_free() might end up calling vfree() which uses
+        * IRQ-unsafe lock and thus can't be called under pcpu_lock.
+        */
+       pcpu_mem_free(old, old_size);
+       pcpu_mem_free(new, new_size);
+
        return 0;
 }
 
@@ -1049,7 +1073,7 @@ static void *pcpu_alloc(size_t size, size_t align, bool reserved)
        static int warn_limit = 10;
        struct pcpu_chunk *chunk;
        const char *err;
-       int slot, off;
+       int slot, off, new_alloc;
        unsigned long flags;
 
        if (unlikely(!size || size > PCPU_MIN_UNIT_SIZE || align > PAGE_SIZE)) {
@@ -1064,14 +1088,25 @@ static void *pcpu_alloc(size_t size, size_t align, bool reserved)
        /* serve reserved allocations from the reserved chunk if available */
        if (reserved && pcpu_reserved_chunk) {
                chunk = pcpu_reserved_chunk;
-               if (size > chunk->contig_hint ||
-                   pcpu_extend_area_map(chunk, &flags) < 0) {
-                       err = "failed to extend area map of reserved chunk";
+
+               if (size > chunk->contig_hint) {
+                       err = "alloc from reserved chunk failed";
                        goto fail_unlock;
                }
+
+               while ((new_alloc = pcpu_need_to_extend(chunk))) {
+                       spin_unlock_irqrestore(&pcpu_lock, flags);
+                       if (pcpu_extend_area_map(chunk, new_alloc) < 0) {
+                               err = "failed to extend area map of reserved chunk";
+                               goto fail_unlock_mutex;
+                       }
+                       spin_lock_irqsave(&pcpu_lock, flags);
+               }
+
                off = pcpu_alloc_area(chunk, size, align);
                if (off >= 0)
                        goto area_found;
+
                err = "alloc from reserved chunk failed";
                goto fail_unlock;
        }
@@ -1083,14 +1118,20 @@ restart:
                        if (size > chunk->contig_hint)
                                continue;
 
-                       switch (pcpu_extend_area_map(chunk, &flags)) {
-                       case 0:
-                               break;
-                       case 1:
-                               goto restart;   /* pcpu_lock dropped, restart */
-                       default:
-                               err = "failed to extend area map";
-                               goto fail_unlock;
+                       new_alloc = pcpu_need_to_extend(chunk);
+                       if (new_alloc) {
+                               spin_unlock_irqrestore(&pcpu_lock, flags);
+                               if (pcpu_extend_area_map(chunk,
+                                                        new_alloc) < 0) {
+                                       err = "failed to extend area map";
+                                       goto fail_unlock_mutex;
+                               }
+                               spin_lock_irqsave(&pcpu_lock, flags);
+                               /*
+                                * pcpu_lock has been dropped, need to
+                                * restart cpu_slot list walking.
+                                */
+                               goto restart;
                        }
 
                        off = pcpu_alloc_area(chunk, size, align);