diff -urN -X dontdiff linux/drivers/char/mem.c work/drivers/char/mem.c
--- linux/drivers/char/mem.c    Thu Dec 16 21:59:38 1999
+++ work/drivers/char/mem.c     Tue Dec 21 09:10:25 1999
@@ -227,6 +227,7 @@
       unsigned long p = *ppos;
       ssize_t read = 0;
       ssize_t virtr;
+       char * kbuf; /* k-addr because vread() takes vmlist_lock spinlock */

       if (p < (unsigned long) high_memory) {
               read = count;
@@ -238,22 +239,34 @@
               if (p < PAGE_SIZE && read > 0) {
                       size_t tmp = PAGE_SIZE - p;
                       if (tmp > read) tmp = read;
-                       clear_user(buf, tmp);
+                       if (clear_user(buf, tmp))
+                               return -EFAULT;
                       buf += tmp;
                       p += tmp;
                       read -= tmp;
                       count -= tmp;
               }
#endif
-               copy_to_user(buf, (char *)p, read);
+               if(copy_to_user(buf, (char *)p, read))
+                       return -EFAULT;
               p += read;
               buf += read;
               count -= read;
       }

-       virtr = vread(buf, (char *)p, count);
-       if (virtr < 0)
+       kbuf = vmalloc(count);
+       if (kbuf == NULL)
+               return -ENOMEM;
+       virtr = vread(kbuf, (char *)p, count);
+       if (virtr < 0) {
+               vfree(kbuf);
               return virtr;
+       }
+       if (copy_to_user(buf, kbuf, virtr)) {
+               vfree(kbuf);
+               return -EFAULT;
+       }
+       vfree(kbuf);
       *ppos += p + virtr;
       return virtr + read;
}
diff -urN -X dontdiff linux/fs/buffer.c work/fs/buffer.c
--- linux/fs/buffer.c   Mon Dec 20 22:52:57 1999
+++ work/fs/buffer.c    Tue Dec 21 08:14:50 1999
@@ -345,7 +345,6 @@
       struct inode * inode;
       int err;

-       lock_kernel();
       err = -EBADF;
       file = fget(fd);
       if (!file)
@@ -365,13 +364,14 @@

       /* We need to protect against concurrent writers.. */
       down(&inode->i_sem);
+       lock_kernel();
       err = file->f_op->fsync(file, dentry);
+       unlock_kernel();
       up(&inode->i_sem);

out_putf:
       fput(file);
out:
-       unlock_kernel();
       return err;
}

@@ -382,7 +382,6 @@
       struct inode * inode;
       int err;

-       lock_kernel();
       err = -EBADF;
       file = fget(fd);
       if (!file)
@@ -402,13 +401,14 @@

       /* this needs further work, at the moment it is identical to fsync() */
       down(&inode->i_sem);
+       lock_kernel();
       err = file->f_op->fsync(file, dentry);
+       unlock_kernel();
       up(&inode->i_sem);

out_putf:
       fput(file);
out:
-       unlock_kernel();
       return err;
}

diff -urN -X dontdiff linux/include/linux/mm.h work/include/linux/mm.h
--- linux/include/linux/mm.h    Tue Dec 21 00:01:14 1999
+++ work/include/linux/mm.h     Tue Dec 21 08:13:57 1999
@@ -244,8 +244,14 @@
 * The following discussion applies only to them.
 *
 * A page may belong to an inode's memory mapping. In this case,
- * page->inode is the pointer to the inode, and page->offset is the
- * file offset of the page (not necessarily a multiple of PAGE_SIZE).
+ * page->inode is the pointer to the inode, and page->index is the
+ * file offset of the page in PAGE_CACHE_SIZE (not PAGE_SIZE!) units.
+ * Although currently (2.3.34) PAGE_SIZE == PAGE_CACHE_SIZE, i.e. there
+ * happens to be one page per page cache entry and MM code can't hanlde
+ * anything else, this may well change. The link to the old page->offset
+ * is given by:
+ *
+ *         page->index == (page->offset >> PAGE_CACHE_SHIFT);
 *
 * A page may have buffers allocated to it. In this case,
 * page->buffers is a circular list of these buffer heads. Else,
