Merge branch 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik...
authorLinus Torvalds <torvalds@g5.osdl.org>
Mon, 11 Sep 2006 14:54:14 +0000 (07:54 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Mon, 11 Sep 2006 14:54:14 +0000 (07:54 -0700)
* 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/libata-dev:
  [PATCH] ata_piix: add map 01b for ICH7M
  [libata] sata_mv: errata check buglet fix

39 files changed:
arch/frv/Kconfig
arch/frv/kernel/time.c
arch/ia64/kernel/entry.S
arch/ia64/kernel/head.S
arch/ia64/kernel/perfmon.c
arch/ia64/kernel/sys_ia64.c
arch/ia64/sn/kernel/setup.c
arch/sparc/kernel/sys_sparc.c
arch/sparc64/kernel/sys_sparc.c
drivers/ide/ide-proc.c
drivers/ide/pci/aec62xx.c
drivers/ide/pci/serverworks.c
drivers/ide/pci/siimage.c
drivers/ide/pci/sis5513.c
drivers/net/Kconfig
drivers/scsi/sata_via.c
fs/ext3/inode.c
fs/nfs/direct.c
fs/nfs/read.c
fs/nfs/write.c
fs/super.c
include/asm-i386/Kbuild
include/asm-ia64/mman.h
include/asm-ia64/unistd.h
include/asm-sh/page.h
include/asm-sparc/mman.h
include/asm-sparc64/mman.h
include/linux/atmdev.h
include/linux/hrtimer.h
include/linux/ktime.h
include/linux/nfs_fs.h
include/linux/nfs_xdr.h
include/linux/pci_ids.h
kernel/futex.c
kernel/panic.c
kernel/power/Kconfig
kernel/spinlock.c
mm/mmap.c
mm/truncate.c

index 95a3892..a601a17 100644 (file)
@@ -29,6 +29,10 @@ config GENERIC_HARDIRQS
        bool
        default n
 
+config GENERIC_TIME
+       bool
+       default y
+
 config TIME_LOW_RES
        bool
        default y
index d5b64e1..68a77fe 100644 (file)
@@ -32,8 +32,6 @@
 
 #define TICK_SIZE (tick_nsec / 1000)
 
-extern unsigned long wall_jiffies;
-
 unsigned long __nongprelbss __clkin_clock_speed_HZ;
 unsigned long __nongprelbss __ext_bus_clock_speed_HZ;
 unsigned long __nongprelbss __res_bus_clock_speed_HZ;
@@ -144,85 +142,6 @@ void time_init(void)
        time_divisor_init();
 }
 
-/*
- * This version of gettimeofday has near microsecond resolution.
- */
-void do_gettimeofday(struct timeval *tv)
-{
-       unsigned long seq;
-       unsigned long usec, sec;
-       unsigned long max_ntp_tick;
-
-       do {
-               unsigned long lost;
-
-               seq = read_seqbegin(&xtime_lock);
-
-               usec = 0;
-               lost = jiffies - wall_jiffies;
-
-               /*
-                * If time_adjust is negative then NTP is slowing the clock
-                * so make sure not to go into next possible interval.
-                * Better to lose some accuracy than have time go backwards..
-                */
-               if (unlikely(time_adjust < 0)) {
-                       max_ntp_tick = (USEC_PER_SEC / HZ) - tickadj;
-                       usec = min(usec, max_ntp_tick);
-
-                       if (lost)
-                               usec += lost * max_ntp_tick;
-               }
-               else if (unlikely(lost))
-                       usec += lost * (USEC_PER_SEC / HZ);
-
-               sec = xtime.tv_sec;
-               usec += (xtime.tv_nsec / 1000);
-       } while (read_seqretry(&xtime_lock, seq));
-
-       while (usec >= 1000000) {
-               usec -= 1000000;
-               sec++;
-       }
-
-       tv->tv_sec = sec;
-       tv->tv_usec = usec;
-}
-
-EXPORT_SYMBOL(do_gettimeofday);
-
-int do_settimeofday(struct timespec *tv)
-{
-       time_t wtm_sec, sec = tv->tv_sec;
-       long wtm_nsec, nsec = tv->tv_nsec;
-
-       if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
-               return -EINVAL;
-
-       write_seqlock_irq(&xtime_lock);
-       /*
-        * This is revolting. We need to set "xtime" correctly. However, the
-        * value in this location is the value at the most recent update of
-        * wall time.  Discover what correction gettimeofday() would have
-        * made, and then undo it!
-        */
-       nsec -= 0 * NSEC_PER_USEC;
-       nsec -= (jiffies - wall_jiffies) * TICK_NSEC;
-
-       wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
-       wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
-
-       set_normalized_timespec(&xtime, sec, nsec);
-       set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
-
-       ntp_clear();
-       write_sequnlock_irq(&xtime_lock);
-       clock_was_set();
-       return 0;
-}
-
-EXPORT_SYMBOL(do_settimeofday);
-
 /*
  * Scheduler clock - returns current time in nanosec units.
  */
index 12701cf..fef0657 100644 (file)
@@ -1605,8 +1605,8 @@ sys_call_table:
        data8 sys_ni_syscall                    // 1295 reserved for ppoll
        data8 sys_unshare
        data8 sys_splice
-       data8 sys_set_robust_list
-       data8 sys_get_robust_list
+       data8 sys_ni_syscall                    // reserved for set_robust_list
+       data8 sys_ni_syscall                    // reserved for get_robust_list
        data8 sys_sync_file_range               // 1300
        data8 sys_tee
        data8 sys_vmsplice
