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 #include +#include #include #include +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; } .