Blame view
ipc/msg.c
23.9 KB
1da177e4c
|
1 2 |
/* * linux/ipc/msg.c |
5a06a363e
|
3 |
* Copyright (C) 1992 Krishna Balasubramanian |
1da177e4c
|
4 5 6 7 8 9 10 11 12 13 14 |
* * Removed all the remaining kerneld mess * Catch the -EFAULT stuff properly * Use GFP_KERNEL for messages as in 1.2 * Fixed up the unchecked user space derefs * Copyright (C) 1998 Alan Cox & Andi Kleen * * /proc/sysvipc/msg support (c) 1999 Dragos Acostachioaie <dragos@iname.com> * * mostly rewritten, threaded and wake-one semantics added * MSGMAX limit removed, sysctl's added |
624dffcbc
|
15 |
* (c) 1999 Manfred Spraul <manfred@colorfullife.com> |
073115d6b
|
16 17 18 |
* * support for audit of ipc object properties and permission changes * Dustin Kirkland <dustin.kirkland@us.ibm.com> |
1e7869373
|
19 20 21 22 |
* * namespaces support * OpenVZ, SWsoft Inc. * Pavel Emelianov <xemul@openvz.org> |
1da177e4c
|
23 |
*/ |
c59ede7b7
|
24 |
#include <linux/capability.h> |
1da177e4c
|
25 26 27 |
#include <linux/msg.h> #include <linux/spinlock.h> #include <linux/init.h> |
f7bf3df8b
|
28 |
#include <linux/mm.h> |
1da177e4c
|
29 30 31 32 33 34 |
#include <linux/proc_fs.h> #include <linux/list.h> #include <linux/security.h> #include <linux/sched.h> #include <linux/syscalls.h> #include <linux/audit.h> |
19b4946ca
|
35 |
#include <linux/seq_file.h> |
3e148c799
|
36 |
#include <linux/rwsem.h> |
1e7869373
|
37 |
#include <linux/nsproxy.h> |
ae5e1b22f
|
38 |
#include <linux/ipc_namespace.h> |
5f921ae96
|
39 |
|
1da177e4c
|
40 |
#include <asm/current.h> |
7153e4027
|
41 |
#include <linux/uaccess.h> |
1da177e4c
|
42 |
#include "util.h" |
4bb6657dd
|
43 |
/* one msg_receiver structure for each sleeping receiver */ |
1da177e4c
|
44 |
struct msg_receiver { |
5a06a363e
|
45 46 |
struct list_head r_list; struct task_struct *r_tsk; |
1da177e4c
|
47 |
|
5a06a363e
|
48 49 50 |
int r_mode; long r_msgtype; long r_maxsize; |
1da177e4c
|
51 |
|
4bb6657dd
|
52 53 54 55 56 57 |
/* * Mark r_msg volatile so that the compiler * does not try to get smart and optimize * it. We rely on this for the lockless * receive algorithm. */ |
80491eb90
|
58 |
struct msg_msg *volatile r_msg; |
1da177e4c
|
59 60 61 62 |
}; /* one msg_sender for each sleeping sender */ struct msg_sender { |
5a06a363e
|
63 64 |
struct list_head list; struct task_struct *tsk; |
1da177e4c
|
65 66 67 68 69 70 |
}; #define SEARCH_ANY 1 #define SEARCH_EQUAL 2 #define SEARCH_NOTEQUAL 3 #define SEARCH_LESSEQUAL 4 |
8ac6ed585
|
71 |
#define SEARCH_NUMBER 5 |
1da177e4c
|
72 |
|
ed2ddbf88
|
73 |
#define msg_ids(ns) ((ns)->ids[IPC_MSG_IDS]) |
1da177e4c
|
74 |
|
a5001a0d9
|
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
static inline struct msg_queue *msq_obtain_object(struct ipc_namespace *ns, int id) { struct kern_ipc_perm *ipcp = ipc_obtain_object(&msg_ids(ns), id); if (IS_ERR(ipcp)) return ERR_CAST(ipcp); return container_of(ipcp, struct msg_queue, q_perm); } static inline struct msg_queue *msq_obtain_object_check(struct ipc_namespace *ns, int id) { struct kern_ipc_perm *ipcp = ipc_obtain_object_check(&msg_ids(ns), id); if (IS_ERR(ipcp)) return ERR_CAST(ipcp); return container_of(ipcp, struct msg_queue, q_perm); } |
7ca7e564e
|
95 96 97 98 |
static inline void msg_rmid(struct ipc_namespace *ns, struct msg_queue *s) { ipc_rmid(&msg_ids(ns), &s->q_perm); } |
53dad6d3a
|
99 100 101 102 103 104 105 106 |
static void msg_rcu_free(struct rcu_head *head) { struct ipc_rcu *p = container_of(head, struct ipc_rcu, rcu); struct msg_queue *msq = ipc_rcu_to_struct(p); security_msg_queue_free(msq); ipc_rcu_free(head); } |
f4566f048
|
107 108 109 110 111 |
/** * newque - Create a new msg queue * @ns: namespace * @params: ptr to the structure that contains the key and msgflg * |
d9a605e40
|
112 |
* Called with msg_ids.rwsem held (writer) |
f4566f048
|
113 |
*/ |
7748dbfaa
|
114 |
static int newque(struct ipc_namespace *ns, struct ipc_params *params) |
1da177e4c
|
115 |
{ |
1da177e4c
|
116 |
struct msg_queue *msq; |
5a06a363e
|
117 |
int id, retval; |
7748dbfaa
|
118 119 |
key_t key = params->key; int msgflg = params->flg; |
1da177e4c
|
120 |
|
5a06a363e
|
121 122 |
msq = ipc_rcu_alloc(sizeof(*msq)); if (!msq) |
1da177e4c
|
123 |
return -ENOMEM; |
5a06a363e
|
124 |
msq->q_perm.mode = msgflg & S_IRWXUGO; |
1da177e4c
|
125 126 127 128 129 |
msq->q_perm.key = key; msq->q_perm.security = NULL; retval = security_msg_queue_alloc(msq); if (retval) { |
53dad6d3a
|
130 |
ipc_rcu_putref(msq, ipc_rcu_free); |
1da177e4c
|
131 132 |
return retval; } |
dbfcd91f0
|
133 |
/* ipc_addid() locks msq upon success. */ |
1e7869373
|
134 |
id = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni); |
283bb7fad
|
135 |
if (id < 0) { |
53dad6d3a
|
136 |
ipc_rcu_putref(msq, msg_rcu_free); |
283bb7fad
|
137 |
return id; |
1da177e4c
|
138 139 140 141 142 |
} msq->q_stime = msq->q_rtime = 0; msq->q_ctime = get_seconds(); msq->q_cbytes = msq->q_qnum = 0; |
1e7869373
|
143 |
msq->q_qbytes = ns->msg_ctlmnb; |
1da177e4c
|
144 145 146 147 |
msq->q_lspid = msq->q_lrpid = 0; INIT_LIST_HEAD(&msq->q_messages); INIT_LIST_HEAD(&msq->q_receivers); INIT_LIST_HEAD(&msq->q_senders); |
7ca7e564e
|
148 |
|
cf9d5d78d
|
149 |
ipc_unlock_object(&msq->q_perm); |
dbfcd91f0
|
150 |
rcu_read_unlock(); |
1da177e4c
|
151 |
|
7ca7e564e
|
152 |
return msq->q_perm.id; |
1da177e4c
|
153 |
} |
5a06a363e
|
154 |
static inline void ss_add(struct msg_queue *msq, struct msg_sender *mss) |
1da177e4c
|
155 |
{ |
5a06a363e
|
156 |
mss->tsk = current; |
f75a2f358
|
157 |
__set_current_state(TASK_INTERRUPTIBLE); |
5a06a363e
|
158 |
list_add_tail(&mss->list, &msq->q_senders); |
1da177e4c
|
159 |
} |
5a06a363e
|
160 |
static inline void ss_del(struct msg_sender *mss) |
1da177e4c
|
161 |
{ |
5a06a363e
|
162 |
if (mss->list.next != NULL) |
1da177e4c
|
163 164 |
list_del(&mss->list); } |
5a06a363e
|
165 |
static void ss_wakeup(struct list_head *h, int kill) |
1da177e4c
|
166 |
{ |
41239fe82
|
167 |
struct msg_sender *mss, *t; |
1da177e4c
|
168 |
|
41239fe82
|
169 |
list_for_each_entry_safe(mss, t, h, list) { |
5a06a363e
|
170 171 |
if (kill) mss->list.next = NULL; |
1da177e4c
|
172 173 174 |
wake_up_process(mss->tsk); } } |
5a06a363e
|
175 |
static void expunge_all(struct msg_queue *msq, int res) |
1da177e4c
|
176 |
{ |
41239fe82
|
177 |
struct msg_receiver *msr, *t; |
5a06a363e
|
178 |
|
41239fe82
|
179 |
list_for_each_entry_safe(msr, t, &msq->q_receivers, r_list) { |
ffa571daf
|
180 |
msr->r_msg = NULL; /* initialize expunge ordering */ |
1da177e4c
|
181 |
wake_up_process(msr->r_tsk); |
ffa571daf
|
182 183 184 185 186 187 |
/* * Ensure that the wakeup is visible before setting r_msg as * the receiving end depends on it: either spinning on a nil, * or dealing with -EAGAIN cases. See lockless receive part 1 * and 2 in do_msgrcv(). */ |
1da177e4c
|
188 189 190 191 |
smp_mb(); msr->r_msg = ERR_PTR(res); } } |
5a06a363e
|
192 193 194 |
/* * freeque() wakes up waiters on the sender and receiver waiting queue, |
f4566f048
|
195 196 |
* removes the message queue from message queue ID IDR, and cleans up all the * messages associated with this queue. |
1da177e4c
|
197 |
* |
d9a605e40
|
198 199 |
* msg_ids.rwsem (writer) and the spinlock for this message queue are held * before freeque() is called. msg_ids.rwsem remains locked on exit. |
1da177e4c
|
200 |
*/ |
01b8b07a5
|
201 |
static void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp) |
1da177e4c
|
202 |
{ |
41239fe82
|
203 |
struct msg_msg *msg, *t; |
01b8b07a5
|
204 |
struct msg_queue *msq = container_of(ipcp, struct msg_queue, q_perm); |
1da177e4c
|
205 |
|
5a06a363e
|
206 207 |
expunge_all(msq, -EIDRM); ss_wakeup(&msq->q_senders, 1); |
7ca7e564e
|
208 |
msg_rmid(ns, msq); |
4718787d1
|
209 210 |
ipc_unlock_object(&msq->q_perm); rcu_read_unlock(); |
5a06a363e
|
211 |
|
41239fe82
|
212 |
list_for_each_entry_safe(msg, t, &msq->q_messages, m_list) { |
3ac88a41f
|
213 |
atomic_dec(&ns->msg_hdrs); |
1da177e4c
|
214 215 |
free_msg(msg); } |
3ac88a41f
|
216 |
atomic_sub(msq->q_cbytes, &ns->msg_bytes); |
53dad6d3a
|
217 |
ipc_rcu_putref(msq, msg_rcu_free); |
1da177e4c
|
218 |
} |
f4566f048
|
219 |
/* |
d9a605e40
|
220 |
* Called with msg_ids.rwsem and ipcp locked. |
f4566f048
|
221 |
*/ |
03f02c765
|
222 |
static inline int msg_security(struct kern_ipc_perm *ipcp, int msgflg) |
7748dbfaa
|
223 |
{ |
03f02c765
|
224 225 226 |
struct msg_queue *msq = container_of(ipcp, struct msg_queue, q_perm); return security_msg_queue_associate(msq, msgflg); |
7748dbfaa
|
227 |
} |
e48fbb699
|
228 |
SYSCALL_DEFINE2(msgget, key_t, key, int, msgflg) |
1da177e4c
|
229 |
{ |
1e7869373
|
230 |
struct ipc_namespace *ns; |
eb66ec44f
|
231 232 233 234 |
static const struct ipc_ops msg_ops = { .getnew = newque, .associate = msg_security, }; |
7748dbfaa
|
235 |
struct ipc_params msg_params; |
1e7869373
|
236 237 |
ns = current->nsproxy->ipc_ns; |
7ca7e564e
|
238 |
|
7748dbfaa
|
239 240 |
msg_params.key = key; msg_params.flg = msgflg; |
5a06a363e
|
241 |
|
7748dbfaa
|
242 |
return ipcget(ns, &msg_ids(ns), &msg_ops, &msg_params); |
1da177e4c
|
243 |
} |
5a06a363e
|
244 245 |
static inline unsigned long copy_msqid_to_user(void __user *buf, struct msqid64_ds *in, int version) |
1da177e4c
|
246 |
{ |
239521f31
|
247 |
switch (version) { |
1da177e4c
|
248 |
case IPC_64: |
5a06a363e
|
249 |
return copy_to_user(buf, in, sizeof(*in)); |
1da177e4c
|
250 |
case IPC_OLD: |
5a06a363e
|
251 |
{ |
1da177e4c
|
252 |
struct msqid_ds out; |
5a06a363e
|
253 |
memset(&out, 0, sizeof(out)); |
1da177e4c
|
254 255 256 257 258 259 |
ipc64_perm_to_ipc_perm(&in->msg_perm, &out.msg_perm); out.msg_stime = in->msg_stime; out.msg_rtime = in->msg_rtime; out.msg_ctime = in->msg_ctime; |
4be929be3
|
260 261 |
if (in->msg_cbytes > USHRT_MAX) out.msg_cbytes = USHRT_MAX; |
1da177e4c
|
262 263 264 |
else out.msg_cbytes = in->msg_cbytes; out.msg_lcbytes = in->msg_cbytes; |
4be929be3
|
265 266 |
if (in->msg_qnum > USHRT_MAX) out.msg_qnum = USHRT_MAX; |
1da177e4c
|
267 268 |
else out.msg_qnum = in->msg_qnum; |
4be929be3
|
269 270 |
if (in->msg_qbytes > USHRT_MAX) out.msg_qbytes = USHRT_MAX; |
1da177e4c
|
271 272 273 274 275 276 |
else out.msg_qbytes = in->msg_qbytes; out.msg_lqbytes = in->msg_qbytes; out.msg_lspid = in->msg_lspid; out.msg_lrpid = in->msg_lrpid; |
5a06a363e
|
277 278 |
return copy_to_user(buf, &out, sizeof(out)); } |
1da177e4c
|
279 280 281 282 |
default: return -EINVAL; } } |
5a06a363e
|
283 |
static inline unsigned long |
016d7132f
|
284 |
copy_msqid_from_user(struct msqid64_ds *out, void __user *buf, int version) |
1da177e4c
|
285 |
{ |
239521f31
|
286 |
switch (version) { |
1da177e4c
|
287 |
case IPC_64: |
016d7132f
|
288 |
if (copy_from_user(out, buf, sizeof(*out))) |
1da177e4c
|
289 |
return -EFAULT; |
1da177e4c
|
290 |
return 0; |
1da177e4c
|
291 |
case IPC_OLD: |
5a06a363e
|
292 |
{ |
1da177e4c
|
293 |
struct msqid_ds tbuf_old; |
5a06a363e
|
294 |
if (copy_from_user(&tbuf_old, buf, sizeof(tbuf_old))) |
1da177e4c
|
295 |
return -EFAULT; |
239521f31
|
296 297 298 |
out->msg_perm.uid = tbuf_old.msg_perm.uid; out->msg_perm.gid = tbuf_old.msg_perm.gid; out->msg_perm.mode = tbuf_old.msg_perm.mode; |
1da177e4c
|
299 |
|
5a06a363e
|
300 |
if (tbuf_old.msg_qbytes == 0) |
016d7132f
|
301 |
out->msg_qbytes = tbuf_old.msg_lqbytes; |
1da177e4c
|
302 |
else |
016d7132f
|
303 |
out->msg_qbytes = tbuf_old.msg_qbytes; |
1da177e4c
|
304 305 |
return 0; |
5a06a363e
|
306 |
} |
1da177e4c
|
307 308 309 310 |
default: return -EINVAL; } } |
a0d092fc2
|
311 |
/* |
d9a605e40
|
312 |
* This function handles some msgctl commands which require the rwsem |
a0d092fc2
|
313 |
* to be held in write mode. |
d9a605e40
|
314 |
* NOTE: no locks must be held, the rwsem is taken inside this function. |
a0d092fc2
|
315 316 317 |
*/ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd, struct msqid_ds __user *buf, int version) |
1da177e4c
|
318 |
{ |
1da177e4c
|
319 |
struct kern_ipc_perm *ipcp; |
f1970c48e
|
320 |
struct msqid64_ds uninitialized_var(msqid64); |
a0d092fc2
|
321 322 323 324 |
struct msg_queue *msq; int err; if (cmd == IPC_SET) { |
016d7132f
|
325 |
if (copy_msqid_from_user(&msqid64, buf, version)) |
a0d092fc2
|
326 327 |
return -EFAULT; } |
d9a605e40
|
328 |
down_write(&msg_ids(ns).rwsem); |
7b4cc5d84
|
329 |
rcu_read_lock(); |
15724ecb7
|
330 331 |
ipcp = ipcctl_pre_down_nolock(ns, &msg_ids(ns), msqid, cmd, &msqid64.msg_perm, msqid64.msg_qbytes); |
7b4cc5d84
|
332 333 |
if (IS_ERR(ipcp)) { err = PTR_ERR(ipcp); |
7b4cc5d84
|
334 335 |
goto out_unlock1; } |
a0d092fc2
|
336 |
|
a5f75e7f2
|
337 |
msq = container_of(ipcp, struct msg_queue, q_perm); |
a0d092fc2
|
338 339 340 |
err = security_msg_queue_msgctl(msq, cmd); if (err) |
15724ecb7
|
341 |
goto out_unlock1; |
a0d092fc2
|
342 343 344 |
switch (cmd) { case IPC_RMID: |
15724ecb7
|
345 |
ipc_lock_object(&msq->q_perm); |
7b4cc5d84
|
346 |
/* freeque unlocks the ipc object and rcu */ |
a0d092fc2
|
347 348 349 |
freeque(ns, ipcp); goto out_up; case IPC_SET: |
016d7132f
|
350 |
if (msqid64.msg_qbytes > ns->msg_ctlmnb && |
a0d092fc2
|
351 352 |
!capable(CAP_SYS_RESOURCE)) { err = -EPERM; |
15724ecb7
|
353 |
goto out_unlock1; |
a0d092fc2
|
354 |
} |
15724ecb7
|
355 |
ipc_lock_object(&msq->q_perm); |
1efdb69b0
|
356 357 |
err = ipc_update_perm(&msqid64.msg_perm, ipcp); if (err) |
7b4cc5d84
|
358 |
goto out_unlock0; |
1efdb69b0
|
359 |
|
016d7132f
|
360 |
msq->q_qbytes = msqid64.msg_qbytes; |
a0d092fc2
|
361 |
|
a0d092fc2
|
362 363 364 365 366 367 368 369 370 371 372 373 |
msq->q_ctime = get_seconds(); /* sleeping receivers might be excluded by * stricter permissions. */ expunge_all(msq, -EAGAIN); /* sleeping senders might be able to send * due to a larger queue size. */ ss_wakeup(&msq->q_senders, 0); break; default: err = -EINVAL; |
15724ecb7
|
374 |
goto out_unlock1; |
a0d092fc2
|
375 |
} |
7b4cc5d84
|
376 377 378 379 380 |
out_unlock0: ipc_unlock_object(&msq->q_perm); out_unlock1: rcu_read_unlock(); |
a0d092fc2
|
381 |
out_up: |
d9a605e40
|
382 |
up_write(&msg_ids(ns).rwsem); |
a0d092fc2
|
383 384 |
return err; } |
2cafed30f
|
385 386 |
static int msgctl_nolock(struct ipc_namespace *ns, int msqid, int cmd, int version, void __user *buf) |
a0d092fc2
|
387 |
{ |
2cafed30f
|
388 |
int err; |
5a06a363e
|
389 |
struct msg_queue *msq; |
1da177e4c
|
390 391 |
switch (cmd) { |
5a06a363e
|
392 393 394 |
case IPC_INFO: case MSG_INFO: { |
1da177e4c
|
395 396 |
struct msginfo msginfo; int max_id; |
5a06a363e
|
397 |
|
1da177e4c
|
398 399 |
if (!buf) return -EFAULT; |
2cafed30f
|
400 |
|
5a06a363e
|
401 402 |
/* * We must not return kernel stack data. |
1da177e4c
|
403 404 405 |
* due to padding, it's not enough * to set all member fields. */ |
1da177e4c
|
406 407 408 |
err = security_msg_queue_msgctl(NULL, cmd); if (err) return err; |
5a06a363e
|
409 |
memset(&msginfo, 0, sizeof(msginfo)); |
1e7869373
|
410 411 412 |
msginfo.msgmni = ns->msg_ctlmni; msginfo.msgmax = ns->msg_ctlmax; msginfo.msgmnb = ns->msg_ctlmnb; |
1da177e4c
|
413 414 |
msginfo.msgssz = MSGSSZ; msginfo.msgseg = MSGSEG; |
d9a605e40
|
415 |
down_read(&msg_ids(ns).rwsem); |
1da177e4c
|
416 |
if (cmd == MSG_INFO) { |
1e7869373
|
417 |
msginfo.msgpool = msg_ids(ns).in_use; |
3ac88a41f
|
418 419 |
msginfo.msgmap = atomic_read(&ns->msg_hdrs); msginfo.msgtql = atomic_read(&ns->msg_bytes); |
1da177e4c
|
420 421 422 423 424 |
} else { msginfo.msgmap = MSGMAP; msginfo.msgpool = MSGPOOL; msginfo.msgtql = MSGTQL; } |
7ca7e564e
|
425 |
max_id = ipc_get_maxid(&msg_ids(ns)); |
d9a605e40
|
426 |
up_read(&msg_ids(ns).rwsem); |
5a06a363e
|
427 |
if (copy_to_user(buf, &msginfo, sizeof(struct msginfo))) |
1da177e4c
|
428 |
return -EFAULT; |
5a06a363e
|
429 |
return (max_id < 0) ? 0 : max_id; |
1da177e4c
|
430 |
} |
2cafed30f
|
431 432 |
case MSG_STAT: |
1da177e4c
|
433 434 435 436 |
case IPC_STAT: { struct msqid64_ds tbuf; int success_return; |
5a06a363e
|
437 |
|
1da177e4c
|
438 439 |
if (!buf) return -EFAULT; |
1da177e4c
|
440 |
|
ac0ba20ea
|
441 442 443 |
memset(&tbuf, 0, sizeof(tbuf)); rcu_read_lock(); |
5a06a363e
|
444 |
if (cmd == MSG_STAT) { |
ac0ba20ea
|
445 446 447 448 449 |
msq = msq_obtain_object(ns, msqid); if (IS_ERR(msq)) { err = PTR_ERR(msq); goto out_unlock; } |
7ca7e564e
|
450 |
success_return = msq->q_perm.id; |
1da177e4c
|
451 |
} else { |
ac0ba20ea
|
452 453 454 455 456 |
msq = msq_obtain_object_check(ns, msqid); if (IS_ERR(msq)) { err = PTR_ERR(msq); goto out_unlock; } |
1da177e4c
|
457 458 |
success_return = 0; } |
ac0ba20ea
|
459 |
|
1da177e4c
|
460 |
err = -EACCES; |
b0e77598f
|
461 |
if (ipcperms(ns, &msq->q_perm, S_IRUGO)) |
1da177e4c
|
462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 |
goto out_unlock; err = security_msg_queue_msgctl(msq, cmd); if (err) goto out_unlock; kernel_to_ipc64_perm(&msq->q_perm, &tbuf.msg_perm); tbuf.msg_stime = msq->q_stime; tbuf.msg_rtime = msq->q_rtime; tbuf.msg_ctime = msq->q_ctime; tbuf.msg_cbytes = msq->q_cbytes; tbuf.msg_qnum = msq->q_qnum; tbuf.msg_qbytes = msq->q_qbytes; tbuf.msg_lspid = msq->q_lspid; tbuf.msg_lrpid = msq->q_lrpid; |
ac0ba20ea
|
477 |
rcu_read_unlock(); |
1da177e4c
|
478 479 480 481 |
if (copy_msqid_to_user(buf, &tbuf, version)) return -EFAULT; return success_return; } |
2cafed30f
|
482 |
|
1da177e4c
|
483 |
default: |
2cafed30f
|
484 |
return -EINVAL; |
1da177e4c
|
485 |
} |
2cafed30f
|
486 |
return err; |
1da177e4c
|
487 |
out_unlock: |
ac0ba20ea
|
488 |
rcu_read_unlock(); |
1da177e4c
|
489 490 |
return err; } |
2cafed30f
|
491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 |
SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf) { int version; struct ipc_namespace *ns; if (msqid < 0 || cmd < 0) return -EINVAL; version = ipc_parse_version(&cmd); ns = current->nsproxy->ipc_ns; switch (cmd) { case IPC_INFO: case MSG_INFO: case MSG_STAT: /* msqid is an index rather than a msg queue id */ case IPC_STAT: return msgctl_nolock(ns, msqid, cmd, version, buf); case IPC_SET: case IPC_RMID: return msgctl_down(ns, msqid, cmd, buf, version); default: return -EINVAL; } } |
5a06a363e
|
515 |
static int testmsg(struct msg_msg *msg, long type, int mode) |
1da177e4c
|
516 |
{ |
46c0a8ca3
|
517 518 519 520 521 522 523 524 525 526 |
switch (mode) { case SEARCH_ANY: case SEARCH_NUMBER: return 1; case SEARCH_LESSEQUAL: if (msg->m_type <= type) return 1; break; case SEARCH_EQUAL: if (msg->m_type == type) |
1da177e4c
|
527 |
return 1; |
46c0a8ca3
|
528 529 530 531 532 |
break; case SEARCH_NOTEQUAL: if (msg->m_type != type) return 1; break; |
1da177e4c
|
533 534 535 |
} return 0; } |
5a06a363e
|
536 |
static inline int pipelined_send(struct msg_queue *msq, struct msg_msg *msg) |
1da177e4c
|
537 |
{ |
41239fe82
|
538 |
struct msg_receiver *msr, *t; |
5a06a363e
|
539 |
|
41239fe82
|
540 |
list_for_each_entry_safe(msr, t, &msq->q_receivers, r_list) { |
5a06a363e
|
541 542 543 |
if (testmsg(msg, msr->r_msgtype, msr->r_mode) && !security_msg_queue_msgrcv(msq, msg, msr->r_tsk, msr->r_msgtype, msr->r_mode)) { |
1da177e4c
|
544 |
list_del(&msr->r_list); |
5a06a363e
|
545 |
if (msr->r_maxsize < msg->m_ts) { |
ffa571daf
|
546 |
/* initialize pipelined send ordering */ |
1da177e4c
|
547 548 |
msr->r_msg = NULL; wake_up_process(msr->r_tsk); |
ffa571daf
|
549 |
smp_mb(); /* see barrier comment below */ |
1da177e4c
|
550 551 552 |
msr->r_msg = ERR_PTR(-E2BIG); } else { msr->r_msg = NULL; |
b488893a3
|
553 |
msq->q_lrpid = task_pid_vnr(msr->r_tsk); |
1da177e4c
|
554 555 |
msq->q_rtime = get_seconds(); wake_up_process(msr->r_tsk); |
ffa571daf
|
556 557 558 559 560 561 |
/* * Ensure that the wakeup is visible before * setting r_msg, as the receiving end depends * on it. See lockless receive part 1 and 2 in * do_msgrcv(). */ |
1da177e4c
|
562 563 |
smp_mb(); msr->r_msg = msg; |
5a06a363e
|
564 |
|
1da177e4c
|
565 566 567 568 |
return 1; } } } |
ffa571daf
|
569 |
|
1da177e4c
|
570 571 |
return 0; } |
651971cb7
|
572 573 |
long do_msgsnd(int msqid, long mtype, void __user *mtext, size_t msgsz, int msgflg) |
1da177e4c
|
574 575 576 |
{ struct msg_queue *msq; struct msg_msg *msg; |
1da177e4c
|
577 |
int err; |
1e7869373
|
578 579 580 |
struct ipc_namespace *ns; ns = current->nsproxy->ipc_ns; |
5a06a363e
|
581 |
|
1e7869373
|
582 |
if (msgsz > ns->msg_ctlmax || (long) msgsz < 0 || msqid < 0) |
1da177e4c
|
583 |
return -EINVAL; |
1da177e4c
|
584 585 |
if (mtype < 1) return -EINVAL; |
651971cb7
|
586 |
msg = load_msg(mtext, msgsz); |
5a06a363e
|
587 |
if (IS_ERR(msg)) |
1da177e4c
|
588 589 590 591 |
return PTR_ERR(msg); msg->m_type = mtype; msg->m_ts = msgsz; |
3dd1f784e
|
592 593 |
rcu_read_lock(); msq = msq_obtain_object_check(ns, msqid); |
023a53557
|
594 595 |
if (IS_ERR(msq)) { err = PTR_ERR(msq); |
3dd1f784e
|
596 |
goto out_unlock1; |
023a53557
|
597 |
} |
1da177e4c
|
598 |
|
bebcb928c
|
599 |
ipc_lock_object(&msq->q_perm); |
1da177e4c
|
600 601 |
for (;;) { struct msg_sender s; |
5a06a363e
|
602 |
err = -EACCES; |
b0e77598f
|
603 |
if (ipcperms(ns, &msq->q_perm, S_IWUGO)) |
bebcb928c
|
604 |
goto out_unlock0; |
1da177e4c
|
605 |
|
4271b05a2
|
606 |
/* raced with RMID? */ |
0f3d2b013
|
607 |
if (!ipc_valid_object(&msq->q_perm)) { |
4271b05a2
|
608 609 610 |
err = -EIDRM; goto out_unlock0; } |
1da177e4c
|
611 612 |
err = security_msg_queue_msgsnd(msq, msg, msgflg); if (err) |
bebcb928c
|
613 |
goto out_unlock0; |
1da177e4c
|
614 |
|
5a06a363e
|
615 |
if (msgsz + msq->q_cbytes <= msq->q_qbytes && |
1da177e4c
|
616 617 618 619 620 |
1 + msq->q_qnum <= msq->q_qbytes) { break; } /* queue full, wait: */ |
5a06a363e
|
621 622 |
if (msgflg & IPC_NOWAIT) { err = -EAGAIN; |
bebcb928c
|
623 |
goto out_unlock0; |
1da177e4c
|
624 |
} |
3dd1f784e
|
625 |
|
ffa571daf
|
626 |
/* enqueue the sender and prepare to block */ |
1da177e4c
|
627 |
ss_add(msq, &s); |
6062a8dc0
|
628 629 630 |
if (!ipc_rcu_getref(msq)) { err = -EIDRM; |
3dd1f784e
|
631 |
goto out_unlock0; |
6062a8dc0
|
632 |
} |
3dd1f784e
|
633 634 |
ipc_unlock_object(&msq->q_perm); rcu_read_unlock(); |
1da177e4c
|
635 |
schedule(); |
3dd1f784e
|
636 637 |
rcu_read_lock(); ipc_lock_object(&msq->q_perm); |
53dad6d3a
|
638 |
ipc_rcu_putref(msq, ipc_rcu_free); |
0f3d2b013
|
639 640 |
/* raced with RMID? */ if (!ipc_valid_object(&msq->q_perm)) { |
1da177e4c
|
641 |
err = -EIDRM; |
3dd1f784e
|
642 |
goto out_unlock0; |
1da177e4c
|
643 |
} |
3dd1f784e
|
644 |
|
1da177e4c
|
645 |
ss_del(&s); |
5a06a363e
|
646 |
|
1da177e4c
|
647 |
if (signal_pending(current)) { |
5a06a363e
|
648 |
err = -ERESTARTNOHAND; |
3dd1f784e
|
649 |
goto out_unlock0; |
1da177e4c
|
650 |
} |
3dd1f784e
|
651 |
|
1da177e4c
|
652 |
} |
b488893a3
|
653 |
msq->q_lspid = task_tgid_vnr(current); |
1da177e4c
|
654 |
msq->q_stime = get_seconds(); |
5a06a363e
|
655 |
if (!pipelined_send(msq, msg)) { |
25985edce
|
656 |
/* no one is waiting for this message, enqueue it */ |
5a06a363e
|
657 |
list_add_tail(&msg->m_list, &msq->q_messages); |
1da177e4c
|
658 659 |
msq->q_cbytes += msgsz; msq->q_qnum++; |
3ac88a41f
|
660 661 |
atomic_add(msgsz, &ns->msg_bytes); atomic_inc(&ns->msg_hdrs); |
1da177e4c
|
662 |
} |
5a06a363e
|
663 |
|
1da177e4c
|
664 665 |
err = 0; msg = NULL; |
3dd1f784e
|
666 667 668 669 |
out_unlock0: ipc_unlock_object(&msq->q_perm); out_unlock1: rcu_read_unlock(); |
5a06a363e
|
670 |
if (msg != NULL) |
1da177e4c
|
671 672 673 |
free_msg(msg); return err; } |
e48fbb699
|
674 675 |
SYSCALL_DEFINE4(msgsnd, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz, int, msgflg) |
651971cb7
|
676 677 678 679 680 681 682 |
{ long mtype; if (get_user(mtype, &msgp->mtype)) return -EFAULT; return do_msgsnd(msqid, mtype, msgp->mtext, msgsz, msgflg); } |
5a06a363e
|
683 |
static inline int convert_mode(long *msgtyp, int msgflg) |
1da177e4c
|
684 |
{ |
8ac6ed585
|
685 686 |
if (msgflg & MSG_COPY) return SEARCH_NUMBER; |
5a06a363e
|
687 |
/* |
1da177e4c
|
688 689 690 |
* find message of correct type. * msgtyp = 0 => get first. * msgtyp > 0 => get first message of matching type. |
5a06a363e
|
691 |
* msgtyp < 0 => get message with least type must be < abs(msgtype). |
1da177e4c
|
692 |
*/ |
5a06a363e
|
693 |
if (*msgtyp == 0) |
1da177e4c
|
694 |
return SEARCH_ANY; |
5a06a363e
|
695 696 |
if (*msgtyp < 0) { *msgtyp = -*msgtyp; |
1da177e4c
|
697 698 |
return SEARCH_LESSEQUAL; } |
5a06a363e
|
699 |
if (msgflg & MSG_EXCEPT) |
1da177e4c
|
700 701 702 |
return SEARCH_NOTEQUAL; return SEARCH_EQUAL; } |
f9dd87f47
|
703 704 705 706 707 708 709 710 711 712 713 714 715 |
static long do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz) { struct msgbuf __user *msgp = dest; size_t msgsz; if (put_user(msg->m_type, &msgp->mtype)) return -EFAULT; msgsz = (bufsz > msg->m_ts) ? msg->m_ts : bufsz; if (store_msg(msgp->mtext, msg, msgsz)) return -EFAULT; return msgsz; } |
4a674f34b
|
716 |
#ifdef CONFIG_CHECKPOINT_RESTORE |
3fcfe7865
|
717 718 719 720 |
/* * This function creates new kernel message structure, large enough to store * bufsz message bytes. */ |
8ac6ed585
|
721 |
static inline struct msg_msg *prepare_copy(void __user *buf, size_t bufsz) |
4a674f34b
|
722 723 |
{ struct msg_msg *copy; |
4a674f34b
|
724 725 726 727 728 729 730 731 |
/* * Create dummy message to copy real message to. */ copy = load_msg(buf, bufsz); if (!IS_ERR(copy)) copy->m_ts = bufsz; return copy; } |
85398aa8d
|
732 |
static inline void free_copy(struct msg_msg *copy) |
4a674f34b
|
733 |
{ |
85398aa8d
|
734 |
if (copy) |
4a674f34b
|
735 736 737 |
free_msg(copy); } #else |
8ac6ed585
|
738 |
static inline struct msg_msg *prepare_copy(void __user *buf, size_t bufsz) |
b30efe277
|
739 740 741 |
{ return ERR_PTR(-ENOSYS); } |
85398aa8d
|
742 743 744 |
static inline void free_copy(struct msg_msg *copy) { } |
4a674f34b
|
745 |
#endif |
daaf74cf0
|
746 747 |
static struct msg_msg *find_msg(struct msg_queue *msq, long *msgtyp, int mode) { |
368ae537e
|
748 |
struct msg_msg *msg, *found = NULL; |
daaf74cf0
|
749 750 751 752 753 754 755 756 |
long count = 0; list_for_each_entry(msg, &msq->q_messages, m_list) { if (testmsg(msg, *msgtyp, mode) && !security_msg_queue_msgrcv(msq, msg, current, *msgtyp, mode)) { if (mode == SEARCH_LESSEQUAL && msg->m_type != 1) { *msgtyp = msg->m_type - 1; |
368ae537e
|
757 |
found = msg; |
daaf74cf0
|
758 759 760 761 762 763 764 765 |
} else if (mode == SEARCH_NUMBER) { if (*msgtyp == count) return msg; } else return msg; count++; } } |
368ae537e
|
766 |
return found ?: ERR_PTR(-EAGAIN); |
daaf74cf0
|
767 |
} |
41a0d523d
|
768 |
long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgflg, |
f9dd87f47
|
769 |
long (*msg_handler)(void __user *, struct msg_msg *, size_t)) |
1da177e4c
|
770 |
{ |
1da177e4c
|
771 |
int mode; |
41a0d523d
|
772 |
struct msg_queue *msq; |
1e7869373
|
773 |
struct ipc_namespace *ns; |
41a0d523d
|
774 |
struct msg_msg *msg, *copy = NULL; |
1da177e4c
|
775 |
|
88b9e456b
|
776 |
ns = current->nsproxy->ipc_ns; |
f9dd87f47
|
777 |
if (msqid < 0 || (long) bufsz < 0) |
1da177e4c
|
778 |
return -EINVAL; |
41a0d523d
|
779 |
|
4a674f34b
|
780 |
if (msgflg & MSG_COPY) { |
4f87dac38
|
781 782 |
if ((msgflg & MSG_EXCEPT) || !(msgflg & IPC_NOWAIT)) return -EINVAL; |
8ac6ed585
|
783 |
copy = prepare_copy(buf, min_t(size_t, bufsz, ns->msg_ctlmax)); |
4a674f34b
|
784 785 786 |
if (IS_ERR(copy)) return PTR_ERR(copy); } |
5a06a363e
|
787 |
mode = convert_mode(&msgtyp, msgflg); |
1da177e4c
|
788 |
|
41a0d523d
|
789 790 |
rcu_read_lock(); msq = msq_obtain_object_check(ns, msqid); |
4a674f34b
|
791 |
if (IS_ERR(msq)) { |
41a0d523d
|
792 |
rcu_read_unlock(); |
85398aa8d
|
793 |
free_copy(copy); |
023a53557
|
794 |
return PTR_ERR(msq); |
4a674f34b
|
795 |
} |
1da177e4c
|
796 797 798 |
for (;;) { struct msg_receiver msr_d; |
1da177e4c
|
799 800 |
msg = ERR_PTR(-EACCES); |
b0e77598f
|
801 |
if (ipcperms(ns, &msq->q_perm, S_IRUGO)) |
41a0d523d
|
802 |
goto out_unlock1; |
1da177e4c
|
803 |
|
41a0d523d
|
804 |
ipc_lock_object(&msq->q_perm); |
4271b05a2
|
805 806 |
/* raced with RMID? */ |
0f3d2b013
|
807 |
if (!ipc_valid_object(&msq->q_perm)) { |
4271b05a2
|
808 809 810 |
msg = ERR_PTR(-EIDRM); goto out_unlock0; } |
daaf74cf0
|
811 |
msg = find_msg(msq, &msgtyp, mode); |
5a06a363e
|
812 813 814 815 816 |
if (!IS_ERR(msg)) { /* * Found a suitable message. * Unlink it from the queue. */ |
f9dd87f47
|
817 |
if ((bufsz < msg->m_ts) && !(msgflg & MSG_NOERROR)) { |
1da177e4c
|
818 |
msg = ERR_PTR(-E2BIG); |
41a0d523d
|
819 |
goto out_unlock0; |
1da177e4c
|
820 |
} |
3fcfe7865
|
821 822 823 824 |
/* * If we are copying, then do not unlink message and do * not update queue parameters. */ |
852028af8
|
825 826 |
if (msgflg & MSG_COPY) { msg = copy_msg(msg, copy); |
41a0d523d
|
827 |
goto out_unlock0; |
852028af8
|
828 |
} |
41a0d523d
|
829 |
|
1da177e4c
|
830 831 832 |
list_del(&msg->m_list); msq->q_qnum--; msq->q_rtime = get_seconds(); |
b488893a3
|
833 |
msq->q_lrpid = task_tgid_vnr(current); |
1da177e4c
|
834 |
msq->q_cbytes -= msg->m_ts; |
3ac88a41f
|
835 836 |
atomic_sub(msg->m_ts, &ns->msg_bytes); atomic_dec(&ns->msg_hdrs); |
5a06a363e
|
837 |
ss_wakeup(&msq->q_senders, 0); |
41a0d523d
|
838 839 |
goto out_unlock0; |
1da177e4c
|
840 |
} |
41a0d523d
|
841 |
|
1da177e4c
|
842 843 844 |
/* No message waiting. Wait for a message */ if (msgflg & IPC_NOWAIT) { msg = ERR_PTR(-ENOMSG); |
41a0d523d
|
845 |
goto out_unlock0; |
1da177e4c
|
846 |
} |
41a0d523d
|
847 |
|
5a06a363e
|
848 |
list_add_tail(&msr_d.r_list, &msq->q_receivers); |
1da177e4c
|
849 850 851 |
msr_d.r_tsk = current; msr_d.r_msgtype = msgtyp; msr_d.r_mode = mode; |
5a06a363e
|
852 |
if (msgflg & MSG_NOERROR) |
1da177e4c
|
853 |
msr_d.r_maxsize = INT_MAX; |
5a06a363e
|
854 |
else |
f9dd87f47
|
855 |
msr_d.r_maxsize = bufsz; |
1da177e4c
|
856 |
msr_d.r_msg = ERR_PTR(-EAGAIN); |
f75a2f358
|
857 |
__set_current_state(TASK_INTERRUPTIBLE); |
1da177e4c
|
858 |
|
41a0d523d
|
859 860 |
ipc_unlock_object(&msq->q_perm); rcu_read_unlock(); |
1da177e4c
|
861 862 863 864 865 866 |
schedule(); /* Lockless receive, part 1: * Disable preemption. We don't hold a reference to the queue * and getting a reference would defeat the idea of a lockless * operation, thus the code relies on rcu to guarantee the |
25985edce
|
867 |
* existence of msq: |
1da177e4c
|
868 869 870 |
* Prior to destruction, expunge_all(-EIRDM) changes r_msg. * Thus if r_msg is -EAGAIN, then the queue not yet destroyed. * rcu_read_lock() prevents preemption between reading r_msg |
41a0d523d
|
871 |
* and acquiring the q_perm.lock in ipc_lock_object(). |
1da177e4c
|
872 873 874 875 876 877 878 879 |
*/ rcu_read_lock(); /* Lockless receive, part 2: * Wait until pipelined_send or expunge_all are outside of * wake_up_process(). There is a race with exit(), see * ipc/mqueue.c for the details. */ |
239521f31
|
880 |
msg = (struct msg_msg *)msr_d.r_msg; |
1da177e4c
|
881 882 |
while (msg == NULL) { cpu_relax(); |
5a06a363e
|
883 |
msg = (struct msg_msg *)msr_d.r_msg; |
1da177e4c
|
884 885 886 887 888 889 |
} /* Lockless receive, part 3: * If there is a message or an error then accept it without * locking. */ |
41a0d523d
|
890 891 |
if (msg != ERR_PTR(-EAGAIN)) goto out_unlock1; |
1da177e4c
|
892 893 894 895 |
/* Lockless receive, part 3: * Acquire the queue spinlock. */ |
41a0d523d
|
896 |
ipc_lock_object(&msq->q_perm); |
1da177e4c
|
897 898 899 900 |
/* Lockless receive, part 4: * Repeat test after acquiring the spinlock. */ |
239521f31
|
901 |
msg = (struct msg_msg *)msr_d.r_msg; |
5a06a363e
|
902 |
if (msg != ERR_PTR(-EAGAIN)) |
41a0d523d
|
903 |
goto out_unlock0; |
1da177e4c
|
904 905 906 907 |
list_del(&msr_d.r_list); if (signal_pending(current)) { msg = ERR_PTR(-ERESTARTNOHAND); |
41a0d523d
|
908 |
goto out_unlock0; |
1da177e4c
|
909 |
} |
41a0d523d
|
910 911 |
ipc_unlock_object(&msq->q_perm); |
1da177e4c
|
912 |
} |
41a0d523d
|
913 914 915 916 917 |
out_unlock0: ipc_unlock_object(&msq->q_perm); out_unlock1: rcu_read_unlock(); |
4a674f34b
|
918 |
if (IS_ERR(msg)) { |
85398aa8d
|
919 |
free_copy(copy); |
5a06a363e
|
920 |
return PTR_ERR(msg); |
4a674f34b
|
921 |
} |
1da177e4c
|
922 |
|
f9dd87f47
|
923 |
bufsz = msg_handler(buf, msg, bufsz); |
1da177e4c
|
924 |
free_msg(msg); |
5a06a363e
|
925 |
|
f9dd87f47
|
926 |
return bufsz; |
1da177e4c
|
927 |
} |
e48fbb699
|
928 929 |
SYSCALL_DEFINE5(msgrcv, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz, long, msgtyp, int, msgflg) |
651971cb7
|
930 |
{ |
f9dd87f47
|
931 |
return do_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg, do_msg_fill); |
651971cb7
|
932 |
} |
3440a6bd1
|
933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 |
/* * Scale msgmni with the available lowmem size: the memory dedicated to msg * queues should occupy at most 1/MSG_MEM_SCALE of lowmem. * Also take into account the number of nsproxies created so far. * This should be done staying within the (MSGMNI , IPCMNI/nr_ipc_ns) range. */ void recompute_msgmni(struct ipc_namespace *ns) { struct sysinfo i; unsigned long allowed; int nb_ns; si_meminfo(&i); allowed = (((i.totalram - i.totalhigh) / MSG_MEM_SCALE) * i.mem_unit) / MSGMNB; nb_ns = atomic_read(&nr_ipc_ns); allowed /= nb_ns; if (allowed < MSGMNI) { ns->msg_ctlmni = MSGMNI; return; } if (allowed > IPCMNI / nb_ns) { ns->msg_ctlmni = IPCMNI / nb_ns; return; } ns->msg_ctlmni = allowed; } void msg_init_ns(struct ipc_namespace *ns) { ns->msg_ctlmax = MSGMAX; ns->msg_ctlmnb = MSGMNB; recompute_msgmni(ns); atomic_set(&ns->msg_bytes, 0); atomic_set(&ns->msg_hdrs, 0); ipc_init_ids(&ns->ids[IPC_MSG_IDS]); } #ifdef CONFIG_IPC_NS void msg_exit_ns(struct ipc_namespace *ns) { free_ipcs(ns, &msg_ids(ns), freeque); idr_destroy(&ns->ids[IPC_MSG_IDS].ipcs_idr); } #endif |
1da177e4c
|
983 |
#ifdef CONFIG_PROC_FS |
19b4946ca
|
984 |
static int sysvipc_msg_proc_show(struct seq_file *s, void *it) |
1da177e4c
|
985 |
{ |
1efdb69b0
|
986 |
struct user_namespace *user_ns = seq_user_ns(s); |
19b4946ca
|
987 988 989 |
struct msg_queue *msq = it; return seq_printf(s, |
5a06a363e
|
990 991 992 |
"%10d %10d %4o %10lu %10lu %5u %5u %5u %5u %5u %5u %10lu %10lu %10lu ", msq->q_perm.key, |
7ca7e564e
|
993 |
msq->q_perm.id, |
5a06a363e
|
994 995 996 997 998 |
msq->q_perm.mode, msq->q_cbytes, msq->q_qnum, msq->q_lspid, msq->q_lrpid, |
1efdb69b0
|
999 1000 1001 1002 |
from_kuid_munged(user_ns, msq->q_perm.uid), from_kgid_munged(user_ns, msq->q_perm.gid), from_kuid_munged(user_ns, msq->q_perm.cuid), from_kgid_munged(user_ns, msq->q_perm.cgid), |
5a06a363e
|
1003 1004 1005 |
msq->q_stime, msq->q_rtime, msq->q_ctime); |
1da177e4c
|
1006 1007 |
} #endif |
3440a6bd1
|
1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 |
void __init msg_init(void) { msg_init_ns(&init_ipc_ns); printk(KERN_INFO "msgmni has been set to %d ", init_ipc_ns.msg_ctlmni); ipc_init_proc_interface("sysvipc/msg", " key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime ", IPC_MSG_IDS, sysvipc_msg_proc_show); } |