aboutsummaryrefslogtreecommitdiffstats
path: root/ipc
diff options
context:
space:
mode:
authorPeter Hurley <peter@hurleysoftware.com>2013-04-30 22:14:31 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-05-01 11:12:57 -0400
commitbe5f4b335f6e05df1b5c24b7e7d79ff52d7b8dbc (patch)
tree5076680c91f139ba8908d7ecd51dd02206e57496 /ipc
parent3d8fa456d5ed22ce8db085a89a037b87568b2b64 (diff)
ipc: separate msg allocation from userspace copy
Separating msg allocation enables single-block vmalloc allocation instead. Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Acked-by: Stanislav Kinsbursky <skinsbursky@parallels.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'ipc')
-rw-r--r--ipc/msgutil.c52
1 files changed, 38 insertions, 14 deletions
diff --git a/ipc/msgutil.c b/ipc/msgutil.c
index 98b1c2b476cc..0a5c8a95c257 100644
--- a/ipc/msgutil.c
+++ b/ipc/msgutil.c
@@ -44,21 +44,54 @@ struct msg_msgseg {
44#define DATALEN_MSG (int)(PAGE_SIZE-sizeof(struct msg_msg)) 44#define DATALEN_MSG (int)(PAGE_SIZE-sizeof(struct msg_msg))
45#define DATALEN_SEG (int)(PAGE_SIZE-sizeof(struct msg_msgseg)) 45#define DATALEN_SEG (int)(PAGE_SIZE-sizeof(struct msg_msgseg))
46 46
47struct msg_msg *load_msg(const void __user *src, int len) 47
48static struct msg_msg *alloc_msg(int len)
48{ 49{
49 struct msg_msg *msg; 50 struct msg_msg *msg;
50 struct msg_msgseg **pseg; 51 struct msg_msgseg **pseg;
51 int err;
52 int alen; 52 int alen;
53 53
54 alen = min(len, DATALEN_MSG); 54 alen = min(len, DATALEN_MSG);
55 msg = kmalloc(sizeof(*msg) + alen, GFP_KERNEL); 55 msg = kmalloc(sizeof(*msg) + alen, GFP_KERNEL);
56 if (msg == NULL) 56 if (msg == NULL)
57 return ERR_PTR(-ENOMEM); 57 return NULL;
58 58
59 msg->next = NULL; 59 msg->next = NULL;
60 msg->security = NULL; 60 msg->security = NULL;
61 61
62 len -= alen;
63 pseg = &msg->next;
64 while (len > 0) {
65 struct msg_msgseg *seg;
66 alen = min(len, DATALEN_SEG);
67 seg = kmalloc(sizeof(*seg) + alen, GFP_KERNEL);
68 if (seg == NULL)
69 goto out_err;
70 *pseg = seg;
71 seg->next = NULL;
72 pseg = &seg->next;
73 len -= alen;
74 }
75
76 return msg;
77
78out_err:
79 free_msg(msg);
80 return NULL;
81}
82
83struct msg_msg *load_msg(const void __user *src, int len)
84{
85 struct msg_msg *msg;
86 struct msg_msgseg *seg;
87 int err;
88 int alen;
89
90 msg = alloc_msg(len);
91 if (msg == NULL)
92 return ERR_PTR(-ENOMEM);
93
94 alen = min(len, DATALEN_MSG);
62 if (copy_from_user(msg + 1, src, alen)) { 95 if (copy_from_user(msg + 1, src, alen)) {
63 err = -EFAULT; 96 err = -EFAULT;
64 goto out_err; 97 goto out_err;
@@ -66,23 +99,14 @@ struct msg_msg *load_msg(const void __user *src, int len)
66 99
67 len -= alen; 100 len -= alen;
68 src = ((char __user *)src) + alen; 101 src = ((char __user *)src) + alen;
69 pseg = &msg->next; 102 seg = msg->next;
70 while (len > 0) { 103 while (len > 0) {
71 struct msg_msgseg *seg;
72 alen = min(len, DATALEN_SEG); 104 alen = min(len, DATALEN_SEG);
73 seg = kmalloc(sizeof(*seg) + alen,
74 GFP_KERNEL);
75 if (seg == NULL) {
76 err = -ENOMEM;
77 goto out_err;
78 }
79 *pseg = seg;
80 seg->next = NULL;
81 if (copy_from_user(seg + 1, src, alen)) { 105 if (copy_from_user(seg + 1, src, alen)) {
82 err = -EFAULT; 106 err = -EFAULT;
83 goto out_err; 107 goto out_err;
84 } 108 }
85 pseg = &seg->next; 109 seg = seg->next;
86 len -= alen; 110 len -= alen;
87 src = ((char __user *)src) + alen; 111 src = ((char __user *)src) + alen;
88 } 112 }