diff -urN -X dontdiff linux/ipc/util.c work/ipc/util.c
--- linux/ipc/util.c    Tue Dec 14 18:01:21 1999
+++ work/ipc/util.c     Tue Dec 21 09:15:44 1999
@@ -161,13 +161,10 @@
void* ipc_alloc(int size)
{
       void* out;
-       if(size > PAGE_SIZE) {
-               lock_kernel();
+       if(size > PAGE_SIZE)
               out = vmalloc(size);
-               unlock_kernel();
-       } else {
+       else
               out = kmalloc(size, GFP_KERNEL);
-       }
       return out;
}

diff -urN -X dontdiff linux/mm/vmalloc.c work/mm/vmalloc.c
--- linux/mm/vmalloc.c  Sat Nov 20 18:09:05 1999
+++ work/mm/vmalloc.c   Tue Dec 21 09:12:12 1999
@@ -7,10 +7,12 @@

#include <linux/malloc.h>
#include <linux/vmalloc.h>
+#include <linux/spinlock.h>

#include <asm/uaccess.h>
#include <asm/pgalloc.h>

+spinlock_t vmlist_lock = SPIN_LOCK_UNLOCKED;
struct vm_struct * vmlist = NULL;

static inline void free_area_pte(pmd_t * pmd, unsigned long address, unsigned long size)
@@ -162,11 +164,13 @@
       if (!area)
               return NULL;
       addr = VMALLOC_START;
+       spin_lock(&vmlist_lock);
       for (p = &vmlist; (tmp = *p) ; p = &tmp->next) {
               if (size + addr < (unsigned long) tmp->addr)
                       break;
               addr = tmp->size + (unsigned long) tmp->addr;
               if (addr > VMALLOC_END-size) {
+                       spin_unlock(&vmlist_lock);
                       kfree(area);
                       return NULL;
               }
@@ -176,6 +180,7 @@
       area->size = size + PAGE_SIZE;
       area->next = *p;
       *p = area;
+       spin_unlock(&vmlist_lock);
       return area;
}

@@ -189,14 +194,17 @@
               printk(KERN_ERR "Trying to vfree() bad address (%p)\n", addr);
               return;
       }
+       spin_lock(&vmlist_lock);
       for (p = &vmlist ; (tmp = *p) ; p = &tmp->next) {
               if (tmp->addr == addr) {
                       *p = tmp->next;
                       vmfree_area_pages(VMALLOC_VMADDR(tmp->addr), tmp->size);
+                       spin_unlock(&vmlist_lock);
                       kfree(tmp);
                       return;
               }
       }
+       spin_unlock(&vmlist_lock);
       printk(KERN_ERR "Trying to vfree() nonexistent vm area (%p)\n", addr);
}

@@ -224,16 +232,17 @@
       return addr;
}

-long vread(char *buf, char *addr, unsigned long count)
+long vread(char *kbuf, char *addr, unsigned long count)
{
       struct vm_struct *tmp;
-       char *vaddr, *buf_start = buf;
+       char *vaddr, *buf_start = kbuf;
       unsigned long n;

       /* Don't allow overflow */
       if ((unsigned long) addr + count < count)
               count = -(unsigned long) addr;

+       spin_lock(&vmlist_lock);
       for (tmp = vmlist; tmp; tmp = tmp->next) {
               vaddr = (char *) tmp->addr;
               if (addr >= vaddr + tmp->size - PAGE_SIZE)
@@ -241,8 +250,8 @@
               while (addr < vaddr) {
                       if (count == 0)
                               goto finished;
-                       put_user('\0', buf);
-                       buf++;
+                       *kbuf = '\0';
+                       kbuf++;
                       addr++;
                       count--;
               }
@@ -250,12 +259,13 @@
               do {
                       if (count == 0)
                               goto finished;
-                       put_user(*addr, buf);
-                       buf++;
+                       *kbuf = *addr;
+                       kbuf++;
                       addr++;
                       count--;
               } while (--n > 0);
       }
finished:
-       return buf - buf_start;
+       spin_unlock(&vmlist_lock);
+       return kbuf - buf_start;
}