index 29236f0..44d540e 100644 (file)
@@ -197,6 +197,11 @@ start_ap:
        ;;
        srlz.i
        ;;
+ {
+       flushrs                         // must be first insn in group
+       srlz.i
+ }
+       ;;
        /*
         * Save the region registers, predicate before they get clobbered
         */
index c7ccd6e..84a7e52 100644 (file)
@@ -4936,13 +4936,15 @@ abort_locked:
        if (likely(ctx)) {
                DPRINT(("context unlocked\n"));
                UNPROTECT_CTX(ctx, flags);
-               fput(file);
        }
 
        /* copy argument back to user, if needed */
        if (call_made && PFM_CMD_RW_ARG(cmd) && copy_to_user(arg, args_k, base_sz*count)) ret = -EFAULT;
 
 error_args:
+       if (file)
+               fput(file);
+
        kfree(args_k);
 
        DPRINT(("cmd=%s ret=%ld\n", PFM_CMD_NAME(cmd), ret));
index 40722d8..9ef62a3 100644 (file)
@@ -163,10 +163,25 @@ sys_pipe (void)
        return retval;
 }
 
+int ia64_mmap_check(unsigned long addr, unsigned long len,
+               unsigned long flags)
+{
+       unsigned long roff;
+
+       /*
+        * Don't permit mappings into unmapped space, the virtual page table
+        * of a region, or across a region boundary.  Note: RGN_MAP_LIMIT is
+        * equal to 2^n-PAGE_SIZE (for some integer n <= 61) and len > 0.
+        */
+       roff = REGION_OFFSET(addr);
+       if ((len > RGN_MAP_LIMIT) || (roff > (RGN_MAP_LIMIT - len)))
+               return -EINVAL;
+       return 0;
+}
+
 static inline unsigned long
 do_mmap2 (unsigned long addr, unsigned long len, int prot, int flags, int fd, unsigned long pgoff)
 {
-       unsigned long roff;
        struct file *file = NULL;
 
        flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
@@ -188,17 +203,6 @@ do_mmap2 (unsigned long addr, unsigned long len, int prot, int flags, int fd, un
                goto out;
        }
 
-       /*
-        * Don't permit mappings into unmapped space, the virtual page table of a region,
-        * or across a region boundary.  Note: RGN_MAP_LIMIT is equal to 2^n-PAGE_SIZE
-        * (for some integer n <= 61) and len > 0.
-        */
-       roff = REGION_OFFSET(addr);
-       if ((len > RGN_MAP_LIMIT) || (roff > (RGN_MAP_LIMIT - len))) {
-               addr = -EINVAL;
-               goto out;
-       }
-
        down_write(&current->mm->mmap_sem);
        addr = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
        up_write(&current->mm->mmap_sem);
index c119e8b..5f2dcba 100644 (file)
@@ -565,7 +565,7 @@ static void __init sn_init_pdas(char **cmdline_p)
  * Also sets up a few fields in the nodepda.  Also known as
  * platform_cpu_init() by the ia64 machvec code.
  */
-void __init sn_cpu_init(void)
+void __cpuinit sn_cpu_init(void)
 {
        int cpuid;
        int cpuphyid;
index a41c8a5..94ff58c 100644 (file)
@@ -219,6 +219,21 @@ out:
        return err;
 }
 
+int sparc_mmap_check(unsigned long addr, unsigned long len, unsigned long flags)
+{
+       if (ARCH_SUN4C_SUN4 &&
+           (len > 0x20000000 ||
+            ((flags & MAP_FIXED) &&
+             addr < 0xe0000000 && addr + len > 0x20000000)))
+               return -EINVAL;
+
+       /* See asm-sparc/uaccess.h */
+       if (len > TASK_SIZE - PAGE_SIZE || addr + len > TASK_SIZE - PAGE_SIZE)
+               return -EINVAL;
+
+       return 0;
+}
+
 /* Linux version of mmap */
 static unsigned long do_mmap2(unsigned long addr, unsigned long len,
        unsigned long prot, unsigned long flags, unsigned long fd,
@@ -233,25 +248,13 @@ static unsigned long do_mmap2(unsigned long addr, unsigned long len,
                        goto out;
        }
 
-       retval = -EINVAL;
        len = PAGE_ALIGN(len);
-       if (ARCH_SUN4C_SUN4 &&
-           (len > 0x20000000 ||
-            ((flags & MAP_FIXED) &&
-             addr < 0xe0000000 && addr + len > 0x20000000)))
-               goto out_putf;
-
-       /* See asm-sparc/uaccess.h */
-       if (len > TASK_SIZE - PAGE_SIZE || addr + len > TASK_SIZE - PAGE_SIZE)
-               goto out_putf;
-
        flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 
        down_write(&current->mm->mmap_sem);
        retval = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
        up_write(&current->mm->mmap_sem);
 
-out_putf:
        if (file)
                fput(file);
 out:
index 054d0ab..bf5f14e 100644 (file)
@@ -548,6 +548,26 @@ asmlinkage long sparc64_personality(unsigned long personality)
        return ret;
 }
 
+int sparc64_mmap_check(unsigned long addr, unsigned long len,
+               unsigned long flags)
+{
+       if (test_thread_flag(TIF_32BIT)) {
+               if (len >= STACK_TOP32)
+                       return -EINVAL;
+
+               if ((flags & MAP_FIXED) && addr > STACK_TOP32 - len)
+                       return -EINVAL;
+       } else {
+               if (len >= VA_EXCLUDE_START)
+                       return -EINVAL;
+
+               if ((flags & MAP_FIXED) && invalid_64bit_range(addr, len))
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
 /* Linux version of mmap */
 asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
        unsigned long prot, unsigned long flags, unsigned long fd,
@@ -563,27 +583,11 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
        }
        flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
        len = PAGE_ALIGN(len);
-       retval = -EINVAL;
-
-       if (test_thread_flag(TIF_32BIT)) {
-               if (len >= STACK_TOP32)
-                       goto out_putf;
-
-               if ((flags & MAP_FIXED) && addr > STACK_TOP32 - len)
-                       goto out_putf;
-       } else {
-               if (len >= VA_EXCLUDE_START)
-                       goto out_putf;
-
-               if ((flags & MAP_FIXED) && invalid_64bit_range(addr, len))
-                       goto out_putf;
-       }
 
        down_write(&current->mm->mmap_sem);
        retval = do_mmap(file, addr, len, prot, flags, off);
        up_write(&current->mm->mmap_sem);
 
-out_putf:
        if (file)
                fput(file);
 out:
index c12f1b7..41b74b1 100644 (file)
@@ -376,6 +376,8 @@ static int proc_ide_read_media
                                break;
                case ide_floppy:media = "floppy\n";
                                break;
+               case ide_optical:media = "optical\n";
+                               break;
                default:        media = "UNKNOWN\n";
                                break;
        }
index a7c725f..f286079 100644 (file)
@@ -425,12 +425,12 @@ static int __devinit aec62xx_init_one(struct pci_dev *dev, const struct pci_devi
        return d->init_setup(dev, d);
 }
 
-static const struct pci_device_id aec62xx_pci_tbl[] = {
-       { PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP850UF), 0 },
-       { PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860), 1 },
-       { PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860R), 2 },
-       { PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP865), 3 },
-       { PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP865R), 4 },
+static struct pci_device_id aec62xx_pci_tbl[] = {
+       { PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP850UF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+       { PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860,   PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
+       { PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860R,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 },
+       { PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP865,   PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 },
+       { PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP865R,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
        { 0, },
 };
 MODULE_DEVICE_TABLE(pci, aec62xx_pci_tbl);
index 03677bf..f063d95 100644 (file)
@@ -649,11 +649,11 @@ static int __devinit svwks_init_one(struct pci_dev *dev, const struct pci_device
 }
 
 static struct pci_device_id svwks_pci_tbl[] = {
-       { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE), 0},
-       { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE), 1},
-       { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE), 2},
-       { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2), 3},
-       { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000IDE), 4},
+       { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+       { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+       { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+       { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
        { 0, },
 };
 MODULE_DEVICE_TABLE(pci, svwks_pci_tbl);
index 25ceb4a..20b3929 100644 (file)
@@ -1082,10 +1082,10 @@ static int __devinit siimage_init_one(struct pci_dev *dev, const struct pci_devi
 }
 
 static struct pci_device_id siimage_pci_tbl[] = {
-       { PCI_DEVICE(PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_680), 0},
+       { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_680,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 #ifdef CONFIG_BLK_DEV_IDE_SATA
-       { PCI_DEVICE(PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_3112), 1},
-       { PCI_DEVICE(PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_1210SA), 2},
+       { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+       { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_1210SA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
 #endif
        { 0, },
 };
index 8a6c23a..f03196c 100644 (file)
@@ -86,6 +86,8 @@ static const struct {
        u8 chipset_family;
        u8 flags;
 } SiSHostChipInfo[] = {
+       { "SiS968",     PCI_DEVICE_ID_SI_968,   ATA_133  },
+       { "SiS966",     PCI_DEVICE_ID_SI_966,   ATA_133  },
        { "SiS965",     PCI_DEVICE_ID_SI_965,   ATA_133  },
        { "SiS745",     PCI_DEVICE_ID_SI_745,   ATA_100  },
        { "SiS735",     PCI_DEVICE_ID_SI_735,   ATA_100  },
index 30b3671..a2bd811 100644 (file)
@@ -2393,7 +2393,7 @@ config MYRI10GE
          you will need a newer firmware image.
          You may get this image or more information, at:
 
-         <http://www.myri.com/Myri-10G/>
+         <http://www.myri.com/scs/download-Myri10GE.html>
 
          To compile this driver as a module, choose M here and read
          <file:Documentation/networking/net-modules.txt>.  The module
index 01d4036..a3727af 100644 (file)
@@ -77,6 +77,7 @@ static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 static void vt6420_error_handler(struct ata_port *ap);
 
 static const struct pci_device_id svia_pci_tbl[] = {
+       { 0x1106, 0x0591, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6420 },
        { 0x1106, 0x3149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6420 },
        { 0x1106, 0x3249, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6421 },
 
index c5ee9f0..0f0b1ea 100644 (file)
@@ -1009,11 +1009,14 @@ struct buffer_head *ext3_getblk(handle_t *handle, struct inode *inode,
        buffer_trace_init(&dummy.b_history);
        err = ext3_get_blocks_handle(handle, inode, block, 1,
                                        &dummy, create, 1);
-       if (err == 1) {
+       /*
+        * ext3_get_blocks_handle() returns number of blocks
+        * mapped. 0 in case of a HOLE.
+        */
+       if (err > 0) {
+               if (err > 1)
+                       WARN_ON(1);
                err = 0;
-       } else if (err >= 0) {
-               WARN_ON(1);
-               err = -EIO;
        }
        *errp = err;
        if (!err && buffer_mapped(&dummy)) {
index fecd3b0..76ca1cb 100644 (file)
@@ -100,25 +100,6 @@ static inline int put_dreq(struct nfs_direct_req *dreq)
        return atomic_dec_and_test(&dreq->io_count);
 }
 
-/*
- * "size" is never larger than rsize or wsize.
- */
-static inline int nfs_direct_count_pages(unsigned long user_addr, size_t size)
-{
-       int page_count;
-
-       page_count = (user_addr + size + PAGE_SIZE - 1) >> PAGE_SHIFT;
-       page_count -= user_addr >> PAGE_SHIFT;
-       BUG_ON(page_count < 0);
-
-       return page_count;
-}
-
-static inline unsigned int nfs_max_pages(unsigned int size)
-{
-       return (size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-}
-
 /**
  * nfs_direct_IO - NFS address space operation for direct I/O
  * @rw: direction (read or write)
@@ -276,28 +257,24 @@ static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned lo
        struct nfs_open_context *ctx = dreq->ctx;
        struct inode *inode = ctx->dentry->d_inode;
        size_t rsize = NFS_SERVER(inode)->rsize;
-       unsigned int rpages = nfs_max_pages(rsize);
        unsigned int pgbase;
        int result;
        ssize_t started = 0;
 
        get_dreq(dreq);
 
-       pgbase = user_addr & ~PAGE_MASK;
        do {
                struct nfs_read_data *data;
                size_t bytes;
 
+               pgbase = user_addr & ~PAGE_MASK;
+               bytes = min(rsize,count);
+
                result = -ENOMEM;
-               data = nfs_readdata_alloc(rpages);
+               data = nfs_readdata_alloc(pgbase + bytes);
                if (unlikely(!data))
                        break;
 
-               bytes = rsize;
-               if (count < rsize)
-                       bytes = count;
-
-               data->npages = nfs_direct_count_pages(user_addr, bytes);
                down_read(&current->mm->mmap_sem);
                result = get_user_pages(current, current->mm, user_addr,
                                        data->npages, 1, 0, data->pagevec, NULL);
@@ -344,8 +321,10 @@ static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned lo
                started += bytes;
                user_addr += bytes;
                pos += bytes;
+               /* FIXME: Remove this unnecessary math from final patch */
                pgbase += bytes;
                pgbase &= ~PAGE_MASK;
+               BUG_ON(pgbase != (user_addr & ~PAGE_MASK));
 
                count -= bytes;
        } while (count != 0);
@@ -524,7 +503,7 @@ static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode
 
 static void nfs_alloc_commit_data(struct nfs_direct_req *dreq)
 {
-       dreq->commit_data = nfs_commit_alloc(0);
+       dreq->commit_data = nfs_commit_alloc();
        if (dreq->commit_data != NULL)
                dreq->commit_data->req = (struct nfs_page *) dreq;
 }
@@ -605,28 +584,24 @@ static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned l
        struct nfs_open_context *ctx = dreq->ctx;
        struct inode *inode = ctx->dentry->d_inode;
        size_t wsize = NFS_SERVER(inode)->wsize;
-       unsigned int wpages = nfs_max_pages(wsize);
        unsigned int pgbase;
        int result;
        ssize_t started = 0;
 
        get_dreq(dreq);
 
-       pgbase = user_addr & ~PAGE_MASK;
        do {
                struct nfs_write_data *data;
                size_t bytes;
 
+               pgbase = user_addr & ~PAGE_MASK;
+               bytes = min(wsize,count);
+
                result = -ENOMEM;
-               data = nfs_writedata_alloc(wpages);
+               data = nfs_writedata_alloc(pgbase + bytes);
                if (unlikely(!data))
                        break;
 
-               bytes = wsize;
-               if (count < wsize)
-                       bytes = count;
-
-               data->npages = nfs_direct_count_pages(user_addr, bytes);
                down_read(&current->mm->mmap_sem);
                result = get_user_pages(current, current->mm, user_addr,
                                        data->npages, 0, 0, data->pagevec, NULL);
@@ -676,8 +651,11 @@ static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned l
                started += bytes;
                user_addr += bytes;
                pos += bytes;
+
+               /* FIXME: Remove this useless math from the final patch */
                pgbase += bytes;
                pgbase &= ~PAGE_MASK;
+               BUG_ON(pgbase != (user_addr & ~PAGE_MASK));
 
                count -= bytes;
        } while (count != 0);
index da9cf11..7a9ee00 100644 (file)
@@ -43,13 +43,15 @@ static mempool_t *nfs_rdata_mempool;
 
 #define MIN_POOL_READ  (32)
 
-struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount)
+struct nfs_read_data *nfs_readdata_alloc(size_t len)
 {
+       unsigned int pagecount = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
        struct nfs_read_data *p = mempool_alloc(nfs_rdata_mempool, SLAB_NOFS);
 
        if (p) {
                memset(p, 0, sizeof(*p));
                INIT_LIST_HEAD(&p->pages);
+               p->npages = pagecount;
                if (pagecount <= ARRAY_SIZE(p->page_array))
                        p->pagevec = p->page_array;
                else {
@@ -140,7 +142,7 @@ static int nfs_readpage_sync(struct nfs_open_context *ctx, struct inode *inode,
        int             result;
        struct nfs_read_data *rdata;
 
-       rdata = nfs_readdata_alloc(1);
+       rdata = nfs_readdata_alloc(count);
        if (!rdata)
                return -ENOMEM;
 
@@ -336,25 +338,25 @@ static int nfs_pagein_multi(struct list_head *head, struct inode *inode)
        struct nfs_page *req = nfs_list_entry(head->next);
        struct page *page = req->wb_page;
        struct nfs_read_data *data;
-       unsigned int rsize = NFS_SERVER(inode)->rsize;
-       unsigned int nbytes, offset;
+       size_t rsize = NFS_SERVER(inode)->rsize, nbytes;
+       unsigned int offset;
        int requests = 0;
        LIST_HEAD(list);
 
        nfs_list_remove_request(req);
 
        nbytes = req->wb_bytes;
-       for(;;) {
-               data = nfs_readdata_alloc(1);
+       do {
+               size_t len = min(nbytes,rsize);
+
+               data = nfs_readdata_alloc(len);
                if (!data)
                        goto out_bad;
                INIT_LIST_HEAD(&data->pages);
                list_add(&data->pages, &list);
                requests++;
-               if (nbytes <= rsize)
-                       break;
-               nbytes -= rsize;
-       }
+               nbytes -= len;
+       } while(nbytes != 0);
        atomic_set(&req->wb_complete, requests);
 
        ClearPageError(page);
@@ -402,7 +404,7 @@ static int nfs_pagein_one(struct list_head *head, struct inode *inode)
        if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE)
                return nfs_pagein_multi(head, inode);
 
-       data = nfs_readdata_alloc(NFS_SERVER(inode)->rpages);
+       data = nfs_readdata_alloc(NFS_SERVER(inode)->rsize);
        if (!data)
                goto out_bad;
 
index 5077499..8ab3cf1 100644 (file)
@@ -90,22 +90,13 @@ static mempool_t *nfs_commit_mempool;
 
 static DECLARE_WAIT_QUEUE_HEAD(nfs_write_congestion);
 
-struct nfs_write_data *nfs_commit_alloc(unsigned int pagecount)
+struct nfs_write_data *nfs_commit_alloc(void)
 {
        struct nfs_write_data *p = mempool_alloc(nfs_commit_mempool, SLAB_NOFS);
 
        if (p) {
                memset(p, 0, sizeof(*p));
                INIT_LIST_HEAD(&p->pages);
-               if (pagecount <= ARRAY_SIZE(p->page_array))
-                       p->pagevec = p->page_array;
-               else {
-                       p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_NOFS);
-                       if (!p->pagevec) {
-                               mempool_free(p, nfs_commit_mempool);
-                               p = NULL;
-                       }
-               }
        }
        return p;
 }
@@ -117,13 +108,15 @@ void nfs_commit_free(struct nfs_write_data *p)
        mempool_free(p, nfs_commit_mempool);
 }
 
-struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount)
+struct nfs_write_data *nfs_writedata_alloc(size_t len)
 {
+       unsigned int pagecount = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
        struct nfs_write_data *p = mempool_alloc(nfs_wdata_mempool, SLAB_NOFS);
 
        if (p) {
                memset(p, 0, sizeof(*p));
                INIT_LIST_HEAD(&p->pages);
+               p->npages = pagecount;
                if (pagecount <= ARRAY_SIZE(p->page_array))
                        p->pagevec = p->page_array;
                else {
@@ -208,7 +201,7 @@ static int nfs_writepage_sync(struct nfs_open_context *ctx, struct inode *inode,
        int             result, written = 0;
        struct nfs_write_data *wdata;
 
-       wdata = nfs_writedata_alloc(1);
+       wdata = nfs_writedata_alloc(wsize);
        if (!wdata)
                return -ENOMEM;
 
@@ -999,24 +992,24 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, int how)
        struct nfs_page *req = nfs_list_entry(head->next);
        struct page *page = req->wb_page;
        struct nfs_write_data *data;
-       unsigned int wsize = NFS_SERVER(inode)->wsize;
-       unsigned int nbytes, offset;
+       size_t wsize = NFS_SERVER(inode)->wsize, nbytes;
+       unsigned int offset;
        int requests = 0;
        LIST_HEAD(list);
 
        nfs_list_remove_request(req);
 
        nbytes = req->wb_bytes;
-       for (;;) {
-               data = nfs_writedata_alloc(1);
+       do {
+               size_t len = min(nbytes, wsize);
+
+               data = nfs_writedata_alloc(len);
                if (!data)
                        goto out_bad;
                list_add(&data->pages, &list);
                requests++;
-               if (nbytes <= wsize)
-                       break;
-               nbytes -= wsize;
-       }
+               nbytes -= len;
+       } while (nbytes != 0);
        atomic_set(&req->wb_complete, requests);
 
        ClearPageError(page);
@@ -1070,7 +1063,7 @@ static int nfs_flush_one(struct inode *inode, struct list_head *head, int how)
        struct nfs_write_data   *data;
        unsigned int            count;
 
-       data = nfs_writedata_alloc(NFS_SERVER(inode)->wpages);
+       data = nfs_writedata_alloc(NFS_SERVER(inode)->wsize);
        if (!data)
                goto out_bad;
 
@@ -1378,7 +1371,7 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how)
        struct nfs_write_data   *data;
        struct nfs_page         *req;
 
-       data = nfs_commit_alloc(NFS_SERVER(inode)->wpages);
+       data = nfs_commit_alloc();
 
        if (!data)
                goto out_bad;
index 6d4e817..5c4c94d 100644 (file)
@@ -49,6 +49,7 @@ DEFINE_SPINLOCK(sb_lock);
 
 /**
  *     alloc_super     -       create new superblock
+ *     @type:  filesystem type superblock should belong to
  *
  *     Allocates and initializes a new &struct super_block.  alloc_super()
  *     returns a pointer new superblock or %NULL if allocation had failed.
index c064a8e..335b2fa 100644 (file)
@@ -1,5 +1,5 @@
 include include/asm-generic/Kbuild.asm
 
-header-y += boot.h cpufeature.h debugreg.h ldt.h setup.h ucontext.h
+header-y += boot.h debugreg.h ldt.h setup.h ucontext.h
 
 unifdef-y += mtrr.h vm86.h
index 6ba179f..c73b878 100644 (file)
 #define MCL_CURRENT    1               /* lock all current mappings */
 #define MCL_FUTURE     2               /* lock all future mappings */
 
+#ifdef __KERNEL__
+#ifndef __ASSEMBLY__
+#define arch_mmap_check        ia64_mmap_check
+int ia64_mmap_check(unsigned long addr, unsigned long len,
+               unsigned long flags);
+#endif
+#endif
+
 #endif /* _ASM_IA64_MMAN_H */
index bb0eb72..f581662 100644 (file)
 /* 1294, 1295 reserved for pselect/ppoll */
 #define __NR_unshare                   1296
 #define __NR_splice                    1297
-#define __NR_set_robust_list           1298
-#define __NR_get_robust_list           1299
+/* 1298, 1299 reserved for set_robust_list/get_robust_list */
 #define __NR_sync_file_range           1300
 #define __NR_tee                       1301
 #define __NR_vmsplice                  1302
index a5559e3..5a057b0 100644 (file)
@@ -104,7 +104,7 @@ typedef struct { unsigned long pgprot; } pgprot_t;
 
 /* PFN start number, because of __MEMORY_START */
 #define PFN_START              (__MEMORY_START >> PAGE_SHIFT)
-#define ARCH_PFN_OFFSET                (FPN_START)
+#define ARCH_PFN_OFFSET                (PFN_START)
 #define virt_to_page(kaddr)    pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
 #define pfn_valid(pfn)         (((pfn) - PFN_START) < max_mapnr)
 #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
index 88d1886..b7dc40b 100644 (file)
 
 #define MADV_FREE      0x5             /* (Solaris) contents can be freed */
 
+#ifdef __KERNEL__
+#ifndef __ASSEMBLY__
+#define arch_mmap_check        sparc_mmap_check
+int sparc_mmap_check(unsigned long addr, unsigned long len,
+               unsigned long flags);
+#endif
+#endif
+
 #endif /* __SPARC_MMAN_H__ */
index 6fd878e..8cc1860 100644 (file)
 
 #define MADV_FREE      0x5             /* (Solaris) contents can be freed */
 
+#ifdef __KERNEL__
+#ifndef __ASSEMBLY__
+#define arch_mmap_check        sparc64_mmap_check
+int sparc64_mmap_check(unsigned long addr, unsigned long len,
+               unsigned long flags);
+#endif
+#endif
+
 #endif /* __SPARC64_MMAN_H__ */
index 41788a3..2096e5c 100644 (file)
@@ -7,7 +7,6 @@
 #define LINUX_ATMDEV_H
 
 
-#include <linux/device.h>
 #include <linux/atmapi.h>
 #include <linux/atm.h>
 #include <linux/atmioc.h>
@@ -210,6 +209,7 @@ struct atm_cirange {
 
 #ifdef __KERNEL__
 
+#include <linux/device.h>
 #include <linux/wait.h> /* wait_queue_head_t */
 #include <linux/time.h> /* struct timeval */
 #include <linux/net.h>
index e4bccbc..4fc379d 100644 (file)
@@ -80,6 +80,7 @@ struct hrtimer_sleeper {
  * @get_softirq_time:  function to retrieve the current time from the softirq
  * @curr_timer:                the timer which is executing a callback right now
  * @softirq_time:      the time when running the hrtimer queue in the softirq
+ * @lock_key:          the lock_class_key for use with lockdep
  */
 struct hrtimer_base {
        clockid_t               index;
index ed3396d..84eeecd 100644 (file)
@@ -56,7 +56,8 @@ typedef union {
 #endif
 } ktime_t;
 
-#define KTIME_MAX                      (~((u64)1 << 63))
+#define KTIME_MAX                      ((s64)~((u64)1 << 63))
+#define KTIME_SEC_MAX                  (KTIME_MAX / NSEC_PER_SEC)
 
 /*
  * ktime_t definitions when using the 64-bit scalar representation:
@@ -73,6 +74,10 @@ typedef union {
  */
 static inline ktime_t ktime_set(const long secs, const unsigned long nsecs)
 {
+#if (BITS_PER_LONG == 64)
+       if (unlikely(secs >= KTIME_SEC_MAX))
+               return (ktime_t){ .tv64 = KTIME_MAX };
+#endif
        return (ktime_t) { .tv64 = (s64)secs * NSEC_PER_SEC + (s64)nsecs };
 }
 
index 2474345..530b1e6 100644 (file)
@@ -427,7 +427,7 @@ extern int nfs_writeback_done(struct rpc_task *, struct nfs_write_data *);
 extern void nfs_writedata_release(void *);
 
 #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
-struct nfs_write_data *nfs_commit_alloc(unsigned int pagecount);
+struct nfs_write_data *nfs_commit_alloc(void);
 void nfs_commit_free(struct nfs_write_data *p);
 #endif
 
@@ -478,7 +478,7 @@ static inline int nfs_wb_page(struct inode *inode, struct page* page)
 /*
  * Allocate nfs_write_data structures
  */
-extern struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount);
+extern struct nfs_write_data *nfs_writedata_alloc(size_t len);
 
 /*
  * linux/fs/nfs/read.c
@@ -492,7 +492,7 @@ extern void nfs_readdata_release(void *data);
 /*
  * Allocate nfs_read_data structures
  */
-extern struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount);
+extern struct nfs_read_data *nfs_readdata_alloc(size_t len);
 
 /*
  * linux/fs/nfs3proc.c
index db9cbf6..41e5a19 100644 (file)
@@ -729,7 +729,7 @@ struct nfs_read_data {
        struct list_head        pages;  /* Coalesced read requests */
        struct nfs_page         *req;   /* multi ops per nfs_page */
        struct page             **pagevec;
-       unsigned int            npages; /* active pages in pagevec */
+       unsigned int            npages; /* Max length of pagevec */
        struct nfs_readargs args;
        struct nfs_readres  res;
 #ifdef CONFIG_NFS_V4
@@ -748,7 +748,7 @@ struct nfs_write_data {
        struct list_head        pages;          /* Coalesced requests we wish to flush */
        struct nfs_page         *req;           /* multi ops per nfs_page */
        struct page             **pagevec;
-       unsigned int            npages;         /* active pages in pagevec */
+       unsigned int            npages;         /* Max length of pagevec */
        struct nfs_writeargs    args;           /* argument struct */
        struct nfs_writeres     res;            /* result struct */
 #ifdef CONFIG_NFS_V4
index c91164e..7a24915 100644 (file)
 #define PCI_DEVICE_ID_SI_962           0x0962
 #define PCI_DEVICE_ID_SI_963           0x0963
 #define PCI_DEVICE_ID_SI_965           0x0965
+#define PCI_DEVICE_ID_SI_966           0x0966
+#define PCI_DEVICE_ID_SI_968           0x0968
 #define PCI_DEVICE_ID_SI_5511          0x5511
 #define PCI_DEVICE_ID_SI_5513          0x5513
 #define PCI_DEVICE_ID_SI_5517          0x5517
index b9b8aea..9d260e8 100644 (file)
@@ -1120,9 +1120,10 @@ static int futex_wait(u32 __user *uaddr, u32 val, unsigned long time)
  * if there are waiters then it will block, it does PI, etc. (Due to
  * races the kernel might see a 0 value of the futex too.)
  */
-static int do_futex_lock_pi(u32 __user *uaddr, int detect, int trylock,
-                           struct hrtimer_sleeper *to)
+static int futex_lock_pi(u32 __user *uaddr, int detect, unsigned long sec,
+                        long nsec, int trylock)
 {
+       struct hrtimer_sleeper timeout, *to = NULL;
        struct task_struct *curr = current;
        struct futex_hash_bucket *hb;
        u32 uval, newval, curval;
@@ -1132,6 +1133,13 @@ static int do_futex_lock_pi(u32 __user *uaddr, int detect, int trylock,
        if (refill_pi_state_cache())
                return -ENOMEM;
 
+       if (sec != MAX_SCHEDULE_TIMEOUT) {
+               to = &timeout;
+               hrtimer_init(&to->timer, CLOCK_REALTIME, HRTIMER_ABS);
+               hrtimer_init_sleeper(to, current);
+               to->timer.expires = ktime_set(sec, nsec);
+       }
+
        q.pi_state = NULL;
  retry:
        down_read(&curr->mm->mmap_sem);
@@ -1307,7 +1315,7 @@ static int do_futex_lock_pi(u32 __user *uaddr, int detect, int trylock,
        if (!detect && ret == -EDEADLK && 0)
                force_sig(SIGKILL, current);
 
-       return ret;
+       return ret != -EINTR ? ret : -ERESTARTNOINTR;
 
  out_unlock_release_sem:
        queue_unlock(&q, hb);
@@ -1341,76 +1349,6 @@ static int do_futex_lock_pi(u32 __user *uaddr, int detect, int trylock,
        return ret;
 }
 
-/*
- * Restart handler
- */
-static long futex_lock_pi_restart(struct restart_block *restart)
-{
-       struct hrtimer_sleeper timeout, *to = NULL;
-       int ret;
-
-       restart->fn = do_no_restart_syscall;
-
-       if (restart->arg2 || restart->arg3) {
-               to = &timeout;
-               hrtimer_init(&to->timer, CLOCK_REALTIME, HRTIMER_ABS);
-               hrtimer_init_sleeper(to, current);
-               to->timer.expires.tv64 = ((u64)restart->arg1 << 32) |
-                       (u64) restart->arg0;
-       }
-
-       pr_debug("lock_pi restart: %p, %d (%d)\n",
-                (u32 __user *)restart->arg0, current->pid);
-
-       ret = do_futex_lock_pi((u32 __user *)restart->arg0, restart->arg1,
-                              0, to);
-
-       if (ret != -EINTR)
-               return ret;
-
-       restart->fn = futex_lock_pi_restart;
-
-       /* The other values are filled in */
-       return -ERESTART_RESTARTBLOCK;
-}
-
-/*
- * Called from the syscall entry below.
- */
-static int futex_lock_pi(u32 __user *uaddr, int detect, unsigned long sec,
-                        long nsec, int trylock)
-{
-       struct hrtimer_sleeper timeout, *to = NULL;
-       struct restart_block *restart;
-       int ret;
-
-       if (sec != MAX_SCHEDULE_TIMEOUT) {
-               to = &timeout;
-               hrtimer_init(&to->timer, CLOCK_REALTIME, HRTIMER_ABS);
-               hrtimer_init_sleeper(to, current);
-               to->timer.expires = ktime_set(sec, nsec);
-       }
-
-       ret = do_futex_lock_pi(uaddr, detect, trylock, to);
-
-       if (ret != -EINTR)
-               return ret;
-
-       pr_debug("lock_pi interrupted: %p, %d (%d)\n", uaddr, current->pid);
-
-       restart = &current_thread_info()->restart_block;
-       restart->fn = futex_lock_pi_restart;
-       restart->arg0 = (unsigned long) uaddr;
-       restart->arg1 = detect;
-       if (to) {
-               restart->arg2 = to->timer.expires.tv64 & 0xFFFFFFFF;
-               restart->arg3 = to->timer.expires.tv64 >> 32;
-       } else
-               restart->arg2 = restart->arg3 = 0;
-
-       return -ERESTART_RESTARTBLOCK;
-}
-
 /*
  * Userspace attempted a TID -> 0 atomic transition, and failed.
  * This is the in-kernel slowpath: we look up the PI state (if any),
index 9b8dcfd..8010b9b 100644 (file)
@@ -173,7 +173,7 @@ const char *print_tainted(void)
 
 void add_taint(unsigned flag)
 {
-       debug_locks_off(); /* can't trust the integrity of the kernel anymore */
+       debug_locks = 0; /* can't trust the integrity of the kernel anymore */
        tainted |= flag;
 }
 EXPORT_SYMBOL(add_taint);
index ae44a70..619ecab 100644 (file)
@@ -56,7 +56,7 @@ config PM_TRACE
 
 config SOFTWARE_SUSPEND
        bool "Software Suspend"
-       depends on PM && SWAP && (X86 && (!SMP || SUSPEND_SMP)) || ((FRV || PPC32) && !SMP)
+       depends on PM && SWAP && ((X86 && (!SMP || SUSPEND_SMP) && !X86_PAE) || ((FRV || PPC32) && !SMP))
        ---help---
          Enable the possibility of suspending the machine.
          It doesn't need ACPI or APM.
@@ -78,6 +78,10 @@ config SOFTWARE_SUSPEND
 
          For more information take a look at <file:Documentation/power/swsusp.txt>.
 
+         (For now, swsusp is incompatible with PAE aka HIGHMEM_64G on i386.
+         we need identity mapping for resume to work, and that is trivial
+         to get with 4MB pages, but less than trivial on PAE).
+
 config PM_STD_PARTITION
        string "Default resume partition"
        depends on SOFTWARE_SUSPEND
index bfd6ad9..fb524b0 100644 (file)
@@ -72,7 +72,7 @@ EXPORT_SYMBOL(_write_trylock);
  * not re-enabled during lock-acquire (which the preempt-spin-ops do):
  */
 #if !defined(CONFIG_PREEMPT) || !defined(CONFIG_SMP) || \
-       defined(CONFIG_PROVE_LOCKING)
+       defined(CONFIG_DEBUG_LOCK_ALLOC)
 
 void __lockfunc _read_lock(rwlock_t *lock)
 {
index c1868ec..e66a0b5 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
 #include <asm/cacheflush.h>
 #include <asm/tlb.h>
 
+#ifndef arch_mmap_check
+#define arch_mmap_check(addr, len, flags)      (0)
+#endif
+
 static void unmap_region(struct mm_struct *mm,
                struct vm_area_struct *vma, struct vm_area_struct *prev,
                unsigned long start, unsigned long end);
@@ -913,6 +917,10 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
        if (!len)
                return -EINVAL;
 
+       error = arch_mmap_check(addr, len, flags);
+       if (error)
+               return error;
+
        /* Careful about overflows.. */
        len = PAGE_ALIGN(len);
        if (!len || len > TASK_SIZE)
@@ -1859,6 +1867,7 @@ unsigned long do_brk(unsigned long addr, unsigned long len)
        unsigned long flags;
        struct rb_node ** rb_link, * rb_parent;
        pgoff_t pgoff = addr >> PAGE_SHIFT;
+       int error;
 
        len = PAGE_ALIGN(len);
        if (!len)
@@ -1867,6 +1876,12 @@ unsigned long do_brk(unsigned long addr, unsigned long len)
        if ((addr + len) > TASK_SIZE || (addr + len) < addr)
                return -EINVAL;
 
+       flags = VM_DATA_DEFAULT_FLAGS | VM_ACCOUNT | mm->def_flags;
+
+       error = arch_mmap_check(addr, len, flags);
+       if (error)
+               return error;
+
        /*
         * mlock MCL_FUTURE?
         */
@@ -1907,8 +1922,6 @@ unsigned long do_brk(unsigned long addr, unsigned long len)
        if (security_vm_enough_memory(len >> PAGE_SHIFT))
                return -ENOMEM;
 
-       flags = VM_DATA_DEFAULT_FLAGS | VM_ACCOUNT | mm->def_flags;
-
        /* Can we just expand an old private anonymous mapping? */
        if (vma_merge(mm, prev, addr, addr + len, flags,
                                        NULL, NULL, pgoff, NULL))
index cf1b015..c6ab55e 100644 (file)
@@ -68,10 +68,10 @@ invalidate_complete_page(struct address_space *mapping, struct page *page)
                return 0;
 
        write_lock_irq(&mapping->tree_lock);
-       if (PageDirty(page)) {
-               write_unlock_irq(&mapping->tree_lock);
-               return 0;
-       }
+       if (PageDirty(page))
+               goto failed;
+       if (page_count(page) != 2)      /* caller's ref + pagecache ref */
+               goto failed;
 
        BUG_ON(PagePrivate(page));
        __remove_from_page_cache(page);
@@ -79,6 +79,9 @@ invalidate_complete_page(struct address_space *mapping, struct page *page)
        ClearPageUptodate(page);
        page_cache_release(page);       /* pagecache ref */
        return 1;
+failed:
+       write_unlock_irq(&mapping->tree_lock);
+       return 0;
 }
 
 /**