memdup_user(): introduce

I notice there are many places doing copy_from_user() which follows
kmalloc():

        dst = kmalloc(len, GFP_KERNEL);
        if (!dst)
                return -ENOMEM;
        if (copy_from_user(dst, src, len)) {
		kfree(dst);
		return -EFAULT
	}

memdup_user() is a wrapper of the above code.  With this new function, we
don't have to write 'len' twice, which can lead to typos/mistakes.  It
also produces smaller code and kernel text.

A quick grep shows 250+ places where memdup_user() *may* be used.  I'll
prepare a patchset to do this conversion.

Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Americo Wang <xiyou.wangcong@gmail.com>
Cc: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Li Zefan 2009-03-31 15:23:16 -07:00 committed by Linus Torvalds
parent e2f17d9459
commit 610a77e04a
2 changed files with 31 additions and 0 deletions

View file

@ -12,6 +12,7 @@
#include <linux/stddef.h> /* for NULL */ #include <linux/stddef.h> /* for NULL */
extern char *strndup_user(const char __user *, long); extern char *strndup_user(const char __user *, long);
extern void *memdup_user(const void __user *, size_t);
/* /*
* Include machine specific inline routines * Include machine specific inline routines

View file

@ -69,6 +69,36 @@ void *kmemdup(const void *src, size_t len, gfp_t gfp)
} }
EXPORT_SYMBOL(kmemdup); EXPORT_SYMBOL(kmemdup);
/**
* memdup_user - duplicate memory region from user space
*
* @src: source address in user space
* @len: number of bytes to copy
*
* Returns an ERR_PTR() on failure.
*/
void *memdup_user(const void __user *src, size_t len)
{
void *p;
/*
* Always use GFP_KERNEL, since copy_from_user() can sleep and
* cause pagefault, which makes it pointless to use GFP_NOFS
* or GFP_ATOMIC.
*/
p = kmalloc_track_caller(len, GFP_KERNEL);
if (!p)
return ERR_PTR(-ENOMEM);
if (copy_from_user(p, src, len)) {
kfree(p);
return ERR_PTR(-EFAULT);
}
return p;
}
EXPORT_SYMBOL(memdup_user);
/** /**
* __krealloc - like krealloc() but don't free @p. * __krealloc - like krealloc() but don't free @p.
* @p: object to reallocate memory for. * @p: object to reallocate memory for.