lkml.org 
[lkml]   [1999]   [Dec]   [21]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
SubjectRe: [patch-2.3.34-4review] vmalloc/vfree/ioremap made SMP-safe.
On Tue, 21 Dec 1999 manfreds@colorfullife.com wrote:
> I don\'t like the vmalloc():

Ok, please have a look at this version, when you get a spare minute:

http://www.ocston.org/~tigran/patches/vmalloc-2.3.34b.patch

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 12:02:10 1999
@@ -226,7 +226,8 @@
{
unsigned long p = *ppos;
ssize_t read = 0;
- ssize_t virtr;
+ ssize_t virtr = 0;
+ char * kbuf; /* k-addr because vread() takes vmlist_lock rwlock */

if (p < (unsigned long) high_memory) {
read = count;
@@ -238,22 +239,44 @@
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)
- return virtr;
+ kbuf = (char *)get_free_page(GFP_KERNEL);
+ if (!kbuf)
+ return -ENOMEM;
+ while (count > 0) {
+ int len = count;
+
+ if (len > PAGE_SIZE)
+ len = PAGE_SIZE;
+
+ len = vread(kbuf, (char *)p, len);
+ if (len < 0) {
+ free_page((unsigned long)kbuf);
+ return len;
+ }
+ if (copy_to_user(buf, kbuf, len)) {
+ free_page((unsigned long)kbuf);
+ return -EFAULT;
+ }
+ count -= len;
+ buf += len;
+ virtr += len;
+ }
+ free_page((unsigned long)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/fs/proc/kcore.c work/fs/proc/kcore.c
--- linux/fs/proc/kcore.c Fri Nov 19 03:32:51 1999
+++ work/fs/proc/kcore.c Tue Dec 21 11:27:35 1999
@@ -329,9 +329,12 @@
* and after elf_kcore_store_hdr() returns.
* For now assume that num_vma does not change (TA)
*/
+ read_lock(&vmlist_lock);
proc_root_kcore.size = size = get_kcore_size(&num_vma, &elf_buflen);
- if (buflen == 0 || *fpos >= size)
+ if (buflen == 0 || *fpos >= size) {
+ read_unlock(&vmlist_lock);
return 0;
+ }

/* trim buflen to not go beyond EOF */
if (buflen > size - *fpos)
@@ -345,10 +348,13 @@
if (buflen < tsz)
tsz = buflen;
elf_buf = kmalloc(elf_buflen, GFP_ATOMIC);
- if (!elf_buf)
+ if (!elf_buf) {
+ read_unlock(&vmlist_lock);
return -ENOMEM;
+ }
memset(elf_buf, 0, elf_buflen);
elf_kcore_store_hdr(elf_buf, num_vma, elf_buflen);
+ read_unlock(&vmlist_lock);
if (copy_to_user(buffer, elf_buf + *fpos, tsz)) {
kfree(elf_buf);
return -EFAULT;
@@ -362,7 +368,8 @@
/* leave now if filled buffer already */
if (buflen == 0)
return acc;
- }
+ } else
+ read_unlock(&vmlist_lock);

/* where page 0 not mapped, write zeros into buffer */
#if defined (__i386__) || defined (__mc68000__)
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/include/linux/vmalloc.h work/include/linux/vmalloc.h
--- linux/include/linux/vmalloc.h Tue Dec 21 00:01:18 1999
+++ work/include/linux/vmalloc.h Tue Dec 21 11:30:01 1999
@@ -3,6 +3,7 @@

#include <linux/sched.h>
#include <linux/mm.h>
+#include <linux/spinlock.h>

#include <asm/pgtable.h>

@@ -24,6 +25,10 @@
void vmfree_area_pages(unsigned long address, unsigned long size);
int vmalloc_area_pages(unsigned long address, unsigned long size);

+/* vmlist_lock is a read-write spinlock that protects vmlist
+ * Currently (2.3.34) used in mm/vmalloc.c and fs/proc/kcore.c.
+ */
+extern rwlock_t vmlist_lock;
extern struct vm_struct * vmlist;
#endif

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 11:23:39 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>

+rwlock_t vmlist_lock = RW_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;
+ write_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) {
+ write_unlock(&vmlist_lock);
kfree(area);
return NULL;
}
@@ -176,6 +180,7 @@
area->size = size + PAGE_SIZE;
area->next = *p;
*p = area;
+ write_unlock(&vmlist_lock);
return area;
}

@@ -189,14 +194,17 @@
printk(KERN_ERR "Trying to vfree() bad address (%p)\n", addr);
return;
}
+ write_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);
+ write_unlock(&vmlist_lock);
kfree(tmp);
return;
}
}
+ write_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;

+ read_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;
+ read_unlock(&vmlist_lock);
+ return kbuf - buf_start;
}


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/

\
 
 \ /
  Last update: 2005-03-22 13:55    [W:0.138 / U:0.416 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site