Merge branch 'core-v28-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
Linus Torvalds [Thu, 16 Oct 2008 22:17:40 +0000 (15:17 -0700)]
* 'core-v28-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  do_generic_file_read: s/EINTR/EIO/ if lock_page_killable() fails
  softirq, warning fix: correct a format to avoid a warning
  softirqs, debug: preemption check
  x86, pci-hotplug, calgary / rio: fix EBDA ioremap()
  IO resources, x86: ioremap sanity check to catch mapping requests exceeding, fix
  IO resources, x86: ioremap sanity check to catch mapping requests exceeding the BAR sizes
  softlockup: Documentation/sysctl/kernel.txt: fix softlockup_thresh description
  dmi scan: warn about too early calls to dmi_check_system()
  generic: redefine resource_size_t as phys_addr_t
  generic: make PFN_PHYS explicitly return phys_addr_t
  generic: add phys_addr_t for holding physical addresses
  softirq: allocate less vectors
  IO resources: fix/remove printk
  printk: robustify printk, update comment
  printk: robustify printk, fix #2
  printk: robustify printk, fix
  printk: robustify printk

Fixed up conflicts in:
arch/powerpc/include/asm/types.h
arch/powerpc/platforms/Kconfig.cputype
manually.

1  2 
arch/powerpc/Kconfig
arch/powerpc/include/asm/types.h
arch/powerpc/platforms/Kconfig.cputype
arch/powerpc/sysdev/ppc4xx_pci.c
arch/x86/Kconfig
include/linux/ioport.h
include/linux/kernel.h
kernel/printk.c
kernel/resource.c
mm/Kconfig
mm/filemap.c

diff --combined arch/powerpc/Kconfig
@@@ -22,6 -22,9 +22,9 @@@ config WORD_SIZ
  config PPC_MERGE
        def_bool y
  
+ config ARCH_PHYS_ADDR_T_64BIT
+        def_bool PPC64 || PHYS_64BIT
  config MMU
        bool
        default y
@@@ -415,11 -418,8 +418,11 @@@ config PPC_64K_PAGE
  
  config FORCE_MAX_ZONEORDER
        int "Maximum zone order"
 +      range 9 64 if PPC_64K_PAGES
        default "9" if PPC_64K_PAGES
 +      range 13 64 if PPC64 && !PPC_64K_PAGES
        default "13" if PPC64 && !PPC_64K_PAGES
 +      range 11 64
        default "11"
        help
          The kernel memory allocator divides physically contiguous memory
@@@ -809,19 -809,6 +812,19 @@@ config PIN_TL
  endmenu
  
  if PPC64
 +config RELOCATABLE
 +      bool "Build a relocatable kernel"
 +      help
 +        This builds a kernel image that is capable of running anywhere
 +        in the RMA (real memory area) at any 16k-aligned base address.
 +        The kernel is linked as a position-independent executable (PIE)
 +        and contains dynamic relocations which are processed early
 +        in the bootup process.
 +
 +        One use is for the kexec on panic case where the recovery kernel
 +        must live at a different physical address than the primary
 +        kernel.
 +
  config PAGE_OFFSET
        hex
        default "0xc000000000000000"
@@@ -48,14 -48,7 +48,7 @@@ typedef struct 
  
  typedef __vector128 vector128;
  
- /* Physical address used by some IO functions */
- #if defined(CONFIG_PPC64) || defined(CONFIG_PHYS_64BIT)
- typedef u64 phys_addr_t;
- #else
- typedef u32 phys_addr_t;
- #endif
 -#ifdef __powerpc64__
 +#if defined(__powerpc64__) || defined(CONFIG_PHYS_64BIT)
  typedef u64 dma_addr_t;
  #else
  typedef u32 dma_addr_t;
@@@ -50,7 -50,6 +50,7 @@@ config 44
        select PPC_UDBG_16550
        select 4xx_SOC
        select PPC_PCI_CHOICE
 +      select PHYS_64BIT
  
  config E200
        bool "Freescale e200"
@@@ -129,20 -128,17 +129,19 @@@ config FSL_EMB_PERFMO
  
  config PTE_64BIT
        bool
 -      depends on 44x || E500
 -      default y if 44x
 -      default y if E500 && PHYS_64BIT
 +      depends on 44x || E500 || PPC_86xx
 +      default y if PHYS_64BIT
  
  config PHYS_64BIT
 -      bool 'Large physical address support' if E500
 -      depends on 44x || E500
 -      default y if 44x
 +      bool 'Large physical address support' if E500 || PPC_86xx
 +      depends on (44x || E500 || PPC_86xx) && !PPC_83xx && !PPC_82xx
