Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6
authorLinus Torvalds <torvalds@woody.linux-foundation.org>
Sat, 9 Jun 2007 01:14:42 +0000 (18:14 -0700)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Sat, 9 Jun 2007 01:14:42 +0000 (18:14 -0700)
* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6:
  OHCI: Fix machine check in ohci_hub_status_data
  USB: Fix up bogus bInterval values in endpoint descriptors
  USB: cxacru: ignore error trying to start ADSL in atm_start
  USB: cxacru: create sysfs attributes in atm_start instead of bind
  USB: cxacru: add Documentation file
  USB: UNUSUAL_DEV: Sync up some reported devices from Ubuntu
  USB: usb gadgets avoid le{16,32}_to_cpup()
  usblp: Don't let suspend to kill ->used
  USB: set default y for CONFIG_USB_DEVICE_CLASS

45 files changed:
Documentation/SubmittingPatches
Documentation/atomic_ops.txt
Documentation/driver-model/platform.txt
Documentation/feature-removal-schedule.txt
Documentation/filesystems/tmpfs.txt
Documentation/firmware_class/README
Documentation/firmware_class/firmware_sample_driver.c
Documentation/firmware_class/firmware_sample_firmware_class.c
MAINTAINERS
arch/i386/math-emu/fpu_entry.c
arch/m68knommu/platform/5307/timers.c
arch/ppc/syslib/qspan_pci.c
arch/sh64/kernel/pci_sh5.c
arch/um/Kconfig
arch/um/drivers/line.c
arch/um/drivers/stderr_console.c
arch/um/drivers/ubd_kern.c
arch/um/kernel/exitcode.c
arch/x86_64/kernel/traps.c
arch/x86_64/mm/init.c
drivers/ata/sata_promise.c
drivers/base/class.c
drivers/base/core.c
drivers/base/dd.c
drivers/base/firmware_class.c
drivers/block/loop.c
drivers/cdrom/mcdx.c
drivers/char/stallion.c
drivers/isdn/hardware/eicon/divasfunc.c
drivers/tc/zs.c
fs/binfmt_flat.c
include/linux/console_struct.h
include/linux/kernel.h
include/linux/sched.h
include/linux/slub_def.h
kernel/exit.c
kernel/futex.c
kernel/rtmutex.c
lib/hexdump.c
lib/kobject.c
mm/shmem.c
mm/slab.c
mm/slub.c
mm/sparse.c
scripts/checkpatch.pl

index d91125ab6f49253fece7bc6e056cd248ec7812ec..0958e97d4bf4326ad0f6bc6418263f403d168eda 100644 (file)
@@ -340,8 +340,32 @@ now, but you can do this to mark internal company procedures or just
 point out some special detail about the sign-off. 
 
 
+13) When to use Acked-by:
 
-13) The canonical patch format
+The Signed-off-by: tag indicates that the signer was involved in the
+development of the patch, or that he/she was in the patch's delivery path.
+
+If a person was not directly involved in the preparation or handling of a
+patch but wishes to signify and record their approval of it then they can
+arrange to have an Acked-by: line added to the patch's changelog.
+
+Acked-by: is often used by the maintainer of the affected code when that
+maintainer neither contributed to nor forwarded the patch.
+
+Acked-by: is not as formal as Signed-off-by:.  It is a record that the acker
+has at least reviewed the patch and has indicated acceptance.  Hence patch
+mergers will sometimes manually convert an acker's "yep, looks good to me"
+into an Acked-by:.
+
+Acked-by: does not necessarily indicate acknowledgement of the entire patch.
+For example, if a patch affects multiple subsystems and has an Acked-by: from
+one subsystem maintainer then this usually indicates acknowledgement of just
+the part which affects that maintainer's code.  Judgement should be used here.
+ When in doubt people should refer to the original discussion in the mailing
+list archives.
+
+
+14) The canonical patch format
 
 The canonical patch subject line is:
 
index 2a63d5662a93a1fd2e0889bc6aab93c1ae987102..05851e9982edfefbab5ead5b774ab976926a12e4 100644 (file)
@@ -149,7 +149,7 @@ defined which accomplish this:
        void smp_mb__before_atomic_dec(void);
        void smp_mb__after_atomic_dec(void);
        void smp_mb__before_atomic_inc(void);
-       void smp_mb__after_atomic_dec(void);
+       void smp_mb__after_atomic_inc(void);
 
 For example, smp_mb__before_atomic_dec() can be used like so:
 
index 19c4a6e136760750365483d49751edb4853daad6..2a97320ee17f1d1b1c5a9b1efc138bbea4631f0e 100644 (file)
@@ -96,6 +96,46 @@ System setup also associates those clocks with the device, so that that
 calls to clk_get(&pdev->dev, clock_name) return them as needed.
 
 
+Legacy Drivers:  Device Probing
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Some drivers are not fully converted to the driver model, because they take
+on a non-driver role:  the driver registers its platform device, rather than
+leaving that for system infrastructure.  Such drivers can't be hotplugged
+or coldplugged, since those mechanisms require device creation to be in a
+different system component than the driver.
+
+The only "good" reason for this is to handle older system designs which, like
+original IBM PCs, rely on error-prone "probe-the-hardware" models for hardware
+configuration.  Newer systems have largely abandoned that model, in favor of
+bus-level support for dynamic configuration (PCI, USB), or device tables
+provided by the boot firmware (e.g. PNPACPI on x86).  There are too many
+conflicting options about what might be where, and even educated guesses by
+an operating system will be wrong often enough to make trouble.
+
+This style of driver is discouraged.  If you're updating such a driver,
+please try to move the device enumeration to a more appropriate location,
+outside the driver.  This will usually be cleanup, since such drivers
+tend to already have "normal" modes, such as ones using device nodes that
+were created by PNP or by platform device setup.
+
+None the less, there are some APIs to support such legacy drivers.  Avoid
+using these calls except with such hotplug-deficient drivers.
+
+       struct platform_device *platform_device_alloc(
+                       char *name, unsigned id);
+
+You can use platform_device_alloc() to dynamically allocate a device, which
+you will then initialize with resources and platform_device_register().
+A better solution is usually:
+
+       struct platform_device *platform_device_register_simple(
+                       char *name, unsigned id,
+                       struct resource *res, unsigned nres);
+
+You can use platform_device_register_simple() as a one-step call to allocate
+and register a device.
+
+
 Device Naming and Driver Binding
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 The platform_device.dev.bus_id is the canonical name for the devices.
index 49ae1ea9e868d9d0803e8d2711748be45cc1a546..7d3f205b0ba50fddc8da631ba9fad29063239256 100644 (file)
@@ -104,6 +104,7 @@ Who:        Dominik Brodowski <linux@brodo.de>
 What:  remove EXPORT_SYMBOL(kernel_thread)
 When:  August 2006
 Files: arch/*/kernel/*_ksyms.c
+Funcs: kernel_thread
 Why:   kernel_thread is a low-level implementation detail.  Drivers should
         use the <linux/kthread.h> API instead which shields them from
        implementation details and provides a higherlevel interface that
index 6dd050878a2087269b9891f704177dc7f1dc1462..145e44086358653e4b8b6b17302f3b7652246194 100644 (file)
@@ -94,10 +94,10 @@ largest node numbers in the range.  For example, mpol=bind:0-3,5,7,9-15
 
 Note that trying to mount a tmpfs with an mpol option will fail if the
 running kernel does not support NUMA; and will fail if its nodelist
-specifies a node >= MAX_NUMNODES.  If your system relies on that tmpfs
-being mounted, but from time to time runs a kernel built without NUMA
-capability (perhaps a safe recovery kernel), or configured to support
-fewer nodes, then it is advisable to omit the mpol option from automatic
+specifies a node which is not online.  If your system relies on that
+tmpfs being mounted, but from time to time runs a kernel built without
+NUMA capability (perhaps a safe recovery kernel), or with fewer nodes
+online, then it is advisable to omit the mpol option from automatic
 mount options.  It can be added later, when the tmpfs is already mounted
 on MountPoint, by 'mount -o remount,mpol=Policy:NodeList MountPoint'.
 
@@ -121,4 +121,4 @@ RAM/SWAP in 10240 inodes and it is only accessible by root.
 Author:
    Christoph Rohland <cr@sap.com>, 1.12.01
 Updated:
-   Hugh Dickins <hugh@veritas.com>, 19 February 2006
+   Hugh Dickins <hugh@veritas.com>, 4 June 2007
index e9cc8bb26f7d0952b0226c66e6a43abe8e00a211..c3480aa66ba8048bf46483544ed6fb3ebb7151eb 100644 (file)
@@ -1,7 +1,7 @@
 
  request_firmware() hotplug interface:
  ------------------------------------
-       Copyright (C) 2003 Manuel Estrada Sainz <ranty@debian.org>
+       Copyright (C) 2003 Manuel Estrada Sainz
 
  Why:
  ---
index 87feccdb5c9f8f67b2739358edca07c76a9a24a1..6865cbe075ec3549cf033fa3c11c07bb0ee4eef6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * firmware_sample_driver.c -
  *
- * Copyright (c) 2003 Manuel Estrada Sainz <ranty@debian.org>
+ * Copyright (c) 2003 Manuel Estrada Sainz
  *
  * Sample code on how to use request_firmware() from drivers.
  *
index 9e1b0e4051cd0546985b9985fd308d301d537c41..4994f1f28f8ce23bf56ec61976cbefe19c008d41 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * firmware_sample_firmware_class.c -
  *
- * Copyright (c) 2003 Manuel Estrada Sainz <ranty@debian.org>
+ * Copyright (c) 2003 Manuel Estrada Sainz
  *
  * NOTE: This is just a probe of concept, if you think that your driver would
  * be well served by this mechanism please contact me first.
@@ -19,7 +19,7 @@
 #include <linux/firmware.h>
 
 
-MODULE_AUTHOR("Manuel Estrada Sainz <ranty@debian.org>");
+MODULE_AUTHOR("Manuel Estrada Sainz");
 MODULE_DESCRIPTION("Hackish sample for using firmware class directly");
 MODULE_LICENSE("GPL");
 
index f3b5a391e074822b9303d8bd06e5743efbddacaa..4c715a7e059a70f914ad49f9d6b747964e129c5f 100644 (file)
@@ -782,11 +782,6 @@ M: rathamahata@php4.ru
 L:     linux-kernel@vger.kernel.org
 S:     Maintained
 
-BERKSHIRE PRODUCTS PC WATCHDOG DRIVER
-P:     Kenji Hollis
-W:     http://ftp.bitgate.com/pcwd/
-S:     Maintained
-
 BFS FILE SYSTEM
 P:     Tigran A. Aivazian
 M:     tigran@aivazian.fsnet.co.uk
@@ -3025,7 +3020,7 @@ S:        Maintained
 REISERFS FILE SYSTEM
 P:     Hans Reiser
 M:     reiserfs-dev@namesys.com
-L:     reiserfs-list@namesys.com
+L:     reiserfs-devel@vger.kernel.org
 W:     http://www.namesys.com
 S:     Supported
 
@@ -3904,10 +3899,6 @@ S:       Maintained
 
 UCLINUX FOR NEC V850
 P:     Miles Bader
-M:     uclinux-v850@lsi.nec.co.jp
-W:     http://www.ic.nec.co.jp/micro/uclinux/eng/
-W:     http://www.ee.nec.de/uclinux/
-S:     Supported
 
 UCLINUX FOR RENESAS H8/300
 P:     Yoshinori Sato
@@ -3916,10 +3907,10 @@ W:      http://uclinux-h8.sourceforge.jp/
 S:     Supported
 
 UFS FILESYSTEM
-P: Evgeniy Dushistov
-M: dushistov@mail.ru
-L: linux-kernel@vger.kernel.org
-S: Maintained
+P:     Evgeniy Dushistov
+M:     dushistov@mail.ru
+L:     linux-kernel@vger.kernel.org
+S:     Maintained
 
 USB DIAMOND RIO500 DRIVER
 P:     Cesar Miquel
index ddf8fa3bbd01d7c15ef03abf6c7c55c5356ebd57..1853524c8b576f5420de5cbd746aecb30f594d50 100644 (file)
@@ -754,7 +754,7 @@ int save_i387_soft(void *s387, struct _fpstate __user * buf)
     return -1;
   if ( offset )
     if (__copy_to_user(d+other, (u_char *)&S387->st_space, offset))
-      return -1
+      return -1;
   RE_ENTRANT_CHECK_ON;
 
   return 1;
index 92e58070b01664f31d10625b02822ddc2ede3bff..fb66eadd589633cf02ecc9e9f89dffe395a808ef 100644 (file)
@@ -62,10 +62,13 @@ void coldfire_tick(void)
 
 /***************************************************************************/
 
+static int ticks_per_intr;
+
 void coldfire_timer_init(irq_handler_t handler)
 {
        __raw_writew(MCFTIMER_TMR_DISABLE, TA(MCFTIMER_TMR));
-       __raw_writetrr(((MCF_BUSCLK / 16) / HZ), TA(MCFTIMER_TRR));
+       ticks_per_intr = (MCF_BUSCLK / 16) / HZ;
+       __raw_writetrr(ticks_per_intr - 1, TA(MCFTIMER_TRR));
        __raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 |
                MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, TA(MCFTIMER_TMR));
 
@@ -81,11 +84,10 @@ void coldfire_timer_init(irq_handler_t handler)
 
 unsigned long coldfire_timer_offset(void)
 {
-       unsigned long trr, tcn, offset;
+       unsigned long tcn, offset;
 
        tcn = __raw_readw(TA(MCFTIMER_TCN));
-       trr = __raw_readtrr(TA(MCFTIMER_TRR));
-       offset = (tcn * (1000000 / HZ)) / trr;
+       offset = ((tcn + 1) * (1000000 / HZ)) / ticks_per_intr;
 
        /* Check if we just wrapped the counters and maybe missed a tick */
        if ((offset < (1000000 / HZ / 2)) && mcf_timerirqpending(1))
index 85053b2816a9dd9a40a394ca5cc7299118f13953..7a97c7440b30267f84e45b2773e85bd8f545bdd0 100644 (file)
@@ -365,13 +365,13 @@ int qspan_pcibios_find_class(unsigned int class_code, unsigned short index,
 }
 
 void __init
-m8xx_pcibios_fixup(void))
+m8xx_pcibios_fixup(void)
 {
    /* Lots to do here, all board and configuration specific. */
 }
 
 void __init
-m8xx_setup_pci_ptrs(void))
+m8xx_setup_pci_ptrs(void)
 {
        set_config_access_method(qspan);
 
index fb51660847c8380e92b315099c659b432f86f191..3334f99b5835f0a113514fa3e25dcf886690dbd5 100644 (file)
@@ -521,10 +521,10 @@ void __init pcibios_fixup_bus(struct pci_bus *bus)
                bus->resource[0]->start = PCIBIOS_MIN_IO;
                bus->resource[1]->start = PCIBIOS_MIN_MEM;
 #else
-               bus->resource[0]->end = 0
-               bus->resource[1]->end = 0
-               bus->resource[0]->start =0
-                 bus->resource[1]->start = 0;
+               bus->resource[0]->end = 0;
+               bus->resource[1]->end = 0;
+               bus->resource[0]->start =0;
+               bus->resource[1]->start = 0;
 #endif
                /* Turn off downstream PF memory address range by default */
                bus->resource[2]->start = 1024*1024;
index c504312219b42b8f9797c50fe1569e5f05163a84..e6ff30266542a79b8909a5ef5f4e7991e58e16ca 100644 (file)
@@ -278,6 +278,7 @@ config HIGHMEM
 config KERNEL_STACK_ORDER
        int "Kernel stack size order"
        default 1 if 64BIT
+       range 1 10 if 64BIT
        default 0 if !64BIT
        help
        This option determines the size of UML kernel stacks.  They will
index ced99106f7982b84a13eed11a71890f04ba4ae2e..4bd40bb43ec27f3935306fb784e84bdf160172a4 100644 (file)
@@ -3,6 +3,7 @@
  * Licensed under the GPL
  */
 
+#include "linux/kernel.h"
 #include "linux/sched.h"
 #include "linux/slab.h"
 #include "linux/list.h"
index 911539293871d271ed306c36fd1b113f6acc9203..4739dd527b43ab8ff5cf59ab007cfbbd033b90d8 100644 (file)
@@ -1,3 +1,4 @@
+#include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/console.h>
 
index 70509ddaac035cd60537e286883614323410be6d..2e09f162c42f01b6ac39f3689eae208f5d4b75b1 100644 (file)
@@ -20,6 +20,7 @@
 #define MAJOR_NR UBD_MAJOR
 #define UBD_SHIFT 4
 
+#include "linux/kernel.h"
 #include "linux/module.h"
 #include "linux/blkdev.h"
 #include "linux/hdreg.h"
index 8b7f2cdedf945148ffd96306ac04024dc9a0a7ee..c716b5a6db13d9552a59e7f7ec5688229ca9bf0e 100644 (file)
@@ -1,8 +1,9 @@
-/* 
+/*
  * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
  * Licensed under the GPL
  */
 
+#include "linux/kernel.h"
 #include "linux/init.h"
 #include "linux/ctype.h"
 #include "linux/proc_fs.h"
@@ -24,11 +25,14 @@ static int read_proc_exitcode(char *page, char **start, off_t off,
        val = uml_exitcode;
        len = sprintf(page, "%d\n", val);
        len -= off;
-       if(len <= off+count) *eof = 1;
+       if(len <= off+count)
+               *eof = 1;
        *start = page + off;
-       if(len > count) len = count;
-       if(len < 0) len = 0;
-       return(len);
+       if(len > count)
+               len = count;
+       if(len < 0)
+               len = 0;
+       return len;
 }
 
 static int write_proc_exitcode(struct file *file, const char __user *buffer,
@@ -38,12 +42,14 @@ static int write_proc_exitcode(struct file *file, const char __user *buffer,
        int tmp;
 
        if(copy_from_user(buf, buffer, count))
-               return(-EFAULT);
+               return -EFAULT;
+
        tmp = simple_strtol(buf, &end, 0);
        if((*end != '\0') && !isspace(*end))
-               return(-EINVAL);
+               return -EINVAL;
+
        uml_exitcode = tmp;
-       return(count);
+       return count;
 }
 
 static int make_proc_exitcode(void)
@@ -54,24 +60,13 @@ static int make_proc_exitcode(void)
        if(ent == NULL){
                printk(KERN_WARNING "make_proc_exitcode : Failed to register "
                       "/proc/exitcode\n");
-               return(0);
+               return 0;
        }
 
        ent->read_proc = read_proc_exitcode;
        ent->write_proc = write_proc_exitcode;
-       
-       return(0);
+
+       return 0;
 }
 
 __initcall(make_proc_exitcode);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index cb29fb96948dd2653886e2fe444fb35ea55dae48..aac1c0be54c6b8f99c032f61f6b29f904d91977d 100644 (file)
@@ -465,13 +465,14 @@ static unsigned int die_nest_count;
 
 unsigned __kprobes long oops_begin(void)
 {
-       int cpu = smp_processor_id();
+       int cpu;
        unsigned long flags;
 
        oops_enter();
 
        /* racy, but better than risking deadlock. */
        local_irq_save(flags);
+       cpu = smp_processor_id();
        if (!spin_trylock(&die_lock)) { 
                if (cpu == die_owner) 
                        /* nested oops. should stop eventually */;
index 1ad5111aec381d7042648c0a871f2707181f3400..efb6e845114ec727430860981b03b22495f9d299 100644 (file)
@@ -79,6 +79,8 @@ void show_mem(void)
                        if (unlikely(i % MAX_ORDER_NR_PAGES == 0)) {
                                touch_nmi_watchdog();
                        }
+                       if (!pfn_valid(pgdat->node_start_pfn + i))
+                               continue;
                        page = pfn_to_page(pgdat->node_start_pfn + i);
                        total++;
                        if (PageReserved(page))
index 2b924a69b365cfda37d7b6acd705c2b567672e84..6dc0b011a6b7c5a10febc2a0242c5dc431939a23 100644 (file)
@@ -784,9 +784,12 @@ static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc)
                if (qc->dev->flags & ATA_DFLAG_CDB_INTR)
                        break;
                /*FALLTHROUGH*/
+       case ATA_PROT_NODATA:
+               if (qc->tf.flags & ATA_TFLAG_POLLING)
+                       break;
+               /*FALLTHROUGH*/
        case ATA_PROT_ATAPI_DMA:
        case ATA_PROT_DMA:
-       case ATA_PROT_NODATA:
                pdc_packet_start(qc);
                return 0;
 
@@ -800,7 +803,7 @@ static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc)
 static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
 {
        WARN_ON (tf->protocol == ATA_PROT_DMA ||
-                tf->protocol == ATA_PROT_NODATA);
+                tf->protocol == ATA_PROT_ATAPI_DMA);
        ata_tf_load(ap, tf);
 }
 
@@ -808,7 +811,7 @@ static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
 static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
 {
        WARN_ON (tf->protocol == ATA_PROT_DMA ||
-                tf->protocol == ATA_PROT_NODATA);
+                tf->protocol == ATA_PROT_ATAPI_DMA);
        ata_exec_command(ap, tf);
 }
 
index 20c4ea6eb50d0a8836e2f89af145fc88634c02ba..8c506dbe39138bc11b8901944a81461c5a424e79 100644 (file)
@@ -369,36 +369,6 @@ char *make_class_name(const char *name, struct kobject *kobj)
        return class_name;
 }
 
-static int deprecated_class_uevent(char **envp, int num_envp, int *cur_index,
-                                  char *buffer, int buffer_size,
-                                  int *cur_len,
-                                  struct class_device *class_dev)
-{
-       struct device *dev = class_dev->dev;
-       char *path;
-
-       if (!dev)
-               return 0;
-
-       /* add device, backing this class device (deprecated) */
-       path = kobject_get_path(&dev->kobj, GFP_KERNEL);
-
-       add_uevent_var(envp, num_envp, cur_index, buffer, buffer_size,
-                      cur_len, "PHYSDEVPATH=%s", path);
-       kfree(path);
-
-       if (dev->bus)
-               add_uevent_var(envp, num_envp, cur_index,
-                              buffer, buffer_size, cur_len,
-                              "PHYSDEVBUS=%s", dev->bus->name);
-
-       if (dev->driver)
-               add_uevent_var(envp, num_envp, cur_index,
-                              buffer, buffer_size, cur_len,
-                              "PHYSDEVDRIVER=%s", dev->driver->name);
-       return 0;
-}
-
 static int make_deprecated_class_device_links(struct class_device *class_dev)
 {
        char *class_name;
@@ -430,11 +400,6 @@ static void remove_deprecated_class_device_links(struct class_device *class_dev)
        kfree(class_name);
 }
 #else
-static inline int deprecated_class_uevent(char **envp, int num_envp,
-                                         int *cur_index, char *buffer,
-                                         int buffer_size, int *cur_len,
-                                         struct class_device *class_dev)
-{ return 0; }
 static inline int make_deprecated_class_device_links(struct class_device *cd)
 { return 0; }
 static void remove_deprecated_class_device_links(struct class_device *cd)