-       select RESOURCES_64BIT
        ---help---
          This option enables kernel support for larger than 32-bit physical
 -        addresses.  This features is not be available on all e500 cores.
 +        addresses.  This feature may not be available on all cores.
 +
 +        If you have more than 3.5GB of RAM or so, you also need to enable
 +        SWIOTLB under Kernel Options for this to work.  The actual number
 +        is platform-dependent.
  
          If in doubt, say N here.
  
  #include <asm/machdep.h>
  #include <asm/dcr.h>
  #include <asm/dcr-regs.h>
 +#include <mm/mmu_decl.h>
  
  #include "ppc4xx_pci.h"
  
  static int dma_offset_set;
  
  #define U64_TO_U32_LOW(val)   ((u32)((val) & 0x00000000ffffffffULL))
  #define U64_TO_U32_HIGH(val)  ((u32)((val) >> 32))
  
- #ifdef CONFIG_RESOURCES_64BIT
- #define RES_TO_U32_LOW(val)   U64_TO_U32_LOW(val)
- #define RES_TO_U32_HIGH(val)  U64_TO_U32_HIGH(val)
- #else
- #define RES_TO_U32_LOW(val)   (val)
- #define RES_TO_U32_HIGH(val)  (0)
- #endif
+ #define RES_TO_U32_LOW(val)   \
+       ((sizeof(resource_size_t) > sizeof(u32)) ? U64_TO_U32_LOW(val) : (val))
+ #define RES_TO_U32_HIGH(val)  \
+       ((sizeof(resource_size_t) > sizeof(u32)) ? U64_TO_U32_HIGH(val) : (0))
  
  static inline int ppc440spe_revA(void)
  {
@@@ -103,8 -102,7 +100,8 @@@ static int __init ppc4xx_parse_dma_rang
  
        /* Default */
        res->start = 0;
 -      res->end = size = 0x80000000;
 +      size = 0x80000000;
 +      res->end = size - 1;
        res->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
  
        /* Get dma-ranges property */
  
                /* Use that */
                res->start = pci_addr;
- #ifndef CONFIG_RESOURCES_64BIT
                /* Beware of 32 bits resources */
-               if ((pci_addr + size) > 0x100000000ull)
+               if (sizeof(resource_size_t) == sizeof(u32) &&
+                   (pci_addr + size) > 0x100000000ull)
                        res->end = 0xffffffff;
                else
- #endif
                        res->end = res->start + size - 1;
                break;
        }
         */
        if (size < total_memory) {
                printk(KERN_ERR "%s: dma-ranges too small "
 -                     "(size=%llx total_memory=%lx)\n",
 -                     hose->dn->full_name, size, total_memory);
 +                     "(size=%llx total_memory=%llx)\n",
 +                     hose->dn->full_name, size, (u64)total_memory);
                return -ENXIO;
        }
  
        /* Check we are a power of 2 size and that base is a multiple of size*/
 -      if (!is_power_of_2(size) ||
 +      if ((size & (size - 1)) != 0  ||
            (res->start & (size - 1)) != 0) {
                printk(KERN_ERR "%s: dma-ranges unaligned\n",
                       hose->dn->full_name);
@@@ -276,16 -273,9 +272,16 @@@ static void __init ppc4xx_probe_pci_bri
        const int *bus_range;
        int primary = 0;
  
 +      /* Check if device is enabled */
 +      if (!of_device_is_available(np)) {
 +              printk(KERN_INFO "%s: Port disabled via device-tree\n",
 +                     np->full_name);
 +              return;
 +      }
 +
        /* Fetch config space registers address */
        if (of_address_to_resource(np, 0, &rsrc_cfg)) {
 -              printk(KERN_ERR "%s:Can't get PCI config register base !",
 +              printk(KERN_ERR "%s: Can't get PCI config register base !",
                       np->full_name);
                return;
        }
@@@ -816,7 -806,7 +812,7 @@@ static int ppc460ex_pciex_init_port_hw(
        switch (port->index) {
        case 0:
                mtdcri(SDR0, PESDR0_460EX_L0CDRCTL, 0x00003230);
 -              mtdcri(SDR0, PESDR0_460EX_L0DRV, 0x00000136);
 +              mtdcri(SDR0, PESDR0_460EX_L0DRV, 0x00000130);
                mtdcri(SDR0, PESDR0_460EX_L0CLK, 0x00000006);
  
                mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST,0x10000000);
                mtdcri(SDR0, PESDR1_460EX_L1CDRCTL, 0x00003230);
                mtdcri(SDR0, PESDR1_460EX_L2CDRCTL, 0x00003230);
                mtdcri(SDR0, PESDR1_460EX_L3CDRCTL, 0x00003230);
 -              mtdcri(SDR0, PESDR1_460EX_L0DRV, 0x00000136);
 -              mtdcri(SDR0, PESDR1_460EX_L1DRV, 0x00000136);
 -              mtdcri(SDR0, PESDR1_460EX_L2DRV, 0x00000136);
 -              mtdcri(SDR0, PESDR1_460EX_L3DRV, 0x00000136);
 +              mtdcri(SDR0, PESDR1_460EX_L0DRV, 0x00000130);
 +              mtdcri(SDR0, PESDR1_460EX_L1DRV, 0x00000130);
 +              mtdcri(SDR0, PESDR1_460EX_L2DRV, 0x00000130);
 +              mtdcri(SDR0, PESDR1_460EX_L3DRV, 0x00000130);
                mtdcri(SDR0, PESDR1_460EX_L0CLK, 0x00000006);
                mtdcri(SDR0, PESDR1_460EX_L1CLK, 0x00000006);
                mtdcri(SDR0, PESDR1_460EX_L2CLK, 0x00000006);
diff --combined arch/x86/Kconfig
@@@ -39,6 -39,10 +39,6 @@@ config ARCH_DEFCONFI
        default "arch/x86/configs/i386_defconfig" if X86_32
        default "arch/x86/configs/x86_64_defconfig" if X86_64
  
 -
 -config GENERIC_LOCKBREAK
 -      def_bool n
 -
  config GENERIC_TIME
        def_bool y
  
@@@ -91,7 -95,7 +91,7 @@@ config GENERIC_HWEIGH
        def_bool y
  
  config GENERIC_GPIO
 -      def_bool n
 +      bool
  
  config ARCH_MAY_HAVE_PC_FDC
        def_bool y
@@@ -102,6 -106,12 +102,6 @@@ config RWSEM_GENERIC_SPINLOC
  config RWSEM_XCHGADD_ALGORITHM
        def_bool X86_XADD
  
 -config ARCH_HAS_ILOG2_U32
 -      def_bool n
 -
 -config ARCH_HAS_ILOG2_U64
 -      def_bool n
 -
  config ARCH_HAS_CPU_IDLE_WAIT
        def_bool y
  
@@@ -748,8 -758,9 +748,8 @@@ config I8
          Say N otherwise.
  
  config X86_REBOOTFIXUPS
 -      def_bool n
 -      prompt "Enable X86 board specific fixups for reboot"
 -      depends on X86_32 && X86
 +      bool "Enable X86 board specific fixups for reboot"
 +      depends on X86_32
        ---help---
          This enables chipset and/or board specific fixups to be done
          in order to get reboot to work correctly. This is only needed on
@@@ -933,15 -944,18 +933,17 @@@ config HIGHME
        depends on X86_32 && (HIGHMEM64G || HIGHMEM4G)
  
  config X86_PAE
 -      def_bool n
 -      prompt "PAE (Physical Address Extension) Support"
 +      bool "PAE (Physical Address Extension) Support"
        depends on X86_32 && !HIGHMEM4G
-       select RESOURCES_64BIT
        help
          PAE is required for NX support, and furthermore enables
          larger swapspace support for non-overcommit purposes. It
          has the cost of more pagetable lookup overhead, and also
          consumes more pagetable space per process.
  
+ config ARCH_PHYS_ADDR_T_64BIT
+        def_bool X86_64 || X86_PAE
  # Common NUMA Features
  config NUMA
        bool "Numa Memory Allocation and Scheduler Support (EXPERIMENTAL)"
@@@ -1226,7 -1240,8 +1228,7 @@@ config X86_PA
          If unsure, say Y.
  
  config EFI
 -      def_bool n
 -      prompt "EFI runtime service support"
 +      bool "EFI runtime service support"
        depends on ACPI
        ---help---
        This enables the kernel to use EFI runtime services that are
diff --combined include/linux/ioport.h
@@@ -34,8 -34,7 +34,8 @@@ struct resource_list 
   */
  #define IORESOURCE_BITS               0x000000ff      /* Bus-specific bits */
  
 -#define IORESOURCE_IO         0x00000100      /* Resource type */
 +#define IORESOURCE_TYPE_BITS  0x00000f00      /* Resource type */
 +#define IORESOURCE_IO         0x00000100
  #define IORESOURCE_MEM                0x00000200
  #define IORESOURCE_IRQ                0x00000400
  #define IORESOURCE_DMA                0x00000800
@@@ -127,10 -126,6 +127,10 @@@ static inline resource_size_t resource_
  {
        return res->end - res->start + 1;
  }
 +static inline unsigned long resource_type(struct resource *res)
 +{
 +      return res->flags & IORESOURCE_TYPE_BITS;
 +}
  
  /* Convenience shorthand with allocation */
  #define request_region(start,n,name)  __request_region(&ioport_resource, (start), (n), (name))
@@@ -174,6 -169,7 +174,7 @@@ extern struct resource * __devm_request
  
  extern void __devm_release_region(struct device *dev, struct resource *parent,
                                  resource_size_t start, resource_size_t n);
+ extern int iomem_map_sanity_check(resource_size_t addr, unsigned long size);
  
  #endif /* __ASSEMBLY__ */
  #endif        /* _LINUX_IOPORT_H */
diff --combined include/linux/kernel.h
@@@ -16,7 -16,6 +16,7 @@@
  #include <linux/log2.h>
  #include <linux/typecheck.h>
  #include <linux/ratelimit.h>
 +#include <linux/dynamic_printk.h>
  #include <asm/byteorder.h>
  #include <asm/bug.h>
  
@@@ -214,6 -213,9 +214,9 @@@ static inline bool printk_timed_ratelim
                { return false; }
  #endif
  
+ extern int printk_needs_cpu(int cpu);
+ extern void printk_tick(void);
  extern void asmlinkage __attribute__((format(printf, 1, 2)))
        early_printk(const char *fmt, ...);
  
@@@ -236,10 -238,9 +239,10 @@@ extern int oops_in_progress;             /* If set
  extern int panic_timeout;
  extern int panic_on_oops;
  extern int panic_on_unrecovered_nmi;
 -extern int tainted;
  extern const char *print_tainted(void);
 -extern void add_taint(unsigned);
 +extern void add_taint(unsigned flag);
 +extern int test_taint(unsigned flag);
 +extern unsigned long get_taint(void);
  extern int root_mountflags;
  
  /* Values used for system_state */
@@@ -252,16 -253,16 +255,16 @@@ extern enum system_states 
        SYSTEM_SUSPEND_DISK,
  } system_state;
  
 -#define TAINT_PROPRIETARY_MODULE      (1<<0)
 -#define TAINT_FORCED_MODULE           (1<<1)
 -#define TAINT_UNSAFE_SMP              (1<<2)
 -#define TAINT_FORCED_RMMOD            (1<<3)
 -#define TAINT_MACHINE_CHECK           (1<<4)
 -#define TAINT_BAD_PAGE                        (1<<5)
 -#define TAINT_USER                    (1<<6)
 -#define TAINT_DIE                     (1<<7)
 -#define TAINT_OVERRIDDEN_ACPI_TABLE   (1<<8)
 -#define TAINT_WARN                    (1<<9)
 +#define TAINT_PROPRIETARY_MODULE      0
 +#define TAINT_FORCED_MODULE           1
 +#define TAINT_UNSAFE_SMP              2
 +#define TAINT_FORCED_RMMOD            3
 +#define TAINT_MACHINE_CHECK           4
 +#define TAINT_BAD_PAGE                        5
 +#define TAINT_USER                    6
 +#define TAINT_DIE                     7
 +#define TAINT_OVERRIDDEN_ACPI_TABLE   8
 +#define TAINT_WARN                    9
  
  extern void dump_stack(void) __cold;
  
@@@ -305,12 -306,8 +308,12 @@@ static inline char *pack_hex_byte(char 
  #define pr_info(fmt, arg...) \
        printk(KERN_INFO fmt, ##arg)
  
 -#ifdef DEBUG
  /* If you are writing a driver, please use dev_dbg instead */
 +#if defined(CONFIG_DYNAMIC_PRINTK_DEBUG)
 +#define pr_debug(fmt, ...) do { \
 +      dynamic_pr_debug(fmt, ##__VA_ARGS__); \
 +      } while (0)
 +#elif defined(DEBUG)
  #define pr_debug(fmt, arg...) \
        printk(KERN_DEBUG fmt, ##arg)
  #else
diff --combined kernel/printk.c
@@@ -13,7 -13,7 +13,7 @@@
   * Fixed SMP synchronization, 08/08/99, Manfred Spraul
   *     manfred@colorfullife.com
   * Rewrote bits to get rid of console_lock
 - *    01Mar01 Andrew Morton <andrewm@uow.edu.au>
 + *    01Mar01 Andrew Morton
   */
  
  #include <linux/kernel.h>
@@@ -577,9 -577,6 +577,6 @@@ static int have_callable_console(void
   * @fmt: format string
   *
   * This is printk().  It can be called from any context.  We want it to work.
-  * Be aware of the fact that if oops_in_progress is not set, we might try to
-  * wake klogd up which could deadlock on runqueue lock if printk() is called
-  * from scheduler code.
   *
   * We try to grab the console_sem.  If we succeed, it's easy - we log the output and
   * call the console drivers.  If we fail to get the semaphore we place the output
   *
   * See also:
   * printf(3)
 + *
 + * See the vsnprintf() documentation for format string extensions over C99.
   */
  
  asmlinkage int printk(const char *fmt, ...)
@@@ -984,10 -979,25 +981,25 @@@ int is_console_locked(void
        return console_locked;
  }
  
- void wake_up_klogd(void)
+ static DEFINE_PER_CPU(int, printk_pending);
+ void printk_tick(void)
  {
-       if (!oops_in_progress && waitqueue_active(&log_wait))
+       if (__get_cpu_var(printk_pending)) {
+               __get_cpu_var(printk_pending) = 0;
                wake_up_interruptible(&log_wait);
+       }
+ }
+ int printk_needs_cpu(int cpu)
+ {
+       return per_cpu(printk_pending, cpu);
+ }
+ void wake_up_klogd(void)
+ {
+       if (waitqueue_active(&log_wait))
+               __raw_get_cpu_var(printk_pending) = 1;
  }
  
  /**
diff --combined kernel/resource.c
@@@ -38,10 -38,6 +38,6 @@@ EXPORT_SYMBOL(iomem_resource)
  
  static DEFINE_RWLOCK(resource_lock);
  
- #ifdef CONFIG_PROC_FS
- enum { MAX_IORES_LEVEL = 5 };
  static void *r_next(struct seq_file *m, void *v, loff_t *pos)
  {
        struct resource *p = v;
        return p->sibling;
  }
  
+ #ifdef CONFIG_PROC_FS
+ enum { MAX_IORES_LEVEL = 5 };
  static void *r_start(struct seq_file *m, loff_t *pos)
        __acquires(resource_lock)
  {
@@@ -549,13 -549,9 +549,9 @@@ static void __init __reserve_region_wit
        }
  
        if (!res) {
-               printk(KERN_DEBUG "    __reserve_region_with_split: (%s) [%llx, %llx], res: (%s) [%llx, %llx]\n",
-                        conflict->name, conflict->start, conflict->end,
-                        name, start, end);
                /* failed, split and try again */
  
-               /* conflict coverred whole area */
+               /* conflict covered whole area */
                if (conflict->start <= start && conflict->end >= end)
                        return;
  
@@@ -630,34 -626,33 +626,34 @@@ struct resource * __request_region(stru
  {
        struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);
  
 -      if (res) {
 -              res->name = name;
 -              res->start = start;
 -              res->end = start + n - 1;
 -              res->flags = IORESOURCE_BUSY;
 -
 -              write_lock(&resource_lock);
 -
 -              for (;;) {
 -                      struct resource *conflict;
 -
 -                      conflict = __request_resource(parent, res);
 -                      if (!conflict)
 -                              break;
 -                      if (conflict != parent) {
 -                              parent = conflict;
 -                              if (!(conflict->flags & IORESOURCE_BUSY))
 -                                      continue;
 -                      }
 -
 -                      /* Uhhuh, that didn't work out.. */
 -                      kfree(res);
 -                      res = NULL;
 +      if (!res)
 +              return NULL;
 +
 +      res->name = name;
 +      res->start = start;
 +      res->end = start + n - 1;
 +      res->flags = IORESOURCE_BUSY;
 +
 +      write_lock(&resource_lock);
 +
 +      for (;;) {
 +              struct resource *conflict;
 +
 +              conflict = __request_resource(parent, res);
 +              if (!conflict)
                        break;
 +              if (conflict != parent) {
 +                      parent = conflict;
 +                      if (!(conflict->flags & IORESOURCE_BUSY))
 +                              continue;
                }
 -              write_unlock(&resource_lock);
 +
 +              /* Uhhuh, that didn't work out.. */
 +              kfree(res);
 +              res = NULL;
 +              break;
        }
 +      write_unlock(&resource_lock);
        return res;
  }
  EXPORT_SYMBOL(__request_region);
@@@ -832,3 -827,40 +828,40 @@@ static int __init reserve_setup(char *s
  }
  
  __setup("reserve=", reserve_setup);
+ /*
+  * Check if the requested addr and size spans more than any slot in the
+  * iomem resource tree.
+  */
+ int iomem_map_sanity_check(resource_size_t addr, unsigned long size)
+ {
+       struct resource *p = &iomem_resource;
+       int err = 0;
+       loff_t l;
+       read_lock(&resource_lock);
+       for (p = p->child; p ; p = r_next(NULL, p, &l)) {
+               /*
+                * We can probably skip the resources without
+                * IORESOURCE_IO attribute?
+                */
+               if (p->start >= addr + size)
+                       continue;
+               if (p->end < addr)
+                       continue;
+               if (p->start <= addr && (p->end >= addr + size - 1))
+                       continue;
+               printk(KERN_WARNING "resource map sanity check conflict: "
+                      "0x%llx 0x%llx 0x%llx 0x%llx %s\n",
+                      (unsigned long long)addr,
+                      (unsigned long long)(addr + size - 1),
+                      (unsigned long long)p->start,
+                      (unsigned long long)p->end,
+                      p->name);
+               err = -1;
+               break;
+       }
+       read_unlock(&resource_lock);
+       return err;
+ }
diff --combined mm/Kconfig
@@@ -101,7 -101,7 +101,7 @@@ config HAVE_MEMORY_PRESEN
  # with gcc 3.4 and later.
  #
  config SPARSEMEM_STATIC
 -      def_bool n
 +      bool
  
  #
  # Architecture platforms which require a two level mem_section in SPARSEMEM
@@@ -113,7 -113,7 +113,7 @@@ config SPARSEMEM_EXTREM
        depends on SPARSEMEM && !SPARSEMEM_STATIC
  
  config SPARSEMEM_VMEMMAP_ENABLE
 -      def_bool n
 +      bool
  
  config SPARSEMEM_VMEMMAP
        bool "Sparse Memory virtual memmap"
@@@ -187,6 -187,9 +187,9 @@@ config RESOURCES_64BI
        help
          This option allows memory and IO resources to be 64 bit.
  
+ config PHYS_ADDR_T_64BIT
+       def_bool 64BIT || ARCH_PHYS_ADDR_T_64BIT
  config ZONE_DMA_FLAG
        int
        default "0" if !ZONE_DMA
diff --combined mm/filemap.c
@@@ -1100,8 -1100,9 +1100,9 @@@ page_ok
  
  page_not_up_to_date:
                /* Get exclusive access to the page ... */
-               if (lock_page_killable(page))
-                       goto readpage_eio;
+               error = lock_page_killable(page);
+               if (unlikely(error))
+                       goto readpage_error;
  
  page_not_up_to_date_locked:
                /* Did it get truncated before we got the lock? */
@@@ -1130,8 -1131,9 +1131,9 @@@ readpage
                }
  
                if (!PageUptodate(page)) {
-                       if (lock_page_killable(page))
-                               goto readpage_eio;
+                       error = lock_page_killable(page);
+                       if (unlikely(error))
+                               goto readpage_error;
                        if (!PageUptodate(page)) {
                                if (page->mapping == NULL) {
                                        /*
                                }
                                unlock_page(page);
                                shrink_readahead_size_eio(filp, ra);
-                               goto readpage_eio;
+                               error = -EIO;
+                               goto readpage_error;
                        }
                        unlock_page(page);
                }
  
                goto page_ok;
  
- readpage_eio:
-               error = -EIO;
  readpage_error:
                /* UHHUH! A synchronous read error occurred. Report it */
                desc->error = error;
@@@ -1186,7 -1187,8 +1187,7 @@@ out
        ra->prev_pos |= prev_offset;
  
        *ppos = ((loff_t)index << PAGE_CACHE_SHIFT) + offset;
 -      if (filp)
 -              file_accessed(filp);
 +      file_accessed(filp);
  }
  
  int file_read_actor(read_descriptor_t *desc, struct page *page,