@@ -445,15 +410,13 @@ static int class_uevent(struct kset *kset, struct kobject *kobj, char **envp,
                         int num_envp, char *buffer, int buffer_size)
 {
        struct class_device *class_dev = to_class_dev(kobj);
+       struct device *dev = class_dev->dev;
        int i = 0;
        int length = 0;
        int retval = 0;
 
        pr_debug("%s - name = %s\n", __FUNCTION__, class_dev->class_id);
 
-       deprecated_class_uevent(envp, num_envp, &i, buffer, buffer_size,
-                               &length, class_dev);
-
        if (MAJOR(class_dev->devt)) {
                add_uevent_var(envp, num_envp, &i,
                               buffer, buffer_size, &length,
@@ -464,6 +427,26 @@ static int class_uevent(struct kset *kset, struct kobject *kobj, char **envp,
                               "MINOR=%u", MINOR(class_dev->devt));
        }
 
+       if (dev) {
+               const char *path = kobject_get_path(&dev->kobj, GFP_KERNEL);
+               if (path) {
+                       add_uevent_var(envp, num_envp, &i,
+                                      buffer, buffer_size, &length,
+                                      "PHYSDEVPATH=%s", path);
+                       kfree(path);
+               }
+
+               if (dev->bus)
+                       add_uevent_var(envp, num_envp, &i,
+                                      buffer, buffer_size, &length,
+                                      "PHYSDEVBUS=%s", dev->bus->name);
+
+               if (dev->driver)
+                       add_uevent_var(envp, num_envp, &i,
+                                      buffer, buffer_size, &length,
+                                      "PHYSDEVDRIVER=%s", dev->driver->name);
+       }
+
        /* terminate, set to next free slot, shrink available space */
        envp[i] = NULL;
        envp = &envp[i];
index b78fc1e68264872a196c6a7b1e454b080a9831bd..dd40d78a023dd1f2fde9712ac7700d5ade4893cf 100644 (file)
@@ -180,10 +180,12 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp,
                        const char *path;
 
                        path = kobject_get_path(&parent->kobj, GFP_KERNEL);
-                       add_uevent_var(envp, num_envp, &i,
-                                      buffer, buffer_size, &length,
-                                      "PHYSDEVPATH=%s", path);
-                       kfree(path);
+                       if (path) {
+                               add_uevent_var(envp, num_envp, &i,
+                                              buffer, buffer_size, &length,
+                                              "PHYSDEVPATH=%s", path);
+                               kfree(path);
+                       }
 
                        add_uevent_var(envp, num_envp, &i,
                                       buffer, buffer_size, &length,
index 92428e55b0c210a8c00cf8e656a934fa9e21f2d3..b0088b0efecdd1e5395e4104d23d0fe34dbb9a0d 100644 (file)
@@ -207,19 +207,6 @@ static int __device_attach(struct device_driver * drv, void * data)
        return driver_probe_device(drv, dev);
 }
 
-static int device_probe_drivers(void *data)
-{
-       struct device *dev = data;
-       int ret = 0;
-
-       if (dev->bus) {
-               down(&dev->sem);
-               ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
-               up(&dev->sem);
-       }
-       return ret;
-}
-
 /**
  *     device_attach - try to attach device to a driver.
  *     @dev:   device.
index 97ab5bd1c4d62ebb72ef9babc07f2c35571c484b..89a5f4a5491391e2270069090f43c6e82b6ef601 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * firmware_class.c - Multi purpose firmware loading support
  *
- * Copyright (c) 2003 Manuel Estrada Sainz <ranty@debian.org>
+ * Copyright (c) 2003 Manuel Estrada Sainz
  *
  * Please see Documentation/firmware_class/ for more information.
  *
@@ -23,7 +23,7 @@
 
 #define to_dev(obj) container_of(obj, struct device, kobj)
 
-MODULE_AUTHOR("Manuel Estrada Sainz <ranty@debian.org>");
+MODULE_AUTHOR("Manuel Estrada Sainz");
 MODULE_DESCRIPTION("Multi purpose firmware loading support");
 MODULE_LICENSE("GPL");
 
index 5526eadb65926d4318b790a0ede84d9f272a7059..0ed5470d25339674a5c449feab66f5505db5f3c2 100644 (file)
@@ -1354,7 +1354,7 @@ static struct block_device_operations lo_fops = {
  */
 static int max_loop;
 module_param(max_loop, int, 0);
-MODULE_PARM_DESC(max_loop, "obsolete, loop device is created on-demand");
+MODULE_PARM_DESC(max_loop, "Maximum number of loop devices");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_BLOCKDEV_MAJOR(LOOP_MAJOR);
 
@@ -1394,16 +1394,11 @@ int loop_unregister_transfer(int number)
 EXPORT_SYMBOL(loop_register_transfer);
 EXPORT_SYMBOL(loop_unregister_transfer);
 
-static struct loop_device *loop_init_one(int i)
+static struct loop_device *loop_alloc(int i)
 {
        struct loop_device *lo;
        struct gendisk *disk;
 
-       list_for_each_entry(lo, &loop_devices, lo_list) {
-               if (lo->lo_number == i)
-                       return lo;
-       }
-
        lo = kzalloc(sizeof(*lo), GFP_KERNEL);
        if (!lo)
                goto out;
@@ -1427,8 +1422,6 @@ static struct loop_device *loop_init_one(int i)
        disk->private_data      = lo;
        disk->queue             = lo->lo_queue;
        sprintf(disk->disk_name, "loop%d", i);
-       add_disk(disk);
-       list_add_tail(&lo->lo_list, &loop_devices);
        return lo;
 
 out_free_queue:
@@ -1439,15 +1432,37 @@ out:
        return NULL;
 }
 
-static void loop_del_one(struct loop_device *lo)
+static void loop_free(struct loop_device *lo)
 {
-       del_gendisk(lo->lo_disk);
        blk_cleanup_queue(lo->lo_queue);
        put_disk(lo->lo_disk);
        list_del(&lo->lo_list);
        kfree(lo);
 }
 
+static struct loop_device *loop_init_one(int i)
+{
+       struct loop_device *lo;
+
+       list_for_each_entry(lo, &loop_devices, lo_list) {
+               if (lo->lo_number == i)
+                       return lo;
+       }
+
+       lo = loop_alloc(i);
+       if (lo) {
+               add_disk(lo->lo_disk);
+               list_add_tail(&lo->lo_list, &loop_devices);
+       }
+       return lo;
+}
+
+static void loop_del_one(struct loop_device *lo)
+{
+       del_gendisk(lo->lo_disk);
+       loop_free(lo);
+}
+
 static struct kobject *loop_probe(dev_t dev, int *part, void *data)
 {
        struct loop_device *lo;
@@ -1464,28 +1479,77 @@ static struct kobject *loop_probe(dev_t dev, int *part, void *data)
 
 static int __init loop_init(void)
 {
-       if (register_blkdev(LOOP_MAJOR, "loop"))
-               return -EIO;
-       blk_register_region(MKDEV(LOOP_MAJOR, 0), 1UL << MINORBITS,
-                                 THIS_MODULE, loop_probe, NULL, NULL);
+       int i, nr;
+       unsigned long range;
+       struct loop_device *lo, *next;
+
+       /*
+        * loop module now has a feature to instantiate underlying device
+        * structure on-demand, provided that there is an access dev node.
+        * However, this will not work well with user space tool that doesn't
+        * know about such "feature".  In order to not break any existing
+        * tool, we do the following:
+        *
+        * (1) if max_loop is specified, create that many upfront, and this
+        *     also becomes a hard limit.
+        * (2) if max_loop is not specified, create 8 loop device on module
+        *     load, user can further extend loop device by create dev node
+        *     themselves and have kernel automatically instantiate actual
+        *     device on-demand.
+        */
+       if (max_loop > 1UL << MINORBITS)
+               return -EINVAL;
 
        if (max_loop) {
-               printk(KERN_INFO "loop: the max_loop option is obsolete "
-                                "and will be removed in March 2008\n");
+               nr = max_loop;
+               range = max_loop;
+       } else {
+               nr = 8;
+               range = 1UL << MINORBITS;
+       }
+
+       if (register_blkdev(LOOP_MAJOR, "loop"))
+               return -EIO;
 
+       for (i = 0; i < nr; i++) {
+               lo = loop_alloc(i);
+               if (!lo)
+                       goto Enomem;
+               list_add_tail(&lo->lo_list, &loop_devices);
        }
+
+       /* point of no return */
+
+       list_for_each_entry(lo, &loop_devices, lo_list)
+               add_disk(lo->lo_disk);
+
+       blk_register_region(MKDEV(LOOP_MAJOR, 0), range,
+                                 THIS_MODULE, loop_probe, NULL, NULL);
+
        printk(KERN_INFO "loop: module loaded\n");
        return 0;
+
+Enomem:
+       printk(KERN_INFO "loop: out of memory\n");
+
+       list_for_each_entry_safe(lo, next, &loop_devices, lo_list)
+               loop_free(lo);
+
+       unregister_blkdev(LOOP_MAJOR, "loop");
+       return -ENOMEM;
 }
 
 static void __exit loop_exit(void)
 {
+       unsigned long range;
        struct loop_device *lo, *next;
 
+       range = max_loop ? max_loop :  1UL << MINORBITS;
+
        list_for_each_entry_safe(lo, next, &loop_devices, lo_list)
                loop_del_one(lo);
 
-       blk_unregister_region(MKDEV(LOOP_MAJOR, 0), 1UL << MINORBITS);
+       blk_unregister_region(MKDEV(LOOP_MAJOR, 0), range);
        if (unregister_blkdev(LOOP_MAJOR, "loop"))
                printk(KERN_WARNING "loop: cannot unregister blkdev\n");
 }
index f574962f4288d36233491eb0d98f8968e2d0da2b..4310cc84dfedb4c3b59dc20751e91ed076ace202 100644 (file)
@@ -1053,11 +1053,11 @@ static void __exit mcdx_exit(void)
        if (unregister_blkdev(MAJOR_NR, "mcdx") != 0) {
                xwarn("cleanup() unregister_blkdev() failed\n");
        }
-       blk_cleanup_queue(mcdx_queue);
 #if !MCDX_QUIET
        else
        xinfo("cleanup() succeeded\n");
 #endif
+       blk_cleanup_queue(mcdx_queue);
 }
 
 #ifdef MODULE
index e45113a7a472f7f1035d3fd92b2909b237bd298b..45bf2a262a858c144c74388f271bfb13cb4e9b9a 100644 (file)
@@ -2172,11 +2172,12 @@ static int __devinit stl_initech(struct stlbrd *brdp)
                }
                status = inb(ioaddr + ECH_PNLSTATUS);
                if ((status & ECH_PNLIDMASK) != nxtid)
-                       goto err_fr;
+                       break;
                panelp = kzalloc(sizeof(struct stlpanel), GFP_KERNEL);
                if (!panelp) {
                        printk("STALLION: failed to allocate memory "
                                "(size=%Zd)\n", sizeof(struct stlpanel));
+                       retval = -ENOMEM;
                        goto err_fr;
                }
                panelp->magic = STL_PANELMAGIC;
@@ -2223,8 +2224,10 @@ static int __devinit stl_initech(struct stlbrd *brdp)
                brdp->nrports += panelp->nrports;
                brdp->panels[panelnr++] = panelp;
                if ((brdp->brdtype != BRD_ECHPCI) &&
-                   (ioaddr >= (brdp->ioaddr2 + brdp->iosize2)))
+                   (ioaddr >= (brdp->ioaddr2 + brdp->iosize2))) {
+                       retval = -EINVAL;
                        goto err_fr;
+               }
        }
 
        brdp->nrpanels = panelnr;
@@ -2371,6 +2374,7 @@ static int __devinit stl_pciprobe(struct pci_dev *pdev,
                dev_err(&pdev->dev, "too many boards found, "
                        "maximum supported %d\n", STL_MAXBRDS);
                mutex_unlock(&stl_brdslock);
+               retval = -ENODEV;
                goto err_fr;
        }
        brdp->brdnr = (unsigned int)brdnr;
@@ -4710,6 +4714,29 @@ static int __init stallion_module_init(void)
        spin_lock_init(&stallion_lock);
        spin_lock_init(&brd_lock);
 
+       stl_serial = alloc_tty_driver(STL_MAXBRDS * STL_MAXPORTS);
+       if (!stl_serial) {
+               retval = -ENOMEM;
+               goto err;
+       }
+
+       stl_serial->owner = THIS_MODULE;
+       stl_serial->driver_name = stl_drvname;
+       stl_serial->name = "ttyE";
+       stl_serial->major = STL_SERIALMAJOR;
+       stl_serial->minor_start = 0;
+       stl_serial->type = TTY_DRIVER_TYPE_SERIAL;
+       stl_serial->subtype = SERIAL_TYPE_NORMAL;
+       stl_serial->init_termios = stl_deftermios;
+       stl_serial->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+       tty_set_operations(stl_serial, &stl_ops);
+
+       retval = tty_register_driver(stl_serial);
+       if (retval) {
+               printk("STALLION: failed to register serial driver\n");
+               goto err_frtty;
+       }
+
 /*
  *     Find any dynamically supported boards. That is via module load
  *     line options.
@@ -4739,13 +4766,9 @@ static int __init stallion_module_init(void)
 
        /* this has to be _after_ isa finding because of locking */
        retval = pci_register_driver(&stl_pcidriver);
-       if (retval && stl_nrbrds == 0)
-               goto err;
-
-       stl_serial = alloc_tty_driver(STL_MAXBRDS * STL_MAXPORTS);
-       if (!stl_serial) {
-               retval = -ENOMEM;
-               goto err_pcidr;
+       if (retval && stl_nrbrds == 0) {
+               printk(KERN_ERR "STALLION: can't register pci driver\n");
+               goto err_unrtty;
        }
 
 /*
@@ -4756,43 +4779,18 @@ static int __init stallion_module_init(void)
                printk("STALLION: failed to register serial board device\n");
 
        stallion_class = class_create(THIS_MODULE, "staliomem");
-       if (IS_ERR(stallion_class)) {
-               retval = PTR_ERR(stallion_class);
-               goto err_reg;
-       }
+       if (IS_ERR(stallion_class))
+               printk("STALLION: failed to create class\n");
        for (i = 0; i < 4; i++)
                class_device_create(stallion_class, NULL,
                                    MKDEV(STL_SIOMEMMAJOR, i), NULL,
                                    "staliomem%d", i);
 
-       stl_serial->owner = THIS_MODULE;
-       stl_serial->driver_name = stl_drvname;
-       stl_serial->name = "ttyE";
-       stl_serial->major = STL_SERIALMAJOR;
-       stl_serial->minor_start = 0;
-       stl_serial->type = TTY_DRIVER_TYPE_SERIAL;
-       stl_serial->subtype = SERIAL_TYPE_NORMAL;
-       stl_serial->init_termios = stl_deftermios;
-       stl_serial->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
-       tty_set_operations(stl_serial, &stl_ops);
-
-       retval = tty_register_driver(stl_serial);
-       if (retval) {
-               printk("STALLION: failed to register serial driver\n");
-               goto err_clsdev;
-       }
-
        return 0;
-err_clsdev:
-       for (i = 0; i < 4; i++)
-               class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i));
-       class_destroy(stallion_class);
-err_reg:
-       unregister_chrdev(STL_SIOMEMMAJOR, "staliomem");
+err_unrtty:
+       tty_unregister_driver(stl_serial);
+err_frtty:
        put_tty_driver(stl_serial);
-err_pcidr:
-       pci_unregister_driver(&stl_pcidriver);
-       stl_free_isabrds();
 err:
        return retval;
 }
@@ -4821,8 +4819,6 @@ static void __exit stallion_module_exit(void)
                        tty_unregister_device(stl_serial,
                                brdp->brdnr * STL_MAXPORTS + j);
        }
-       tty_unregister_driver(stl_serial);
-       put_tty_driver(stl_serial);
 
        for (i = 0; i < 4; i++)
                class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i));
@@ -4834,6 +4830,9 @@ static void __exit stallion_module_exit(void)
        pci_unregister_driver(&stl_pcidriver);
 
        stl_free_isabrds();
+
+       tty_unregister_driver(stl_serial);
+       put_tty_driver(stl_serial);
 }
 
 module_init(stallion_module_init);
index 46fc21a3f8ff232038298c3c8dc8e8720f954f3c..d36a4c09e25db2b5d8ee558ab2bf31664455e508 100644 (file)
@@ -195,7 +195,7 @@ static int DIVA_INIT_FUNCTION connect_didd(void)
 /*
  * disconnect from didd
  */
-static void DIVA_EXIT_FUNCTION disconnect_didd(void)
+static void disconnect_didd(void)
 {
        IDI_SYNC_REQ req;
 
index 3524e3fc08b91ed27316748dc5ea528e3f7d61a0..61de78a9f6ee76156523e7041b04fd8b3b8434dd 100644 (file)
@@ -2182,7 +2182,7 @@ struct dec_serial_hook zs_kgdbhook = {
        .init_info      = kgdbhook_init_info,
        .rx_char        = kgdbhook_rx_char,
        .cflags         = B38400 | CS8 | CLOCAL,
-}
+};
 
 void __init zs_kgdb_hook(int tty_num)
 {
index 7b0265d7f3a84a88f537b8e9174a27e4c3e650b6..861141b4f6d6f4cbbfcd96366074db8e4adbeaf3 100644 (file)
@@ -558,7 +558,7 @@ static int load_flat_file(struct linux_binprm * bprm,
                        if (!realdatastart)
                                realdatastart = (unsigned long) -ENOMEM;
                        printk("Unable to allocate RAM for process data, errno %d\n",
-                                       (int)-datapos);
+                                       (int)-realdatastart);
                        do_munmap(current->mm, textpos, text_len);
                        ret = realdatastart;
                        goto err;
index a461f76fb004e874f38ec245c6a6834b333a5004..dc77fed7b28566c585ccc2193f14dfdea8227421 100644 (file)
@@ -9,6 +9,9 @@
  * to achieve effects such as fast scrolling by changing the origin.
  */
 
+#ifndef _LINUX_CONSOLE_STRUCT_H
+#define _LINUX_CONSOLE_STRUCT_H
+
 #include <linux/wait.h>
 #include <linux/vt.h>
 #include <linux/workqueue.h>
@@ -130,3 +133,5 @@ extern void vc_SAK(struct work_struct *work);
 #define CUR_DEFAULT CUR_UNDERLINE
 
 #define CON_IS_VISIBLE(conp) (*conp->vc_display_fg == conp)
+
+#endif /* _LINUX_CONSOLE_STRUCT_H */
index 45353d757cd0f1ca57cc266aaf228c549fcfbf48..7a485250591491089549455a60c944aa4be0a5ff 100644 (file)
@@ -218,10 +218,14 @@ enum {
        DUMP_PREFIX_ADDRESS,
        DUMP_PREFIX_OFFSET
 };
-extern void hex_dump_to_buffer(const void *buf, size_t len, char *linebuf,
-                               size_t linebuflen);
-extern void print_hex_dump(const char *level, int prefix_type,
-                               void *buf, size_t len);
+extern void hex_dump_to_buffer(const void *buf, size_t len,
+                               int rowsize, int groupsize,
+                               char *linebuf, size_t linebuflen, bool ascii);
+extern void print_hex_dump(const char *level, const char *prefix_str,
+                               int prefix_type, int rowsize, int groupsize,
+                               void *buf, size_t len, bool ascii);
+extern void print_hex_dump_bytes(const char *prefix_str, int prefix_type,
+                       void *buf, size_t len);
 #define hex_asc(x)     "0123456789abcdef"[x]
 
 #ifdef DEBUG
index d58e74b98367c756e488b1ce3cf88903e078b7e0..693f0e6c54d47595c6f3268d0e20b5de74303d90 100644 (file)
@@ -1162,6 +1162,7 @@ static inline void put_task_struct(struct task_struct *t)
                                        /* Not implemented yet, only for 486*/
 #define PF_STARTING    0x00000002      /* being created */
 #define PF_EXITING     0x00000004      /* getting shut down */
+#define PF_EXITPIDONE  0x00000008      /* pi exit done on shut down */
 #define PF_FORKNOEXEC  0x00000040      /* forked but didn't exec */
 #define PF_SUPERPRIV   0x00000100      /* used super-user privileges */
 #define PF_DUMPCORE    0x00000200      /* dumped core */
index 0764c829d967ab8c1841cddf79ba51204956e4a8..a0ad37463d623ec1a933c7bc7c3cb8c966b15ff6 100644 (file)
@@ -70,11 +70,8 @@ extern struct kmem_cache kmalloc_caches[KMALLOC_SHIFT_HIGH + 1];
  */
 static inline int kmalloc_index(size_t size)
 {
-       /*
-        * We should return 0 if size == 0 but we use the smallest object
-        * here for SLAB legacy reasons.
-        */
-       WARN_ON_ONCE(size == 0);
+       if (!size)
+               return 0;
 
        if (size > KMALLOC_MAX_SIZE)
                return -1;
@@ -153,13 +150,25 @@ static inline struct kmem_cache *kmalloc_slab(size_t size)
 #define SLUB_DMA 0
 #endif
 
+
+/*
+ * ZERO_SIZE_PTR will be returned for zero sized kmalloc requests.
+ *
+ * Dereferencing ZERO_SIZE_PTR will lead to a distinct access fault.
+ *
+ * ZERO_SIZE_PTR can be passed to kfree though in the same way that NULL can.
+ * Both make kfree a no-op.
+ */
+#define ZERO_SIZE_PTR ((void *)16)
+
+
 static inline void *kmalloc(size_t size, gfp_t flags)
 {
        if (__builtin_constant_p(size) && !(flags & SLUB_DMA)) {
                struct kmem_cache *s = kmalloc_slab(size);
 
                if (!s)
-                       return NULL;
+                       return ZERO_SIZE_PTR;
 
                return kmem_cache_alloc(s, flags);
        } else
@@ -172,7 +181,7 @@ static inline void *kzalloc(size_t size, gfp_t flags)
                struct kmem_cache *s = kmalloc_slab(size);
 
                if (!s)
-                       return NULL;
+                       return ZERO_SIZE_PTR;
 
                return kmem_cache_zalloc(s, flags);
        } else
@@ -188,7 +197,7 @@ static inline void *kmalloc_node(size_t size, gfp_t flags, int node)
                struct kmem_cache *s = kmalloc_slab(size);
 
                if (!s)
-                       return NULL;
+                       return ZERO_SIZE_PTR;
 
                return kmem_cache_alloc_node(s, flags, node);
        } else
index 5b888c24e43e0ce650e554c5cec34a99f699c1fd..5c8ecbaa19a530cc4d417a897457b0d0318bc39b 100644 (file)
@@ -892,13 +892,29 @@ fastcall NORET_TYPE void do_exit(long code)
        if (unlikely(tsk->flags & PF_EXITING)) {
                printk(KERN_ALERT
                        "Fixing recursive fault but reboot is needed!\n");
+               /*
+                * We can do this unlocked here. The futex code uses
+                * this flag just to verify whether the pi state
+                * cleanup has been done or not. In the worst case it
+                * loops once more. We pretend that the cleanup was
+                * done as there is no way to return. Either the
+                * OWNER_DIED bit is set by now or we push the blocked
+                * task into the wait for ever nirwana as well.
+                */
+               tsk->flags |= PF_EXITPIDONE;
                if (tsk->io_context)
                        exit_io_context();
                set_current_state(TASK_UNINTERRUPTIBLE);
                schedule();
        }
 
+       /*
+        * tsk->flags are checked in the futex code to protect against
+        * an exiting task cleaning up the robust pi futexes.
+        */
+       spin_lock_irq(&tsk->pi_lock);
        tsk->flags |= PF_EXITING;
+       spin_unlock_irq(&tsk->pi_lock);
 
        if (unlikely(in_atomic()))
                printk(KERN_INFO "note: %s[%d] exited with preempt_count %d\n",
@@ -912,7 +928,7 @@ fastcall NORET_TYPE void do_exit(long code)
        }
        group_dead = atomic_dec_and_test(&tsk->signal->live);
        if (group_dead) {
-               hrtimer_cancel(&tsk->signal->real_timer);
+               hrtimer_cancel(&tsk->signal->real_timer);
                exit_itimers(tsk->signal);
        }
        acct_collect(code, group_dead);
@@ -965,6 +981,12 @@ fastcall NORET_TYPE void do_exit(long code)
         * Make sure we are holding no locks:
         */
        debug_check_no_locks_held(tsk);
+       /*
+        * We can do this unlocked here. The futex code uses this flag
+        * just to verify whether the pi state cleanup has been done
+        * or not. In the worst case it loops once more.
+        */
+       tsk->flags |= PF_EXITPIDONE;
 
        if (tsk->io_context)
                exit_io_context();
index b7ce15c67e324b468d13599d47df7423adcd69d4..3b7f7713d9a4148e4ee0c9e9a748be0009b7d5c7 100644 (file)
@@ -430,10 +430,6 @@ static struct task_struct * futex_find_get_task(pid_t pid)
                p = NULL;
                goto out_unlock;
        }
-       if (p->exit_state != 0) {
-               p = NULL;
-               goto out_unlock;
-       }
        get_task_struct(p);
 out_unlock:
        rcu_read_unlock();
@@ -502,7 +498,7 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb,
        struct futex_q *this, *next;
        struct plist_head *head;
        struct task_struct *p;
-       pid_t pid;
+       pid_t pid = uval & FUTEX_TID_MASK;
 
        head = &hb->chain;
 
@@ -520,6 +516,8 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb,
                                return -EINVAL;
 
                        WARN_ON(!atomic_read(&pi_state->refcount));
+                       WARN_ON(pid && pi_state->owner &&
+                               pi_state->owner->pid != pid);
 
                        atomic_inc(&pi_state->refcount);
                        *ps = pi_state;
@@ -530,15 +528,33 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb,
 
        /*
         * We are the first waiter - try to look up the real owner and attach
-        * the new pi_state to it, but bail out when the owner died bit is set
-        * and TID = 0:
+        * the new pi_state to it, but bail out when TID = 0
         */
-       pid = uval & FUTEX_TID_MASK;
-       if (!pid && (uval & FUTEX_OWNER_DIED))
+       if (!pid)
                return -ESRCH;
        p = futex_find_get_task(pid);
-       if (!p)
-               return -ESRCH;
+       if (IS_ERR(p))
+               return PTR_ERR(p);
+
+       /*
+        * We need to look at the task state flags to figure out,
+        * whether the task is exiting. To protect against the do_exit
+        * change of the task flags, we do this protected by
+        * p->pi_lock:
+        */
+       spin_lock_irq(&p->pi_lock);
+       if (unlikely(p->flags & PF_EXITING)) {
+               /*
+                * The task is on the way out. When PF_EXITPIDONE is
+                * set, we know that the task has finished the
+                * cleanup:
+                */
+               int ret = (p->flags & PF_EXITPIDONE) ? -ESRCH : -EAGAIN;
+
+               spin_unlock_irq(&p->pi_lock);
+               put_task_struct(p);
+               return ret;
+       }
 
        pi_state = alloc_pi_state();
 
@@ -551,7 +567,6 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb,
        /* Store the key for possible exit cleanups: */
        pi_state->key = *key;
 
-       spin_lock_irq(&p->pi_lock);
        WARN_ON(!list_empty(&pi_state->list));
        list_add(&pi_state->list, &p->pi_state_list);
        pi_state->owner = p;
@@ -618,6 +633,8 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this)
         * preserve the owner died bit.)
         */
        if (!(uval & FUTEX_OWNER_DIED)) {
+               int ret = 0;
+
                newval = FUTEX_WAITERS | new_owner->pid;
                /* Keep the FUTEX_WAITER_REQUEUED flag if it was set */
                newval |= (uval & FUTEX_WAITER_REQUEUED);
@@ -625,10 +642,15 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this)
                pagefault_disable();
                curval = futex_atomic_cmpxchg_inatomic(uaddr, uval, newval);
                pagefault_enable();
+
                if (curval == -EFAULT)
-                       return -EFAULT;
+                       ret = -EFAULT;
                if (curval != uval)
-                       return -EINVAL;
+                       ret = -EINVAL;
+               if (ret) {
+                       spin_unlock(&pi_state->pi_mutex.wait_lock);
+                       return ret;
+               }
        }
 
        spin_lock_irq(&pi_state->owner->pi_lock);
@@ -1174,7 +1196,7 @@ static int futex_requeue(u32 __user *uaddr1, struct rw_semaphore *fshared,
 #ifdef CONFIG_DEBUG_PI_LIST
                                this->list.plist.lock = &hb2->lock;
 #endif
-                       }
+                       }
                        this->key = key2;
                        get_futex_key_refs(&key2);
                        drop_count++;
@@ -1326,12 +1348,10 @@ static void unqueue_me_pi(struct futex_q *q)
 /*
  * Fixup the pi_state owner with current.
  *
- * The cur->mm semaphore must be  held, it is released at return of this
- * function.
+ * Must be called with hash bucket lock held and mm->sem held for non
+ * private futexes.
  */
-static int fixup_pi_state_owner(u32 __user *uaddr, struct rw_semaphore *fshared,
-                               struct futex_q *q,
-                               struct futex_hash_bucket *hb,
+static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
                                struct task_struct *curr)
 {
        u32 newtid = curr->pid | FUTEX_WAITERS;
@@ -1355,23 +1375,24 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct rw_semaphore *fshared,
        list_add(&pi_state->list, &curr->pi_state_list);
        spin_unlock_irq(&curr->pi_lock);
 
-       /* Unqueue and drop the lock */
-       unqueue_me_pi(q);
-       if (fshared)
-               up_read(fshared);
        /*
         * We own it, so we have to replace the pending owner
         * TID. This must be atomic as we have preserve the
         * owner died bit here.
         */
-       ret = get_user(uval, uaddr);
+       ret = get_futex_value_locked(&uval, uaddr);
+
        while (!ret) {
                newval = (uval & FUTEX_OWNER_DIED) | newtid;
                newval |= (uval & FUTEX_WAITER_REQUEUED);
+
+               pagefault_disable();
                curval = futex_atomic_cmpxchg_inatomic(uaddr,
                                                       uval, newval);
+               pagefault_enable();
+
                if (curval == -EFAULT)
-                       ret = -EFAULT;
+                       ret = -EFAULT;
                if (curval == uval)
                        break;
                uval = curval;
@@ -1553,10 +1574,7 @@ static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
                         */
                        uaddr = q.pi_state->key.uaddr;
 
-                       /* mmap_sem and hash_bucket lock are unlocked at
-                          return of this function */
-                       ret = fixup_pi_state_owner(uaddr, fshared,
-                                                  &q, hb, curr);
+                       ret = fixup_pi_state_owner(uaddr, &q, curr);
                } else {
                        /*
                         * Catch the rare case, where the lock was released
@@ -1567,12 +1585,13 @@ static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
                                if (rt_mutex_trylock(&q.pi_state->pi_mutex))
                                        ret = 0;
                        }
-                       /* Unqueue and drop the lock */
-                       unqueue_me_pi(&q);
-                       if (fshared)
-                               up_read(fshared);
                }
 
+               /* Unqueue and drop the lock */
+               unqueue_me_pi(&q);
+               if (fshared)
+                       up_read(fshared);
+
                debug_rt_mutex_free_waiter(&q.waiter);
 
                return ret;
@@ -1688,7 +1707,7 @@ static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared,
        struct futex_hash_bucket *hb;
        u32 uval, newval, curval;
        struct futex_q q;
-       int ret, lock_held, attempt = 0;
+       int ret, lock_taken, ownerdied = 0, attempt = 0;
 
        if (refill_pi_state_cache())
                return -ENOMEM;
@@ -1709,10 +1728,11 @@ static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared,
        if (unlikely(ret != 0))
                goto out_release_sem;
 
+ retry_unlocked:
        hb = queue_lock(&q, -1, NULL);
 
  retry_locked:
-       lock_held = 0;
+       ret = lock_taken = 0;
 
        /*
         * To avoid races, we attempt to take the lock here again
@@ -1728,43 +1748,44 @@ static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared,
        if (unlikely(curval == -EFAULT))
                goto uaddr_faulted;
 
-       /* We own the lock already */
+       /*
+        * Detect deadlocks. In case of REQUEUE_PI this is a valid
+        * situation and we return success to user space.
+        */
        if (unlikely((curval & FUTEX_TID_MASK) == current->pid)) {
-               if (!detect && 0)
-                       force_sig(SIGKILL, current);
-               /*
-                * Normally, this check is done in user space.
-                * In case of requeue, the owner may attempt to lock this futex,
-                * even if the ownership has already been given by the previous
-                * waker.
-                * In the usual case, this is a case of deadlock, but not in case
-                * of REQUEUE_PI.
-                */
                if (!(curval & FUTEX_WAITER_REQUEUED))
                        ret = -EDEADLK;
                goto out_unlock_release_sem;
        }
 
        /*
-        * Surprise - we got the lock. Just return
-        * to userspace:
+        * Surprise - we got the lock. Just return to userspace:
         */
        if (unlikely(!curval))
                goto out_unlock_release_sem;
 
        uval = curval;
+
        /*
-        * In case of a requeue, check if there already is an owner
-        * If not, just take the futex.
+        * Set the WAITERS flag, so the owner will know it has someone
+        * to wake at next unlock
         */
-       if ((curval & FUTEX_WAITER_REQUEUED) && !(curval & FUTEX_TID_MASK)) {
-               /* set current as futex owner */
-               newval = curval | current->pid;
-               lock_held = 1;
-       } else
-               /* Set the WAITERS flag, so the owner will know it has someone
-                  to wake at next unlock */
-               newval = curval | FUTEX_WAITERS;
+       newval = curval | FUTEX_WAITERS;
+
+       /*
+        * There are two cases, where a futex might have no owner (the
+        * owner TID is 0): OWNER_DIED or REQUEUE. We take over the
+        * futex in this case. We also do an unconditional take over,
+        * when the owner of the futex died.
+        *
+        * This is safe as we are protected by the hash bucket lock !
+        */
+       if (unlikely(ownerdied || !(curval & FUTEX_TID_MASK))) {
+               /* Keep the OWNER_DIED and REQUEUE bits */
+               newval = (curval & ~FUTEX_TID_MASK) | current->pid;
+               ownerdied = 0;
+               lock_taken = 1;
+       }
 
        pagefault_disable();
        curval = futex_atomic_cmpxchg_inatomic(uaddr, uval, newval);
@@ -1775,8 +1796,13 @@ static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared,
        if (unlikely(curval != uval))
                goto retry_locked;
 
-       if (lock_held) {
-               set_pi_futex_owner(hb, &q.key, curr);
+       /*
+        * We took the lock due to requeue or owner died take over.
+        */
+       if (unlikely(lock_taken)) {
+               /* For requeue we need to fixup the pi_futex */
+               if (curval & FUTEX_WAITER_REQUEUED)
+                       set_pi_futex_owner(hb, &q.key, curr);
                goto out_unlock_release_sem;
        }
 
@@ -1787,34 +1813,40 @@ static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared,
        ret = lookup_pi_state(uval, hb, &q.key, &q.pi_state);
 
        if (unlikely(ret)) {
-               /*
-                * There were no waiters and the owner task lookup
-                * failed. When the OWNER_DIED bit is set, then we
-                * know that this is a robust futex and we actually
-                * take the lock. This is safe as we are protected by
-                * the hash bucket lock. We also set the waiters bit
-                * unconditionally here, to simplify glibc handling of
-                * multiple tasks racing to acquire the lock and
-                * cleanup the problems which were left by the dead
-                * owner.
-                */
-               if (curval & FUTEX_OWNER_DIED) {
-                       uval = newval;
-                       newval = current->pid |
-                               FUTEX_OWNER_DIED | FUTEX_WAITERS;
+               switch (ret) {
 
-                       pagefault_disable();
-                       curval = futex_atomic_cmpxchg_inatomic(uaddr,
-                                                              uval, newval);
-                       pagefault_enable();
+               case -EAGAIN:
+                       /*
+                        * Task is exiting and we just wait for the
+                        * exit to complete.
+                        */
+                       queue_unlock(&q, hb);
+                       if (fshared)
+                               up_read(fshared);
+                       cond_resched();
+                       goto retry;
 
-                       if (unlikely(curval == -EFAULT))
+               case -ESRCH:
+                       /*
+                        * No owner found for this futex. Check if the
+                        * OWNER_DIED bit is set to figure out whether
+                        * this is a robust futex or not.
+                        */
+                       if (get_futex_value_locked(&curval, uaddr))
                                goto uaddr_faulted;
-                       if (unlikely(curval != uval))
+
+                       /*
+                        * We simply start over in case of a robust
+                        * futex. The code above will take the futex
+                        * and return happy.
+                        */
+                       if (curval & FUTEX_OWNER_DIED) {
+                               ownerdied = 1;
                                goto retry_locked;
-                       ret = 0;
+                       }
+               default:
+                       goto out_unlock_release_sem;
                }
-               goto out_unlock_release_sem;
        }
 
        /*
@@ -1845,31 +1877,42 @@ static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared,
                down_read(fshared);
        spin_lock(q.lock_ptr);
 
-       /*
-        * Got the lock. We might not be the anticipated owner if we
-        * did a lock-steal - fix up the PI-state in that case.
-        */
-       if (!ret && q.pi_state->owner != curr)
-               /* mmap_sem is unlocked at return of this function */
-               ret = fixup_pi_state_owner(uaddr, fshared, &q, hb, curr);
-       else {
+       if (!ret) {
+               /*
+                * Got the lock. We might not be the anticipated owner
+                * if we did a lock-steal - fix up the PI-state in
+                * that case:
+                */
+               if (q.pi_state->owner != curr)
+                       ret = fixup_pi_state_owner(uaddr, &q, curr);
+       } else {
                /*
                 * Catch the rare case, where the lock was released
-                * when we were on the way back before we locked
-                * the hash bucket.
+                * when we were on the way back before we locked the
+                * hash bucket.
                 */
-               if (ret && q.pi_state->owner == curr) {
-                       if (rt_mutex_trylock(&q.pi_state->pi_mutex))
-                               ret = 0;
+               if (q.pi_state->owner == curr &&
+                   rt_mutex_trylock(&q.pi_state->pi_mutex)) {
+                       ret = 0;
+               } else {
+                       /*
+                        * Paranoia check. If we did not take the lock
+                        * in the trylock above, then we should not be
+                        * the owner of the rtmutex, neither the real
+                        * nor the pending one:
+                        */
+                       if (rt_mutex_owner(&q.pi_state->pi_mutex) == curr)
+                               printk(KERN_ERR "futex_lock_pi: ret = %d "
+                                      "pi-mutex: %p pi-state %p\n", ret,
+                                      q.pi_state->pi_mutex.owner,
+                                      q.pi_state->owner);
                }
-               /* Unqueue and drop the lock */
-               unqueue_me_pi(&q);
-               if (fshared)
-                       up_read(fshared);
        }
 
-       if (!detect && ret == -EDEADLK && 0)
-               force_sig(SIGKILL, current);
+       /* Unqueue and drop the lock */
+       unqueue_me_pi(&q);
+       if (fshared)
+               up_read(fshared);
 
        return ret != -EINTR ? ret : -ERESTARTNOINTR;
 
@@ -1887,16 +1930,19 @@ static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared,
         * non-atomically.  Therefore, if get_user below is not
         * enough, we need to handle the fault ourselves, while
         * still holding the mmap_sem.
+        *
+        * ... and hb->lock. :-) --ANK
         */
+       queue_unlock(&q, hb);
+
        if (attempt++) {
                ret = futex_handle_fault((unsigned long)uaddr, fshared,
                                         attempt);
                if (ret)
-                       goto out_unlock_release_sem;
-               goto retry_locked;
+                       goto out_release_sem;
+               goto retry_unlocked;
        }
 
-       queue_unlock(&q, hb);
        if (fshared)
                up_read(fshared);
 
@@ -1940,9 +1986,9 @@ retry:
                goto out;
 
        hb = hash_futex(&key);
+retry_unlocked:
        spin_lock(&hb->lock);
 
-retry_locked:
        /*
         * To avoid races, try to do the TID -> 0 atomic transition
         * again. If it succeeds then we can return without waking
@@ -2005,16 +2051,19 @@ pi_faulted:
         * non-atomically.  Therefore, if get_user below is not
         * enough, we need to handle the fault ourselves, while
         * still holding the mmap_sem.
+        *
+        * ... and hb->lock. --ANK
         */
+       spin_unlock(&hb->lock);
+
        if (attempt++) {
                ret = futex_handle_fault((unsigned long)uaddr, fshared,
                                         attempt);
                if (ret)
-                       goto out_unlock;
-               goto retry_locked;
+                       goto out;
+               goto retry_unlocked;
        }
 
-       spin_unlock(&hb->lock);
        if (fshared)
                up_read(fshared);
 
index 12879f6c1ec3b9a53069690f0205082ea581565c..a6fbb41305210c9d3d45c56a670f3fe96af6ce64 100644 (file)
@@ -189,6 +189,19 @@ int rt_mutex_adjust_prio_chain(struct task_struct *task,
        if (!waiter || !waiter->task)
                goto out_unlock_pi;
 
+       /*
+        * Check the orig_waiter state. After we dropped the locks,
+        * the previous owner of the lock might have released the lock
+        * and made us the pending owner:
+        */
+       if (orig_waiter && !orig_waiter->task)
+               goto out_unlock_pi;
+
+       /*
+        * Drop out, when the task has no waiters. Note,
+        * top_waiter can be NULL, when we are in the deboosting
+        * mode!
+        */
        if (top_waiter && (!task_has_pi_waiters(task) ||
                           top_waiter != task_top_pi_waiter(task)))
                goto out_unlock_pi;
@@ -636,9 +649,16 @@ rt_mutex_slowlock(struct rt_mutex *lock, int state,
                         * all over without going into schedule to try
                         * to get the lock now:
                         */
-                       if (unlikely(!waiter.task))
+                       if (unlikely(!waiter.task)) {
+                               /*
+                                * Reset the return value. We might
+                                * have returned with -EDEADLK and the
+                                * owner released the lock while we
+                                * were walking the pi chain.
+                                */
+                               ret = 0;
                                continue;
-
+                       }
                        if (unlikely(ret))
                                break;
                }
index e6da5b7fc29a1f7ad57842e6f477f096f45c89a7..473f5aed6caeebe88e813429a6e690e3c4ba42c9 100644 (file)
  * hex_dump_to_buffer - convert a blob of data to "hex ASCII" in memory
  * @buf: data blob to dump
  * @len: number of bytes in the @buf
+ * @rowsize: number of bytes to print per line; must be 16 or 32
+ * @groupsize: number of bytes to print at a time (1, 2, 4, 8; default = 1)
  * @linebuf: where to put the converted data
  * @linebuflen: total size of @linebuf, including space for terminating NUL
+ * @ascii: include ASCII after the hex output
  *
  * hex_dump_to_buffer() works on one "line" of output at a time, i.e.,
- * 16 bytes of input data converted to hex + ASCII output.
+ * 16 or 32 bytes of input data converted to hex + ASCII output.
  *
  * Given a buffer of u8 data, hex_dump_to_buffer() converts the input data
  * to a hex + ASCII dump at the supplied memory location.
  * The converted output is always NUL-terminated.
  *
  * E.g.:
- *     hex_dump_to_buffer(frame->data, frame->len, linebuf, sizeof(linebuf));
+ *   hex_dump_to_buffer(frame->data, frame->len, 16, 1,
+ *                     linebuf, sizeof(linebuf), 1);
  *
  * example output buffer:
- * 40414243 44454647 48494a4b 4c4d4e4f  @ABCDEFGHIJKLMNO
+ * 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f  @ABCDEFGHIJKLMNO
  */
-void hex_dump_to_buffer(const void *buf, size_t len, char *linebuf,
-                       size_t linebuflen)
+void hex_dump_to_buffer(const void *buf, size_t len, int rowsize,
+                       int groupsize, char *linebuf, size_t linebuflen,
+                       bool ascii)
 {
        const u8 *ptr = buf;
        u8 ch;
        int j, lx = 0;
+       int ascii_column;
 
-       for (j = 0; (j < 16) && (j < len) && (lx + 3) < linebuflen; j++) {
-               if (j && !(j % 4))
+       if (rowsize != 16 && rowsize != 32)
+               rowsize = 16;
+
+       if (!len)
+               goto nil;
+       if (len > rowsize)              /* limit to one line at a time */
+               len = rowsize;
+       if ((len % groupsize) != 0)     /* no mixed size output */
+               groupsize = 1;
+
+       switch (groupsize) {
+       case 8: {
+               const u64 *ptr8 = buf;
+               int ngroups = len / groupsize;
+
+               for (j = 0; j < ngroups; j++)
+                       lx += scnprintf(linebuf + lx, linebuflen - lx,
+                               "%16.16llx ", (unsigned long long)*(ptr8 + j));
+               ascii_column = 17 * ngroups + 2;
+               break;
+       }
+
+       case 4: {
+               const u32 *ptr4 = buf;
+               int ngroups = len / groupsize;
+
+               for (j = 0; j < ngroups; j++)
+                       lx += scnprintf(linebuf + lx, linebuflen - lx,
+                               "%8.8x ", *(ptr4 + j));
+               ascii_column = 9 * ngroups + 2;
+               break;
+       }
+
+       case 2: {
+               const u16 *ptr2 = buf;
+               int ngroups = len / groupsize;
+
+               for (j = 0; j < ngroups; j++)
+                       lx += scnprintf(linebuf + lx, linebuflen - lx,
+                               "%4.4x ", *(ptr2 + j));
+               ascii_column = 5 * ngroups + 2;
+               break;
+       }
+
+       default:
+               for (j = 0; (j < rowsize) && (j < len) && (lx + 4) < linebuflen;
+                    j++) {
+                       ch = ptr[j];
+                       linebuf[lx++] = hex_asc(ch >> 4);
+                       linebuf[lx++] = hex_asc(ch & 0x0f);
                        linebuf[lx++] = ' ';
-               ch = ptr[j];
-               linebuf[lx++] = hex_asc(ch >> 4);
-               linebuf[lx++] = hex_asc(ch & 0x0f);
+               }
+               ascii_column = 3 * rowsize + 2;
+               break;
        }
-       if ((lx + 2) < linebuflen) {
-               linebuf[lx++] = ' ';
+       if (!ascii)
+               goto nil;
+
+       while (lx < (linebuflen - 1) && lx < (ascii_column - 1))
                linebuf[lx++] = ' ';
-       }
-       for (j = 0; (j < 16) && (j < len) && (lx + 2) < linebuflen; j++)
+       for (j = 0; (j < rowsize) && (j < len) && (lx + 2) < linebuflen; j++)
                linebuf[lx++] = isprint(ptr[j]) ? ptr[j] : '.';
+nil:
        linebuf[lx++] = '\0';
 }
 EXPORT_SYMBOL(hex_dump_to_buffer);
@@ -59,46 +115,83 @@ EXPORT_SYMBOL(hex_dump_to_buffer);
 /**
  * print_hex_dump - print a text hex dump to syslog for a binary blob of data
  * @level: kernel log level (e.g. KERN_DEBUG)
+ * @prefix_str: string to prefix each line with;
+ *  caller supplies trailing spaces for alignment if desired
  * @prefix_type: controls whether prefix of an offset, address, or none
  *  is printed (%DUMP_PREFIX_OFFSET, %DUMP_PREFIX_ADDRESS, %DUMP_PREFIX_NONE)
+ * @rowsize: number of bytes to print per line; must be 16 or 32
+ * @groupsize: number of bytes to print at a time (1, 2, 4, 8; default = 1)
  * @buf: data blob to dump
  * @len: number of bytes in the @buf
+ * @ascii: include ASCII after the hex output
  *
  * Given a buffer of u8 data, print_hex_dump() prints a hex + ASCII dump
  * to the kernel log at the specified kernel log level, with an optional
  * leading prefix.
  *
+ * print_hex_dump() works on one "line" of output at a time, i.e.,
+ * 16 or 32 bytes of input data converted to hex + ASCII output.
+ * print_hex_dump() iterates over the entire input @buf, breaking it into
+ * "line size" chunks to format and print.
+ *
  * E.g.:
- *   print_hex_dump(KERN_DEBUG, DUMP_PREFIX_ADDRESS, frame->data, frame->len);
+ *   print_hex_dump(KERN_DEBUG, "raw data: ", DUMP_PREFIX_ADDRESS,
+ *             16, 1, frame->data, frame->len, 1);
  *
- * Example output using %DUMP_PREFIX_OFFSET:
- * 0009ab42: 40414243 44454647 48494a4b 4c4d4e4f  @ABCDEFGHIJKLMNO
- * Example output using %DUMP_PREFIX_ADDRESS:
- * ffffffff88089af0: 70717273 74757677 78797a7b 7c7d7e7f  pqrstuvwxyz{|}~.
+ * Example output using %DUMP_PREFIX_OFFSET and 1-byte mode:
+ * 0009ab42: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f  @ABCDEFGHIJKLMNO
+ * Example output using %DUMP_PREFIX_ADDRESS and 4-byte mode:
+ * ffffffff88089af0: 73727170 77767574 7b7a7978 7f7e7d7c  pqrstuvwxyz{|}~.
  */
-void print_hex_dump(const char *level, int prefix_type, void *buf, size_t len)
+void print_hex_dump(const char *level, const char *prefix_str, int prefix_type,
+                       int rowsize, int groupsize,
+                       void *buf, size_t len, bool ascii)
 {
        u8 *ptr = buf;
        int i, linelen, remaining = len;
-       unsigned char linebuf[100];
+       unsigned char linebuf[200];
 
-       for (i = 0; i < len; i += 16) {
-               linelen = min(remaining, 16);
-               remaining -= 16;
-               hex_dump_to_buffer(ptr + i, linelen, linebuf, sizeof(linebuf));
+       if (rowsize != 16 && rowsize != 32)
+               rowsize = 16;
+
+       for (i = 0; i < len; i += rowsize) {
+               linelen = min(remaining, rowsize);
+               remaining -= rowsize;
+               hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize,
+                               linebuf, sizeof(linebuf), ascii);
 
                switch (prefix_type) {
                case DUMP_PREFIX_ADDRESS:
-                       printk("%s%*p: %s\n", level,
+                       printk("%s%s%*p: %s\n", level, prefix_str,
                                (int)(2 * sizeof(void *)), ptr + i, linebuf);
                        break;
                case DUMP_PREFIX_OFFSET:
-                       printk("%s%.8x: %s\n", level, i, linebuf);
+                       printk("%s%s%.8x: %s\n", level, prefix_str, i, linebuf);
                        break;
                default:
-                       printk("%s%s\n", level, linebuf);
+                       printk("%s%s%s\n", level, prefix_str, linebuf);
                        break;
                }
        }
 }
 EXPORT_SYMBOL(print_hex_dump);
+
+/**
+ * print_hex_dump_bytes - shorthand form of print_hex_dump() with default params
+ * @prefix_str: string to prefix each line with;
+ *  caller supplies trailing spaces for alignment if desired
+ * @prefix_type: controls whether prefix of an offset, address, or none
+ *  is printed (%DUMP_PREFIX_OFFSET, %DUMP_PREFIX_ADDRESS, %DUMP_PREFIX_NONE)
+ * @buf: data blob to dump
+ * @len: number of bytes in the @buf
+ *
+ * Calls print_hex_dump(), with log level of KERN_DEBUG,
+ * rowsize of 16, groupsize of 1, and ASCII output included.
+ */
+void print_hex_dump_bytes(const char *prefix_str, int prefix_type,
+                       void *buf, size_t len)
+{
+       print_hex_dump(KERN_DEBUG, prefix_str, prefix_type, 16, 1,
+                       buf, len, 1);
+}
+EXPORT_SYMBOL(print_hex_dump_bytes);
index fc5f3f6e73299a27e394294efb4564dea3511c2c..ac1520651b9b457d89e96bd2447aae02d6f8bb46 100644 (file)
@@ -202,14 +202,14 @@ int kobject_shadow_add(struct kobject * kobj, struct dentry *shadow_parent)
 
                /* be noisy on error issues */
                if (error == -EEXIST)
-                       printk("kobject_add failed for %s with -EEXIST, "
-                              "don't try to register things with the "
-                              "same name in the same directory.\n",
+                       printk(KERN_ERR "kobject_add failed for %s with "
+                              "-EEXIST, don't try to register things with "
+                              "the same name in the same directory.\n",
                               kobject_name(kobj));
                else
-                       printk("kobject_add failed for %s (%d)\n",
+                       printk(KERN_ERR "kobject_add failed for %s (%d)\n",
                               kobject_name(kobj), error);
-                dump_stack();
+               dump_stack();
        }
 
        return error;
index e537317bec4d5d02977bf92021d87242e2ff549b..b6aae2b33393d96d694145326c6591acf6f83b4b 100644 (file)
@@ -967,6 +967,8 @@ static inline int shmem_parse_mpol(char *value, int *policy, nodemask_t *policy_
                *nodelist++ = '\0';
                if (nodelist_parse(nodelist, *policy_nodes))
                        goto out;
+               if (!nodes_subset(*policy_nodes, node_online_map))
+                       goto out;
        }
        if (!strcmp(value, "default")) {
                *policy = MPOL_DEFAULT;
index 2e71a328aa09540a75f83ab289a3da8931920914..6d65cf4e4b2e03fb1cbd860a1932ce0cd5cb2621 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -3539,7 +3539,7 @@ static inline void __cache_free(struct kmem_cache *cachep, void *objp)
        check_irq_off();
        objp = cache_free_debugcheck(cachep, objp, __builtin_return_address(0));
 
-       if (use_alien_caches && cache_free_alien(cachep, objp))
+       if (cache_free_alien(cachep, objp))
                return;
 
        if (likely(ac->avail < ac->limit)) {
index 51663a3c3c243c1afeaba27e21b7333808bc1cff..c9ab68881b43ebe8525fb2fa1e943f9810229c21 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -2241,7 +2241,7 @@ void *__kmalloc(size_t size, gfp_t flags)
 
        if (s)
                return slab_alloc(s, flags, -1, __builtin_return_address(0));
-       return NULL;
+       return ZERO_SIZE_PTR;
 }
 EXPORT_SYMBOL(__kmalloc);
 
@@ -2252,16 +2252,20 @@ void *__kmalloc_node(size_t size, gfp_t flags, int node)
 
        if (s)
                return slab_alloc(s, flags, node, __builtin_return_address(0));
-       return NULL;
+       return ZERO_SIZE_PTR;
 }
 EXPORT_SYMBOL(__kmalloc_node);
 #endif
 
 size_t ksize(const void *object)
 {
-       struct page *page = get_object_page(object);
+       struct page *page;
        struct kmem_cache *s;
 
+       if (object == ZERO_SIZE_PTR)
+               return 0;
+
+       page = get_object_page(object);
        BUG_ON(!page);
        s = page->slab;
        BUG_ON(!s);
@@ -2293,7 +2297,13 @@ void kfree(const void *x)
        struct kmem_cache *s;
        struct page *page;
 
-       if (!x)
+       /*
+        * This has to be an unsigned comparison. According to Linus
+        * some gcc version treat a pointer as a signed entity. Then
+        * this comparison would be true for all "negative" pointers
+        * (which would cover the whole upper half of the address space).
+        */
+       if ((unsigned long)x <= (unsigned long)ZERO_SIZE_PTR)
                return;
 
        page = virt_to_head_page(x);
@@ -2398,12 +2408,12 @@ void *krealloc(const void *p, size_t new_size, gfp_t flags)
        void *ret;
        size_t ks;
 
-       if (unlikely(!p))
+       if (unlikely(!p || p == ZERO_SIZE_PTR))
                return kmalloc(new_size, flags);
 
        if (unlikely(!new_size)) {
                kfree(p);
-               return NULL;
+               return ZERO_SIZE_PTR;
        }
 
        ks = ksize(p);
@@ -2652,7 +2662,7 @@ void *__kmalloc_track_caller(size_t size, gfp_t gfpflags, void *caller)
        struct kmem_cache *s = get_slab(size, gfpflags);
 
        if (!s)
-               return NULL;
+               return ZERO_SIZE_PTR;
 
        return slab_alloc(s, gfpflags, -1, caller);
 }
@@ -2663,7 +2673,7 @@ void *__kmalloc_node_track_caller(size_t size, gfp_t gfpflags,
        struct kmem_cache *s = get_slab(size, gfpflags);
 
        if (!s)
-               return NULL;
+               return ZERO_SIZE_PTR;
 
        return slab_alloc(s, gfpflags, node, caller);
 }
index 545e4d3afcdff14877204b270bf6e671c33d5509..e03b39f3540f79adf384c476f185e7a9da91e4ac 100644 (file)
@@ -240,6 +240,27 @@ static struct page __init *sparse_early_mem_map_alloc(unsigned long pnum)
        return NULL;
 }
 
+/*
+ * Allocate the accumulated non-linear sections, allocate a mem_map
+ * for each and record the physical to section mapping.
+ */
+void __init sparse_init(void)
+{
+       unsigned long pnum;
+       struct page *map;
+
+       for (pnum = 0; pnum < NR_MEM_SECTIONS; pnum++) {
+               if (!valid_section_nr(pnum))
+                       continue;
+
+               map = sparse_early_mem_map_alloc(pnum);
+               if (!map)
+                       continue;
+               sparse_init_one_section(__nr_to_section(pnum), pnum, map);
+       }
+}
+
+#ifdef CONFIG_MEMORY_HOTPLUG
 static struct page *__kmalloc_section_memmap(unsigned long nr_pages)
 {
        struct page *page, *ret;
@@ -279,27 +300,6 @@ static void __kfree_section_memmap(struct page *memmap, unsigned long nr_pages)
                           get_order(sizeof(struct page) * nr_pages));
 }
 
-/*
- * Allocate the accumulated non-linear sections, allocate a mem_map
- * for each and record the physical to section mapping.
- */
-void __init sparse_init(void)
-{
-       unsigned long pnum;
-       struct page *map;
-
-       for (pnum = 0; pnum < NR_MEM_SECTIONS; pnum++) {
-               if (!valid_section_nr(pnum))
-                       continue;
-
-               map = sparse_early_mem_map_alloc(pnum);
-               if (!map)
-                       continue;
-               sparse_init_one_section(__nr_to_section(pnum), pnum, map);
-       }
-}
-
-#ifdef CONFIG_MEMORY_HOTPLUG
 /*
  * returns the number of sections whose mem_maps were properly
  * set.  If this is <=0, then that means that the passed-in
index e216d49624b76afccae5ef6981fe270dc9caa15e..aea90d30d2292dc3427de4958a2e3b32ef374f85 100755 (executable)
@@ -1,14 +1,15 @@
 #!/usr/bin/perl -w
 # (c) 2001, Dave Jones. <davej@codemonkey.org.uk> (the file handling bit)
-# (c) 2005, Joel Scohpp <jschopp@austin.ibm.com> (the ugly bit)
+# (c) 2005, Joel Schopp <jschopp@austin.ibm.com> (the ugly bit)
 # (c) 2007, Andy Whitcroft <apw@uk.ibm.com> (new conditions, test suite, etc)
 # Licensed under the terms of the GNU GPL License version 2
 
 use strict;
 
 my $P = $0;
+$P =~ s@.*/@@g;
 
-my $V = '0.01';
+my $V = '0.04';
 
 use Getopt::Long qw(:config no_auto_abbrev);
 
@@ -26,7 +27,7 @@ GetOptions(
 my $exit = 0;
 
 if ($#ARGV < 0) {
-       print "usage: patchstylecheckemail.pl [options] patchfile\n";
+       print "usage: $P [options] patchfile\n";
        print "version: $V\n";
        print "options: -q           => quiet\n";
        print "         --no-tree    => run without a kernel tree\n";
@@ -38,7 +39,8 @@ if ($tree && !top_of_kernel_tree()) {
        exit(2);
 }
 
-my @deprecated = ();
+my @dep_includes = ();
+my @dep_functions = ();
 my $removal = 'Documentation/feature-removal-schedule.txt';
 if ($tree && -f $removal) {
        open(REMOVE, "<$removal") || die "$P: $removal: open failed - $!\n";
@@ -46,22 +48,27 @@ if ($tree && -f $removal) {
                if (/^Files:\s+(.*\S)/) {
                        for my $file (split(/[, ]+/, $1)) {
                                if ($file =~ m@include/(.*)@) {
-                                       push(@deprecated, $1);
+                                       push(@dep_includes, $1);
                                }
                        }
+
+               } elsif (/^Funcs:\s+(.*\S)/) {
+                       for my $func (split(/[, ]+/, $1)) {
+                               push(@dep_functions, $func);
+                       }
                }
        }
 }
 
-my @lines = ();
+my @rawlines = ();
 while (<>) {
        chomp;
-       push(@lines, $_);
+       push(@rawlines, $_);
        if (eof(ARGV)) {
-               if (!process($ARGV, @lines)) {
+               if (!process($ARGV, @rawlines)) {
                        $exit = 1;
                }
-               @lines = ();
+               @rawlines = ();
        }
 }
 
@@ -99,6 +106,130 @@ sub expand_tabs {
        return $res;
 }
 
+sub line_stats {
+       my ($line) = @_;
+
+       # Drop the diff line leader and expand tabs
+       $line =~ s/^.//;
+       $line = expand_tabs($line);
+
+       # Pick the indent from the front of the line.
+       my ($white) = ($line =~ /^(\s*)/);
+
+       return (length($line), length($white));
+}
+
+sub sanitise_line {
+       my ($line) = @_;
+
+       my $res = '';
+       my $l = '';
+
+       my $quote = '';
+
+       foreach my $c (split(//, $line)) {
+               if ($l ne "\\" && ($c eq "'" || $c eq '"')) {
+                       if ($quote eq '') {
+                               $quote = $c;
+                               $res .= $c;
+                               $l = $c;
+                               next;
+                       } elsif ($quote eq $c) {
+                               $quote = '';
+                       }
+               }
+               if ($quote && $c ne "\t") {
+                       $res .= "X";
+               } else {
+                       $res .= $c;
+               }
+
+               $l = $c;
+       }
+
+       return $res;
+}
+
+sub ctx_block_get {
+       my ($linenr, $remain, $outer) = @_;
+       my $line;
+       my $start = $linenr - 1;
+       my $blk = '';
+       my @o;
+       my @c;
+       my @res = ();
+
+       for ($line = $start; $remain > 0; $line++) {
+               next if ($rawlines[$line] =~ /^-/);
+               $remain--;
+
+               $blk .= $rawlines[$line];
+
+               @o = ($blk =~ /\{/g);
+               @c = ($blk =~ /\}/g);
+
+               if (!$outer || (scalar(@o) - scalar(@c)) == 1) {
+                       push(@res, $rawlines[$line]);
+               }
+
+               last if (scalar(@o) == scalar(@c));
+       }
+
+       return @res;
+}
+sub ctx_block_outer {
+       my ($linenr, $remain) = @_;
+
+       return ctx_block_get($linenr, $remain, 1);
+}
+sub ctx_block {
+       my ($linenr, $remain) = @_;
+
+       return ctx_block_get($linenr, $remain, 0);
+}
+
+sub ctx_locate_comment {
+       my ($first_line, $end_line) = @_;
+
+       # Catch a comment on the end of the line itself.
+       my ($current_comment) = ($rawlines[$end_line - 1] =~ m@.*(/\*.*\*/)\s*$@);
+       return $current_comment if (defined $current_comment);
+
+       # Look through the context and try and figure out if there is a
+       # comment.
+       my $in_comment = 0;
+       $current_comment = '';
+       for (my $linenr = $first_line; $linenr < $end_line; $linenr++) {
+               my $line = $rawlines[$linenr - 1];
+               #warn "           $line\n";
+               if ($linenr == $first_line and $line =~ m@^.\s*\*@) {
+                       $in_comment = 1;
+               }
+               if ($line =~ m@/\*@) {
+                       $in_comment = 1;
+               }
+               if (!$in_comment && $current_comment ne '') {
+                       $current_comment = '';
+               }
+               $current_comment .= $line . "\n" if ($in_comment);
+               if ($line =~ m@\*/@) {
+                       $in_comment = 0;
+               }
+       }
+
+       chomp($current_comment);
+       return($current_comment);
+}
+sub ctx_has_comment {
+       my ($first_line, $end_line) = @_;
+       my $cmt = ctx_locate_comment($first_line, $end_line);
+
+       ##print "LINE: $rawlines[$end_line - 1 ]\n";
+       ##print "CMMT: $cmt\n";
+
+       return ($cmt ne '');
+}
+
 sub cat_vet {
        my ($vet) = @_;
 
@@ -116,7 +247,7 @@ sub process {
        my $prevline="";
        my $stashline="";
 
-       my $lineforcounting='';
+       my $length;
        my $indent;
        my $previndent=0;
        my $stashindent=0;
@@ -139,13 +270,14 @@ sub process {
 #extract the filename as it passes
                if ($line=~/^\+\+\+\s+(\S+)/) {
                        $realfile=$1;
+                       $realfile =~ s@^[^/]*/@@;
                        $in_comment = 0;
                        next;
                }
 #extract the line range in the file after the patch is applied
                if ($line=~/^\@\@ -\d+,\d+ \+(\d+)(,(\d+))? \@\@/) {
                        $is_patch = 1;
-                       $first_line = 1;
+                       $first_line = $linenr + 1;
                        $in_comment = 0;
                        $realline=$1-1;
                        if (defined $2) {
@@ -156,10 +288,11 @@ sub process {
                        next;
                }
 
-#track the line number as we move through the hunk
-               if ($line=~/^[ \+]/) {
+# track the line number as we move through the hunk, note that
+# new versions of GNU diff omit the leading space on completely
+# blank context lines so we need to count that too.
+               if ($line =~ /^( |\+|$)/) {
                        $realline++;
-                       $realcnt-- if ($realcnt != 0);
 
                        # track any sort of multi-line comment.  Obviously if
                        # the added text or context do not include the whole
@@ -168,7 +301,7 @@ sub process {
                        # Guestimate if this is a continuing comment.  If this
                        # is the start of a diff block and this line starts
                        # ' *' then it is very likely a comment.
-                       if ($first_line and $line =~ m@^.\s*\*@) {
+                       if ($linenr == $first_line and $line =~ m@^.\s*\*@) {
                                $in_comment = 1;
                        }
                        if ($line =~ m@/\*@) {
@@ -178,23 +311,20 @@ sub process {
                                $in_comment = 0;
                        }
 
-                       $lineforcounting = $line;
-                       $lineforcounting =~ s/^\+//;
-                       $lineforcounting = expand_tabs($lineforcounting);
-
-                       my ($white) = ($lineforcounting =~ /^(\s*)/);
-                       $indent = length($white);
+                       # Measure the line length and indent.
+                       ($length, $indent) = line_stats($line);
 
                        # Track the previous line.
                        ($prevline, $stashline) = ($stashline, $line);
                        ($previndent, $stashindent) = ($stashindent, $indent);
-                       $first_line = 0;
                }
+               $realcnt-- if ($realcnt != 0);
 
 #make up the handle for any error we report on this line
-               $here = "PATCH: $ARGV:$linenr:";
-               $here .= "\nFILE: $realfile:$realline:" if ($realcnt != 0);
+               $here = "#$linenr: ";
+               $here .= "FILE: $realfile:$realline:" if ($realcnt != 0);
 
+               my $hereline = "$here\n$line\n";
                my $herecurr = "$here\n$line\n\n";
                my $hereprev = "$here\n$prevline\n$line\n\n";
 
@@ -203,6 +333,8 @@ sub process {
                        $signoff++;
 
                } elsif ($line =~ /^\s*signed-off-by:/i) {
+                       # This is a signoff, if ugly, so do not double report.
+                       $signoff++;
                        if (!($line =~ /^\s*Signed-off-by:/)) {
                                print "use Signed-off-by:\n";
                                print "$herecurr";
@@ -215,21 +347,28 @@ sub process {
                        }
                }
 
-#ignore lines not being added
-               if ($line=~/^[^\+]/) {next;}
+# Check for wrappage within a valid hunk of the file
+               if ($realcnt != 0 && $line !~ m{^(?:\+|-| |$)}) {
+                       print "patch seems to be corrupt (line wrapped?) [$realcnt]\n";
+                       print "$herecurr";
+                       $clean = 0;
+               }
+
+#ignore lines being removed
+               if ($line=~/^-/) {next;}
 
-# check we are in a valid source file *.[hcsS] if not then ignore this hunk
-               next if ($realfile !~ /\.[hcsS]$/);
+# check we are in a valid source file if not then ignore this hunk
+               next if ($realfile !~ /\.(h|c|s|S|pl|sh)$/);
 
 #trailing whitespace
-               if ($line=~/\S\s+$/) {
+               if ($line=~/\+.*\S\s+$/) {
                        my $herevet = "$here\n" . cat_vet($line) . "\n\n";
                        print "trailing whitespace\n";
                        print "$herevet";
                        $clean = 0;
                }
 #80 column limit
-               if (!($prevline=~/\/\*\*/) && length($lineforcounting) > 80) {
+               if ($line =~ /^\+/ && !($prevline=~/\/\*\*/) && $length > 80) {
                        print "line over 80 characters\n";
                        print "$herecurr";
                        $clean = 0;
@@ -253,19 +392,59 @@ sub process {
                #
                next if ($in_comment);
 
+               # Remove comments from the line before processing.
+               $line =~ s@/\*.*\*/@@g;
+               $line =~ s@/\*.*@@;
+               $line =~ s@.*\*/@@;
+
+               #
+               # Checks which may be anchored in the context.
+               #
+
+               # Check for switch () and associated case and default
+               # statements should be at the same indent.
+               if ($line=~/\bswitch\s*\(.*\)/) {
+                       my $err = '';
+                       my $sep = '';
+                       my @ctx = ctx_block_outer($linenr, $realcnt);
+                       shift(@ctx);
+                       for my $ctx (@ctx) {
+                               my ($clen, $cindent) = line_stats($ctx);
+                               if ($ctx =~ /^\+\s*(case\s+|default:)/ &&
+                                                       $indent != $cindent) {
+                                       $err .= "$sep$ctx\n";
+                                       $sep = '';
+                               } else {
+                                       $sep = "[...]\n";
+                               }
+                       }
+                       if ($err ne '') {
+                               print "switch and case should be at the same indent\n";
+                               print "$here\n$line\n$err\n";
+                               $clean = 0;
+                       }
+               }
+
+#ignore lines not being added
+               if ($line=~/^[^\+]/) {next;}
+
+               #
+               # Checks which are anchored on the added line.
+               #
+
 # no C99 // comments
-               if ($line =~ m@//@ and !($line =~ m@\".*//.*\"@)) {
+               if ($line =~ m{//}) {
                        print "do not use C99 // comments\n";
                        print "$herecurr";
                        $clean = 0;
                }
-
-               # Remove comments from the line before processing.
-               $line =~ s@/\*.*\*/@@g;
-               $line =~ s@/\*.*@@;
-               $line =~ s@.*\*/@@;
+               # Remove C99 comments.
                $line =~ s@//.*@@;
 
+               # Standardise the strings and chars within the input
+               # to simplify matching.
+               $line = sanitise_line($line);
+
 #EXPORT_SYMBOL should immediately follow its function closing }.
                if (($line =~ /EXPORT_SYMBOL.*\(.*\)/) ||
                    ($line =~ /EXPORT_UNUSED_SYMBOL.*\(.*\)/)) {
@@ -293,8 +472,28 @@ sub process {
                }
 
 # * goes on variable not on type
-               if ($line=~/[A-Za-z\d_]+\* [A-Za-z\d_]+/) {
-                       print "\"foo* bar\" should be \"foo *bar\"\n";
+               my $type = '(?:char|short|int|long|unsigned|float|double|' .
+                          'struct\s+[A-Za-z\d_]+|' .
+                          'union\s+[A-Za-z\d_]+)';
+
+               if ($line =~ m{[A-Za-z\d_]+(\*+) [A-Za-z\d_]+}) {
+                       print "\"foo$1 bar\" should be \"foo $1bar\"\n";
+                       print "$herecurr";
+                       $clean = 0;
+               }
+               if ($line =~ m{$type (\*) [A-Za-z\d_]+} ||
+                   $line =~ m{[A-Za-z\d_]+ (\*\*+) [A-Za-z\d_]+}) {
+                       print "\"foo $1 bar\" should be \"foo $1bar\"\n";
+                       print "$herecurr";
+                       $clean = 0;
+               }
+               if ($line =~ m{\([A-Za-z\d_\s]+[A-Za-z\d_](\*+)\)}) {
+                       print "\"(foo$1)\" should be \"(foo $1)\"\n";
+                       print "$herecurr";
+                       $clean = 0;
+               }
+               if ($line =~ m{\([A-Za-z\d_\s]+[A-Za-z\d_]\s+(\*+)\s+\)}) {
+                       print "\"(foo $1 )\" should be \"(foo $1)\"\n";
                        print "$herecurr";
                        $clean = 0;
                }
@@ -306,11 +505,29 @@ sub process {
 #                      $clean = 0;
 #              }
 
-# printk should use KERN_* levels
+# printk should use KERN_* levels.  Note that follow on printk's on the
+# same line do not need a level, so we use the current block context
+# to try and find and validate the current printk.  In summary the current
+# printk includes all preceeding printk's which have no newline on the end.
+# we assume the first bad printk is the one to report.
                if ($line =~ /\bprintk\((?!KERN_)/) {
-                       print "printk() should include KERN_ facility level\n";
-                       print "$herecurr";
-                       $clean = 0;
+                       my $ok = 0;
+                       for (my $ln = $linenr - 1; $ln >= $first_line; $ln--) {
+                               #print "CHECK<$lines[$ln - 1]\n";
+                               # we have a preceeding printk if it ends
+                               # with "\n" ignore it, else it is to blame
+                               if ($lines[$ln - 1] =~ m{\bprintk\(}) {
+                                       if ($rawlines[$ln - 1] !~ m{\\n"}) {
+                                               $ok = 1;
+                                       }
+                                       last;
+                               }
+                       }
+                       if ($ok == 0) {
+                               print "printk() should include KERN_ facility level\n";
+                               print "$herecurr";
+                               $clean = 0;
+                       }
                }
 
 #function brace can't be on same line, except for #defines of do while, or if closed on same line
@@ -320,86 +537,91 @@ sub process {
                        print "$herecurr";
                        $clean = 0;
                }
+               # Note we expand the line with the leading + as the real
+               # line will be displayed with the leading + and the tabs
+               # will therefore also expand that way.
                my $opline = $line;
-               $opline =~ s/^.//;
+               $opline = expand_tabs($opline);
+               $opline =~ s/^./ /;
                if (!($line=~/\#\s*include/)) {
                        # Check operator spacing.
                        my @elements = split(/(<<=|>>=|<=|>=|==|!=|\+=|-=|\*=|\/=|%=|\^=|\|=|&=|->|<<|>>|<|>|=|!|~|&&|\|\||,|\^|\+\+|--|;|&|\||\+|-|\*|\/\/|\/)/, $opline);
+                       my $off = 0;
                        for (my $n = 0; $n < $#elements; $n += 2) {
-                               # $wN says we have white-space before or after
-                               # $sN says we have a separator before or after
-                               # $oN says we have another operator before or after
-                               my $w1 = $elements[$n] =~ /\s$/;
-                               my $s1 = $elements[$n] =~ /(\[|\(|\s)$/;
-                               my $o1 = $elements[$n] eq '';
+                               $off += length($elements[$n]);
+
+                               my $a = '';
+                               $a = 'V' if ($elements[$n] ne '');
+                               $a = 'W' if ($elements[$n] =~ /\s$/);
+                               $a = 'B' if ($elements[$n] =~ /(\[|\()$/);
+                               $a = 'O' if ($elements[$n] eq '');
+                               $a = 'E' if ($elements[$n] eq '' && $n == 0);
+
                                my $op = $elements[$n + 1];
-                               my $w2 = 1;
-                               my $s2 = 1;
-                               my $o2 = 0;
-                               # If we have something after the operator handle it.
+
+                               my $c = '';
                                if (defined $elements[$n + 2]) {
-                                       $w2 = $elements[$n + 2] =~ /^\s/;
-                                       $s2 = $elements[$n + 2] =~ /^(\s|\)|\]|;)/;
-                                       $o2 = $elements[$n + 2] eq '';
+                                       $c = 'V' if ($elements[$n + 2] ne '');
+                                       $c = 'W' if ($elements[$n + 2] =~ /^\s/);
+                                       $c = 'B' if ($elements[$n + 2] =~ /^(\)|\]|;)/);
+                                       $c = 'O' if ($elements[$n + 2] eq '');
+                               } else {
+                                       $c = 'E';
                                }
 
-                               # Generate the context.
-                               my $at = "here: ";
-                               for (my $m = $n; $m >= 0; $m--) {
-                                       if ($elements[$m] ne '') {
-                                               $at .= $elements[$m];
-                                               last;
-                                       }
-                               }
-                               $at .= $op;
-                               for (my $m = $n + 2; defined $elements[$m]; $m++) {
-                                       if ($elements[$m] ne '') {
-                                               $at .= $elements[$m];
-                                               last;
-                                       }
+                               # Pick up the preceeding and succeeding characters.
+                               my $ca = substr($opline, $off - 1, 1);
+                               my $cc = '';
+                               if (length($opline) > ($off + length($elements[$n]))) {
+                                       $cc = substr($opline, $off + 1 + length($elements[$n]), 1);
                                }
 
+                               my $ctx = "${a}x${c}";
+
+                               my $at = "(ctx:$ctx)";
+
+                               my $ptr = (" " x $off) . "^";
+                               my $hereptr = "$hereline$ptr\n\n";
+
                                ##print "<$s1:$op:$s2> <$elements[$n]:$elements[$n + 1]:$elements[$n + 2]>\n";
-                               # Skip things apparently in quotes.
-                               next if ($line=~/\".*\Q$op\E.*\"/ or $line=~/\'\Q$op\E\'/);
 
                                # We need ; as an operator.  // is a comment.
                                if ($op eq ';' or $op eq '//') {
 
                                # -> should have no spaces
                                } elsif ($op eq '->') {
-                                       if ($s1 or $s2) {
+                                       if ($ctx =~ /Wx.|.xW/) {
                                                print "no spaces around that '$op' $at\n";
-                                               print "$herecurr";
+                                               print "$hereptr";
                                                $clean = 0;
                                        }
 
                                # , must have a space on the right.
                                } elsif ($op eq ',') {
-                                       if (!$s2) {
+                                       if ($ctx !~ /.xW|.xE/) {
                                                print "need space after that '$op' $at\n";
-                                               print "$herecurr";
+                                               print "$hereptr";
                                                $clean = 0;
                                        }
 
                                # unary ! and unary ~ are allowed no space on the right
                                } elsif ($op eq '!' or $op eq '~') {
-                                       if (!$s1 && !$o1) {
+                                       if ($ctx !~ /[WOEB]x./) {
                                                print "need space before that '$op' $at\n";
-                                               print "$herecurr";
+                                               print "$hereptr";
                                                $clean = 0;
                                        }
-                                       if ($s2) {
+                                       if ($ctx =~ /.xW/) {
                                                print "no space after that '$op' $at\n";
-                                               print "$herecurr";
+                                               print "$hereptr";
                                                $clean = 0;
                                        }
 
                                # unary ++ and unary -- are allowed no space on one side.
                                } elsif ($op eq '++' or $op eq '--') {
-                                       if (($s1 && $s2) || ((!$s1 && !$o1) && (!$s2 && !$o2))) {
+                                       if ($ctx !~ /[WOB]x[^W]|[^W]x[WOB]/) {
                                                print "need space one side of that '$op' $at\n";
-                                               print "$herecurr";
+                                               print "$hereptr";
                                                $clean = 0;
                                        }
 
@@ -415,15 +637,28 @@ sub process {
                                #
                                # - is the same
                                #
-                               # * is the same only adding:
+                               } elsif ($op eq '&' or $op eq '-') {
+                                       if ($ctx !~ /VxV|[EW]x[WE]|[EWB]x[VO]/) {
+                                               print "need space before that '$op' $at\n";
+                                               print "$hereptr";
+                                               $clean = 0;
+                                       }
+
+                               # * is the same as & only adding:
                                # type:
                                #       (foo *)
                                #       (foo **)
                                #
-                               } elsif ($op eq '&' or $op eq '-' or $op eq '*') {
-                                       if ($w2 and !$w1) {
+                               } elsif ($op eq '*') {
+                                       if ($ca eq '*') {
+                                               if ($cc =~ /\s/) {
+                                                       print "no space after that '$op' $at\n";
+                                                       print "$hereptr";
+                                                       $clean = 0;
+                                               }
+                                       } elsif ($ctx !~ /VxV|[EW]x[WE]|[EWB]x[VO]|OxV|WxB/) {
                                                print "need space before that '$op' $at\n";
-                                               print "$herecurr";
+                                               print "$hereptr";
                                                $clean = 0;
                                        }
 
@@ -431,18 +666,19 @@ sub process {
                                } elsif ($op eq '<<' or $op eq '>>' or $op eq '+' or $op eq '/' or
                                         $op eq '^' or $op eq '|')
                                {
-                                       if ($s1 != $s2) {
+                                       if ($ctx !~ /VxV|WxW|VxE|WxE/) {
                                                print "need consistent spacing around '$op' $at\n";
-                                               print "$herecurr";
+                                               print "$hereptr";
                                                $clean = 0;
                                        }
 
                                # All the others need spaces both sides.
-                               } elsif (!$s1 or !$s2) {
+                               } elsif ($ctx !~ /[EW]x[WE]/) {
                                        print "need spaces around that '$op' $at\n";
-                                       print "$herecurr";
+                                       print "$hereptr";
                                        $clean = 0;
                                }
+                               $off += length($elements[$n + 1]);
                        }
                }
 
@@ -454,7 +690,7 @@ sub process {
                }
 
 #goto labels aren't indented, allow a single space however
-               if ($line=~/^.\s+[A-Za-z\d_]+:/ and
+               if ($line=~/^.\s+[A-Za-z\d_]+:(?![0-9]+)/ and
                   !($line=~/^. [A-Za-z\d_]+:/) and !($line=~/^.\s+default:/)) {
                        print "labels should not be indented\n";
                        print "$herecurr";
@@ -462,15 +698,16 @@ sub process {
                }
 
 # Need a space before open parenthesis after if, while etc
-               if ($line=~/(if|while|for|switch)\(/) {
+               if ($line=~/\b(if|while|for|switch)\(/) {
                        print "need a space before the open parenthesis\n";
                        print "$herecurr";
                        $clean = 0;
                }
 
 # Check for illegal assignment in if conditional.
-               if ($line=~/(if|while)\s*\(.*[^<>!=]=[^=].*\)/) {
-                       print "do not use assignment in if condition\n";
+               if ($line=~/\b(if|while)\s*\(.*[^<>!=]=[^=].*\)/) {
+                       #next if ($line=~/\".*\Q$op\E.*\"/ or $line=~/\'\Q$op\E\'/);
+                       print "do not use assignment in condition\n";
                        print "$herecurr";
                        $clean = 0;
                }
@@ -484,17 +721,6 @@ sub process {
                        $clean = 0;
                }
 
-               # Check for switch () {<nl>case, these must be at the
-               # same indent.  We will only catch the first one, as our
-               # context is very small but people tend to be consistent
-               # so we will catch them out more often than not.
-               if ($prevline=~/\s*switch\s*\(.*\)/ and $line=~/\s*case\s+/
-                                               and $previndent != $indent) {
-                       print "switch and case should be at the same indent\n";
-                       print "$hereprev";
-                       $clean = 0;
-               }
-
 #studly caps, commented out until figure out how to distinguish between use of existing and adding new
 #              if (($line=~/[\w_][a-z\d]+[A-Z]/) and !($line=~/print/)) {
 #                  print "No studly caps, use _\n";
@@ -520,11 +746,11 @@ sub process {
                }
 
 #if/while/etc brace do not go on next line, unless #defining a do while loop, or if that brace on the next line is for something else
-               if ($prevline=~/(if|while|for|switch)\s*\(/) {
+               if ($prevline=~/\b(if|while|for|switch)\s*\(/) {
                        my @opened = $prevline=~/\(/g;
                        my @closed = $prevline=~/\)/g;
                        my $nr_line = $linenr;
-                       my $remaining = $realcnt;
+                       my $remaining = $realcnt - 1;
                        my $next_line = $line;
                        my $extra_lines = 0;
                        my $display_segment = $prevline;
@@ -540,10 +766,10 @@ sub process {
                                @closed = $prevline=~/\)/g;
                        }
 
-                       if (($prevline=~/(if|while|for|switch)\s*\(.*\)\s*$/) and ($next_line=~/{/) and
-                          !($next_line=~/(if|while|for)/) and !($next_line=~/\#define.*do.*while/)) {
+                       if (($prevline=~/\b(if|while|for|switch)\s*\(.*\)\s*$/) and ($next_line=~/{/) and
+                          !($next_line=~/\b(if|while|for)/) and !($next_line=~/\#define.*do.*while/)) {
                                print "That { should be on the previous line\n";
-                               print "$display_segment\n$next_line\n\n";
+                               print "$here\n$display_segment\n$next_line\n\n";
                                $clean = 0;
                        }
                }
@@ -558,7 +784,7 @@ sub process {
                }
 
 # don't include deprecated include files
-               for my $inc (@deprecated) {
+               for my $inc (@dep_includes) {
                        if ($line =~ m@\#\s*include\s*\<$inc>@) {
                                print "Don't use <$inc>: see Documentation/feature-removal-schedule.txt\n";
                                print "$herecurr";
@@ -566,9 +792,56 @@ sub process {
                        }
                }
 
-# don't use kernel_thread()
-               if ($line =~ /\bkernel_thread\b/) {
-                       print "Don't use kernel_thread(), use kthread(): see Documentation/feature-removal-schedule.txt\n";
+# don't use deprecated functions
+               for my $func (@dep_functions) {
+                       if ($line =~ /\b$func\b/) {
+                               print "Don't use $func(): see Documentation/feature-removal-schedule.txt\n";
+                               print "$herecurr";
+                               $clean = 0;
+                       }
+               }
+
+# no volatiles please
+               if ($line =~ /\bvolatile\b/ && $line !~ /\basm\s+volatile\b/) {
+                       print "Use of volatile is usually wrong: see Documentation/volatile-considered-harmful.txt\n";
+                       print "$herecurr";
+                       $clean = 0;
+               }
+
+# warn about #if 0
+               if ($line =~ /^.#\s*if\s+0\b/) {
+                       print "#if 0 -- if this code redundant remove it\n";
+                       print "$herecurr";
+                       $clean = 0;
+               }
+
+# warn about #ifdefs in C files
+#              if ($line =~ /^.#\s*if(|n)def/ && ($realfile =~ /\.c$/)) {
+#                      print "#ifdef in C files should be avoided\n";
+#                      print "$herecurr";
+#                      $clean = 0;
+#              }
+
+# check for spinlock_t definitions without a comment.
+               if ($line =~ /^.\s*(struct\s+mutex|spinlock_t)\s+\S+;/) {
+                       my $which = $1;
+                       if (!ctx_has_comment($first_line, $linenr)) {
+                               print "$1 definition without comment\n";
+                               print "$herecurr";
+                               $clean = 0;
+                       }
+               }
+# check for memory barriers without a comment.
+               if ($line =~ /\b(mb|rmb|wmb|read_barrier_depends|smp_mb|smp_rmb|smp_wmb|smp_read_barrier_depends)\(/) {
+                       if (!ctx_has_comment($first_line, $linenr)) {
+                               print "memory barrier without comment\n";
+                               print "$herecurr";
+                               $clean = 0;
+                       }
+               }
+# check of hardware specific defines
+               if ($line =~ m@^.#\s*if.*\b(__i386__|__powerpc64__|__sun__|__s390x__)\b@) {
+                       print "architecture specific defines should be avoided\n";
                        print "$herecurr";
                        $clean = 0;
                }