Blame view

ipc/msg.c 20.5 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
  /*
   * linux/ipc/msg.c
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
3
   * Copyright (C) 1992 Krishna Balasubramanian
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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   Christian Kujau   correct email add...
15
   * (c) 1999 Manfred Spraul <manfred@colorfullife.com>
073115d6b   Steve Grubb   [PATCH] Rework of...
16
17
18
   *
   * support for audit of ipc object properties and permission changes
   * Dustin Kirkland <dustin.kirkland@us.ibm.com>
1e7869373   Kirill Korotaev   [PATCH] IPC names...
19
20
21
22
   *
   * namespaces support
   * OpenVZ, SWsoft Inc.
   * Pavel Emelianov <xemul@openvz.org>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
   */
c59ede7b7   Randy.Dunlap   [PATCH] move capa...
24
  #include <linux/capability.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
26
27
28
29
30
31
32
33
34
  #include <linux/slab.h>
  #include <linux/msg.h>
  #include <linux/spinlock.h>
  #include <linux/init.h>
  #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   Mike Waychison   [PATCH] ipc: conv...
35
  #include <linux/seq_file.h>
5f921ae96   Ingo Molnar   [PATCH] sem2mutex...
36
  #include <linux/mutex.h>
1e7869373   Kirill Korotaev   [PATCH] IPC names...
37
  #include <linux/nsproxy.h>
5f921ae96   Ingo Molnar   [PATCH] sem2mutex...
38

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
41
  #include <asm/current.h>
  #include <asm/uaccess.h>
  #include "util.h"
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
42
43
44
  /*
   * one msg_receiver structure for each sleeping receiver:
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
  struct msg_receiver {
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
46
47
  	struct list_head	r_list;
  	struct task_struct	*r_tsk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48

5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
49
50
51
  	int			r_mode;
  	long			r_msgtype;
  	long			r_maxsize;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52

80491eb90   Linus Torvalds   Revert unintentio...
53
  	struct msg_msg		*volatile r_msg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
55
56
57
  };
  
  /* one msg_sender for each sleeping sender */
  struct msg_sender {
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
58
59
  	struct list_head	list;
  	struct task_struct	*tsk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
61
62
63
64
65
  };
  
  #define SEARCH_ANY		1
  #define SEARCH_EQUAL		2
  #define SEARCH_NOTEQUAL		3
  #define SEARCH_LESSEQUAL	4
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
66
67
  static atomic_t msg_bytes =	ATOMIC_INIT(0);
  static atomic_t msg_hdrs =	ATOMIC_INIT(0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68

1e7869373   Kirill Korotaev   [PATCH] IPC names...
69
  static struct ipc_ids init_msg_ids;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70

1e7869373   Kirill Korotaev   [PATCH] IPC names...
71
  #define msg_ids(ns)	(*((ns)->ids[IPC_MSG_IDS]))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72

1e7869373   Kirill Korotaev   [PATCH] IPC names...
73
74
75
76
77
78
79
80
81
82
  #define msg_lock(ns, id)	((struct msg_queue*)ipc_lock(&msg_ids(ns), id))
  #define msg_unlock(msq)		ipc_unlock(&(msq)->q_perm)
  #define msg_rmid(ns, id)	((struct msg_queue*)ipc_rmid(&msg_ids(ns), id))
  #define msg_checkid(ns, msq, msgid)	\
  	ipc_checkid(&msg_ids(ns), &msq->q_perm, msgid)
  #define msg_buildid(ns, id, seq) \
  	ipc_buildid(&msg_ids(ns), id, seq)
  
  static void freeque (struct ipc_namespace *ns, struct msg_queue *msq, int id);
  static int newque (struct ipc_namespace *ns, key_t key, int msgflg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
  #ifdef CONFIG_PROC_FS
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
84
  static int sysvipc_msg_proc_show(struct seq_file *s, void *it);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
  #endif
1e7869373   Kirill Korotaev   [PATCH] IPC names...
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
  static void __ipc_init __msg_init_ns(struct ipc_namespace *ns, struct ipc_ids *ids)
  {
  	ns->ids[IPC_MSG_IDS] = ids;
  	ns->msg_ctlmax = MSGMAX;
  	ns->msg_ctlmnb = MSGMNB;
  	ns->msg_ctlmni = MSGMNI;
  	ipc_init_ids(ids, ns->msg_ctlmni);
  }
  
  #ifdef CONFIG_IPC_NS
  int msg_init_ns(struct ipc_namespace *ns)
  {
  	struct ipc_ids *ids;
  
  	ids = kmalloc(sizeof(struct ipc_ids), GFP_KERNEL);
  	if (ids == NULL)
  		return -ENOMEM;
  
  	__msg_init_ns(ns, ids);
  	return 0;
  }
  
  void msg_exit_ns(struct ipc_namespace *ns)
  {
  	int i;
  	struct msg_queue *msq;
  
  	mutex_lock(&msg_ids(ns).mutex);
  	for (i = 0; i <= msg_ids(ns).max_id; i++) {
  		msq = msg_lock(ns, i);
  		if (msq == NULL)
  			continue;
  
  		freeque(ns, msq, i);
  	}
  	mutex_unlock(&msg_ids(ns).mutex);
c7e12b838   Pavel Emelianov   [PATCH] Fix ipc e...
122
  	ipc_fini_ids(ns->ids[IPC_MSG_IDS]);
1e7869373   Kirill Korotaev   [PATCH] IPC names...
123
124
125
126
  	kfree(ns->ids[IPC_MSG_IDS]);
  	ns->ids[IPC_MSG_IDS] = NULL;
  }
  #endif
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
127
  void __init msg_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128
  {
1e7869373   Kirill Korotaev   [PATCH] IPC names...
129
  	__msg_init_ns(&init_ipc_ns, &init_msg_ids);
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
130
131
132
  	ipc_init_proc_interface("sysvipc/msg",
  				"       key      msqid perms      cbytes       qnum lspid lrpid   uid   gid  cuid  cgid      stime      rtime      ctime
  ",
1e7869373   Kirill Korotaev   [PATCH] IPC names...
133
  				IPC_MSG_IDS, sysvipc_msg_proc_show);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
  }
1e7869373   Kirill Korotaev   [PATCH] IPC names...
135
  static int newque (struct ipc_namespace *ns, key_t key, int msgflg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
  	struct msg_queue *msq;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
138
  	int id, retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139

5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
140
141
  	msq = ipc_rcu_alloc(sizeof(*msq));
  	if (!msq)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
  		return -ENOMEM;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
143
  	msq->q_perm.mode = msgflg & S_IRWXUGO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
145
146
147
148
149
150
151
  	msq->q_perm.key = key;
  
  	msq->q_perm.security = NULL;
  	retval = security_msg_queue_alloc(msq);
  	if (retval) {
  		ipc_rcu_putref(msq);
  		return retval;
  	}
1e7869373   Kirill Korotaev   [PATCH] IPC names...
152
  	id = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni);
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
153
  	if (id == -1) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
155
156
157
  		security_msg_queue_free(msq);
  		ipc_rcu_putref(msq);
  		return -ENOSPC;
  	}
1e7869373   Kirill Korotaev   [PATCH] IPC names...
158
  	msq->q_id = msg_buildid(ns, id, msq->q_perm.seq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
160
161
  	msq->q_stime = msq->q_rtime = 0;
  	msq->q_ctime = get_seconds();
  	msq->q_cbytes = msq->q_qnum = 0;
1e7869373   Kirill Korotaev   [PATCH] IPC names...
162
  	msq->q_qbytes = ns->msg_ctlmnb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
164
165
166
167
  	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);
  	msg_unlock(msq);
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
168
  	return msq->q_id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
  }
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
170
  static inline void ss_add(struct msg_queue *msq, struct msg_sender *mss)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
  {
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
172
173
174
  	mss->tsk = current;
  	current->state = TASK_INTERRUPTIBLE;
  	list_add_tail(&mss->list, &msq->q_senders);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
  }
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
176
  static inline void ss_del(struct msg_sender *mss)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
  {
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
178
  	if (mss->list.next != NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
180
  		list_del(&mss->list);
  }
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
181
  static void ss_wakeup(struct list_head *h, int kill)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
183
184
185
186
  {
  	struct list_head *tmp;
  
  	tmp = h->next;
  	while (tmp != h) {
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
187
188
189
  		struct msg_sender *mss;
  
  		mss = list_entry(tmp, struct msg_sender, list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190
  		tmp = tmp->next;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
191
192
  		if (kill)
  			mss->list.next = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
194
195
  		wake_up_process(mss->tsk);
  	}
  }
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
196
  static void expunge_all(struct msg_queue *msq, int res)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
197
198
199
200
201
  {
  	struct list_head *tmp;
  
  	tmp = msq->q_receivers.next;
  	while (tmp != &msq->q_receivers) {
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
202
203
204
  		struct msg_receiver *msr;
  
  		msr = list_entry(tmp, struct msg_receiver, r_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
205
206
207
208
209
210
211
  		tmp = tmp->next;
  		msr->r_msg = NULL;
  		wake_up_process(msr->r_tsk);
  		smp_mb();
  		msr->r_msg = ERR_PTR(res);
  	}
  }
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
212
213
214
215
  
  /*
   * freeque() wakes up waiters on the sender and receiver waiting queue,
   * removes the message queue from message queue ID
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216
217
   * array, and cleans up all the messages associated with this queue.
   *
5f921ae96   Ingo Molnar   [PATCH] sem2mutex...
218
219
   * msg_ids.mutex and the spinlock for this message queue is hold
   * before freeque() is called. msg_ids.mutex remains locked on exit.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220
   */
1e7869373   Kirill Korotaev   [PATCH] IPC names...
221
  static void freeque(struct ipc_namespace *ns, struct msg_queue *msq, int id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222
223
  {
  	struct list_head *tmp;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
224
225
  	expunge_all(msq, -EIDRM);
  	ss_wakeup(&msq->q_senders, 1);
1e7869373   Kirill Korotaev   [PATCH] IPC names...
226
  	msq = msg_rmid(ns, id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
  	msg_unlock(msq);
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
228

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
  	tmp = msq->q_messages.next;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
230
231
  	while (tmp != &msq->q_messages) {
  		struct msg_msg *msg = list_entry(tmp, struct msg_msg, m_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232
233
234
235
236
237
238
239
  		tmp = tmp->next;
  		atomic_dec(&msg_hdrs);
  		free_msg(msg);
  	}
  	atomic_sub(msq->q_cbytes, &msg_bytes);
  	security_msg_queue_free(msq);
  	ipc_rcu_putref(msq);
  }
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
240
  asmlinkage long sys_msgget(key_t key, int msgflg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
241
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242
  	struct msg_queue *msq;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
243
  	int id, ret = -EPERM;
1e7869373   Kirill Korotaev   [PATCH] IPC names...
244
245
246
  	struct ipc_namespace *ns;
  
  	ns = current->nsproxy->ipc_ns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
  	
1e7869373   Kirill Korotaev   [PATCH] IPC names...
248
  	mutex_lock(&msg_ids(ns).mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
  	if (key == IPC_PRIVATE) 
1e7869373   Kirill Korotaev   [PATCH] IPC names...
250
251
  		ret = newque(ns, key, msgflg);
  	else if ((id = ipc_findkey(&msg_ids(ns), key)) == -1) { /* key not used */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252
253
254
  		if (!(msgflg & IPC_CREAT))
  			ret = -ENOENT;
  		else
1e7869373   Kirill Korotaev   [PATCH] IPC names...
255
  			ret = newque(ns, key, msgflg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256
257
258
  	} else if (msgflg & IPC_CREAT && msgflg & IPC_EXCL) {
  		ret = -EEXIST;
  	} else {
1e7869373   Kirill Korotaev   [PATCH] IPC names...
259
  		msq = msg_lock(ns, id);
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
260
  		BUG_ON(msq == NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261
262
263
  		if (ipcperms(&msq->q_perm, msgflg))
  			ret = -EACCES;
  		else {
1e7869373   Kirill Korotaev   [PATCH] IPC names...
264
  			int qid = msg_buildid(ns, id, msq->q_perm.seq);
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
265
266
  
  			ret = security_msg_queue_associate(msq, msgflg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
267
268
269
270
271
  			if (!ret)
  				ret = qid;
  		}
  		msg_unlock(msq);
  	}
1e7869373   Kirill Korotaev   [PATCH] IPC names...
272
  	mutex_unlock(&msg_ids(ns).mutex);
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
273

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
275
  	return ret;
  }
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
276
277
  static inline unsigned long
  copy_msqid_to_user(void __user *buf, struct msqid64_ds *in, int version)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
278
279
280
  {
  	switch(version) {
  	case IPC_64:
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
281
  		return copy_to_user(buf, in, sizeof(*in));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282
  	case IPC_OLD:
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
283
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284
  		struct msqid_ds out;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
285
  		memset(&out, 0, sizeof(out));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286
287
288
289
290
291
  
  		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;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
292
  		if (in->msg_cbytes > USHRT_MAX)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
294
295
296
  			out.msg_cbytes	= USHRT_MAX;
  		else
  			out.msg_cbytes	= in->msg_cbytes;
  		out.msg_lcbytes		= in->msg_cbytes;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
297
  		if (in->msg_qnum > USHRT_MAX)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
298
299
300
  			out.msg_qnum	= USHRT_MAX;
  		else
  			out.msg_qnum	= in->msg_qnum;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
301
  		if (in->msg_qbytes > USHRT_MAX)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302
303
304
305
306
307
308
  			out.msg_qbytes	= USHRT_MAX;
  		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   Ingo Molnar   [PATCH] ipc/msg.c...
309
310
  		return copy_to_user(buf, &out, sizeof(out));
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311
312
313
314
315
316
317
318
319
320
321
  	default:
  		return -EINVAL;
  	}
  }
  
  struct msq_setbuf {
  	unsigned long	qbytes;
  	uid_t		uid;
  	gid_t		gid;
  	mode_t		mode;
  };
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
322
323
  static inline unsigned long
  copy_msqid_from_user(struct msq_setbuf *out, void __user *buf, int version)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324
325
326
  {
  	switch(version) {
  	case IPC_64:
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
327
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
328
  		struct msqid64_ds tbuf;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
329
  		if (copy_from_user(&tbuf, buf, sizeof(tbuf)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330
331
332
333
334
335
336
337
  			return -EFAULT;
  
  		out->qbytes		= tbuf.msg_qbytes;
  		out->uid		= tbuf.msg_perm.uid;
  		out->gid		= tbuf.msg_perm.gid;
  		out->mode		= tbuf.msg_perm.mode;
  
  		return 0;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
338
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
  	case IPC_OLD:
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
340
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
341
  		struct msqid_ds tbuf_old;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
342
  		if (copy_from_user(&tbuf_old, buf, sizeof(tbuf_old)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
343
344
345
346
347
  			return -EFAULT;
  
  		out->uid		= tbuf_old.msg_perm.uid;
  		out->gid		= tbuf_old.msg_perm.gid;
  		out->mode		= tbuf_old.msg_perm.mode;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
348
  		if (tbuf_old.msg_qbytes == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
350
351
352
353
  			out->qbytes	= tbuf_old.msg_lqbytes;
  		else
  			out->qbytes	= tbuf_old.msg_qbytes;
  
  		return 0;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
354
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
355
356
357
358
  	default:
  		return -EINVAL;
  	}
  }
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
359
  asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
360
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
361
  	struct kern_ipc_perm *ipcp;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
362
363
364
  	struct msq_setbuf setbuf;
  	struct msg_queue *msq;
  	int err, version;
1e7869373   Kirill Korotaev   [PATCH] IPC names...
365
  	struct ipc_namespace *ns;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
366

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
368
369
370
  	if (msqid < 0 || cmd < 0)
  		return -EINVAL;
  
  	version = ipc_parse_version(&cmd);
1e7869373   Kirill Korotaev   [PATCH] IPC names...
371
  	ns = current->nsproxy->ipc_ns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
372
373
  
  	switch (cmd) {
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
374
375
376
  	case IPC_INFO:
  	case MSG_INFO:
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
377
378
  		struct msginfo msginfo;
  		int max_id;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
379

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
381
  		if (!buf)
  			return -EFAULT;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
382
383
  		/*
  		 * We must not return kernel stack data.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
384
385
386
  		 * due to padding, it's not enough
  		 * to set all member fields.
  		 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387
388
389
  		err = security_msg_queue_msgctl(NULL, cmd);
  		if (err)
  			return err;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
390
  		memset(&msginfo, 0, sizeof(msginfo));
1e7869373   Kirill Korotaev   [PATCH] IPC names...
391
392
393
  		msginfo.msgmni = ns->msg_ctlmni;
  		msginfo.msgmax = ns->msg_ctlmax;
  		msginfo.msgmnb = ns->msg_ctlmnb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394
395
  		msginfo.msgssz = MSGSSZ;
  		msginfo.msgseg = MSGSEG;
1e7869373   Kirill Korotaev   [PATCH] IPC names...
396
  		mutex_lock(&msg_ids(ns).mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
397
  		if (cmd == MSG_INFO) {
1e7869373   Kirill Korotaev   [PATCH] IPC names...
398
  			msginfo.msgpool = msg_ids(ns).in_use;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
399
400
401
402
403
404
405
  			msginfo.msgmap = atomic_read(&msg_hdrs);
  			msginfo.msgtql = atomic_read(&msg_bytes);
  		} else {
  			msginfo.msgmap = MSGMAP;
  			msginfo.msgpool = MSGPOOL;
  			msginfo.msgtql = MSGTQL;
  		}
1e7869373   Kirill Korotaev   [PATCH] IPC names...
406
407
  		max_id = msg_ids(ns).max_id;
  		mutex_unlock(&msg_ids(ns).mutex);
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
408
  		if (copy_to_user(buf, &msginfo, sizeof(struct msginfo)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
409
  			return -EFAULT;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
410
  		return (max_id < 0) ? 0 : max_id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
412
413
414
415
416
  	}
  	case MSG_STAT:
  	case IPC_STAT:
  	{
  		struct msqid64_ds tbuf;
  		int success_return;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
417

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418
419
  		if (!buf)
  			return -EFAULT;
1e7869373   Kirill Korotaev   [PATCH] IPC names...
420
  		if (cmd == MSG_STAT && msqid >= msg_ids(ns).entries->size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
421
  			return -EINVAL;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
422
  		memset(&tbuf, 0, sizeof(tbuf));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423

1e7869373   Kirill Korotaev   [PATCH] IPC names...
424
  		msq = msg_lock(ns, msqid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
425
426
  		if (msq == NULL)
  			return -EINVAL;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
427
  		if (cmd == MSG_STAT) {
1e7869373   Kirill Korotaev   [PATCH] IPC names...
428
  			success_return = msg_buildid(ns, msqid, msq->q_perm.seq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429
430
  		} else {
  			err = -EIDRM;
1e7869373   Kirill Korotaev   [PATCH] IPC names...
431
  			if (msg_checkid(ns, msq, msqid))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
432
433
434
435
  				goto out_unlock;
  			success_return = 0;
  		}
  		err = -EACCES;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
436
  		if (ipcperms(&msq->q_perm, S_IRUGO))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
  			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;
  		msg_unlock(msq);
  		if (copy_msqid_to_user(buf, &tbuf, version))
  			return -EFAULT;
  		return success_return;
  	}
  	case IPC_SET:
  		if (!buf)
  			return -EFAULT;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
460
  		if (copy_msqid_from_user(&setbuf, buf, version))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
461
  			return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
462
463
464
465
466
467
  		break;
  	case IPC_RMID:
  		break;
  	default:
  		return  -EINVAL;
  	}
1e7869373   Kirill Korotaev   [PATCH] IPC names...
468
469
  	mutex_lock(&msg_ids(ns).mutex);
  	msq = msg_lock(ns, msqid);
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
470
  	err = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
471
472
473
474
  	if (msq == NULL)
  		goto out_up;
  
  	err = -EIDRM;
1e7869373   Kirill Korotaev   [PATCH] IPC names...
475
  	if (msg_checkid(ns, msq, msqid))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
476
477
  		goto out_unlock_up;
  	ipcp = &msq->q_perm;
073115d6b   Steve Grubb   [PATCH] Rework of...
478
479
480
481
  
  	err = audit_ipc_obj(ipcp);
  	if (err)
  		goto out_unlock_up;
ac03221a4   Linda Knippers   [PATCH] update of...
482
  	if (cmd==IPC_SET) {
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
483
484
  		err = audit_ipc_set_perm(setbuf.qbytes, setbuf.uid, setbuf.gid,
  					 setbuf.mode);
ac03221a4   Linda Knippers   [PATCH] update of...
485
486
487
  		if (err)
  			goto out_unlock_up;
  	}
073115d6b   Steve Grubb   [PATCH] Rework of...
488

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489
  	err = -EPERM;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
490
  	if (current->euid != ipcp->cuid &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
491
  	    current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN))
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
492
  		/* We _could_ check for CAP_CHOWN above, but we don't */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493
494
495
496
497
498
499
500
501
502
  		goto out_unlock_up;
  
  	err = security_msg_queue_msgctl(msq, cmd);
  	if (err)
  		goto out_unlock_up;
  
  	switch (cmd) {
  	case IPC_SET:
  	{
  		err = -EPERM;
1e7869373   Kirill Korotaev   [PATCH] IPC names...
503
  		if (setbuf.qbytes > ns->msg_ctlmnb && !capable(CAP_SYS_RESOURCE))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
504
505
506
507
508
509
  			goto out_unlock_up;
  
  		msq->q_qbytes = setbuf.qbytes;
  
  		ipcp->uid = setbuf.uid;
  		ipcp->gid = setbuf.gid;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
510
511
  		ipcp->mode = (ipcp->mode & ~S_IRWXUGO) |
  			     (S_IRWXUGO & setbuf.mode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
512
513
514
515
  		msq->q_ctime = get_seconds();
  		/* sleeping receivers might be excluded by
  		 * stricter permissions.
  		 */
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
516
  		expunge_all(msq, -EAGAIN);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
517
518
519
  		/* sleeping senders might be able to send
  		 * due to a larger queue size.
  		 */
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
520
  		ss_wakeup(&msq->q_senders, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
521
522
523
524
  		msg_unlock(msq);
  		break;
  	}
  	case IPC_RMID:
1e7869373   Kirill Korotaev   [PATCH] IPC names...
525
  		freeque(ns, msq, msqid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526
527
528
529
  		break;
  	}
  	err = 0;
  out_up:
1e7869373   Kirill Korotaev   [PATCH] IPC names...
530
  	mutex_unlock(&msg_ids(ns).mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
531
532
533
534
535
536
537
538
  	return err;
  out_unlock_up:
  	msg_unlock(msq);
  	goto out_up;
  out_unlock:
  	msg_unlock(msq);
  	return err;
  }
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
539
  static int testmsg(struct msg_msg *msg, long type, int mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
540
541
542
543
544
545
  {
  	switch(mode)
  	{
  		case SEARCH_ANY:
  			return 1;
  		case SEARCH_LESSEQUAL:
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
546
  			if (msg->m_type <=type)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
547
548
549
  				return 1;
  			break;
  		case SEARCH_EQUAL:
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
550
  			if (msg->m_type == type)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551
552
553
  				return 1;
  			break;
  		case SEARCH_NOTEQUAL:
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
554
  			if (msg->m_type != type)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555
556
557
558
559
  				return 1;
  			break;
  	}
  	return 0;
  }
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
560
  static inline int pipelined_send(struct msg_queue *msq, struct msg_msg *msg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561
  {
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
562
  	struct list_head *tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
563
564
565
  
  	tmp = msq->q_receivers.next;
  	while (tmp != &msq->q_receivers) {
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
566
567
568
  		struct msg_receiver *msr;
  
  		msr = list_entry(tmp, struct msg_receiver, r_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
569
  		tmp = tmp->next;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
570
571
572
  		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   Linus Torvalds   Linux-2.6.12-rc2
573
  			list_del(&msr->r_list);
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
574
  			if (msr->r_maxsize < msg->m_ts) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
575
576
577
578
579
580
581
582
583
584
585
  				msr->r_msg = NULL;
  				wake_up_process(msr->r_tsk);
  				smp_mb();
  				msr->r_msg = ERR_PTR(-E2BIG);
  			} else {
  				msr->r_msg = NULL;
  				msq->q_lrpid = msr->r_tsk->pid;
  				msq->q_rtime = get_seconds();
  				wake_up_process(msr->r_tsk);
  				smp_mb();
  				msr->r_msg = msg;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
586

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
587
588
589
590
591
592
  				return 1;
  			}
  		}
  	}
  	return 0;
  }
651971cb7   suzuki   [PATCH] Fix the s...
593
594
  long do_msgsnd(int msqid, long mtype, void __user *mtext,
  		size_t msgsz, int msgflg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
595
596
597
  {
  	struct msg_queue *msq;
  	struct msg_msg *msg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
598
  	int err;
1e7869373   Kirill Korotaev   [PATCH] IPC names...
599
600
601
  	struct ipc_namespace *ns;
  
  	ns = current->nsproxy->ipc_ns;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
602

1e7869373   Kirill Korotaev   [PATCH] IPC names...
603
  	if (msgsz > ns->msg_ctlmax || (long) msgsz < 0 || msqid < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
604
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
605
606
  	if (mtype < 1)
  		return -EINVAL;
651971cb7   suzuki   [PATCH] Fix the s...
607
  	msg = load_msg(mtext, msgsz);
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
608
  	if (IS_ERR(msg))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
609
610
611
612
  		return PTR_ERR(msg);
  
  	msg->m_type = mtype;
  	msg->m_ts = msgsz;
1e7869373   Kirill Korotaev   [PATCH] IPC names...
613
  	msq = msg_lock(ns, msqid);
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
614
615
  	err = -EINVAL;
  	if (msq == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
616
617
618
  		goto out_free;
  
  	err= -EIDRM;
1e7869373   Kirill Korotaev   [PATCH] IPC names...
619
  	if (msg_checkid(ns, msq, msqid))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
620
621
622
623
  		goto out_unlock_free;
  
  	for (;;) {
  		struct msg_sender s;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
624
  		err = -EACCES;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
625
626
627
628
629
630
  		if (ipcperms(&msq->q_perm, S_IWUGO))
  			goto out_unlock_free;
  
  		err = security_msg_queue_msgsnd(msq, msg, msgflg);
  		if (err)
  			goto out_unlock_free;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
631
  		if (msgsz + msq->q_cbytes <= msq->q_qbytes &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
632
633
634
635
636
  				1 + msq->q_qnum <= msq->q_qbytes) {
  			break;
  		}
  
  		/* queue full, wait: */
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
637
638
  		if (msgflg & IPC_NOWAIT) {
  			err = -EAGAIN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
639
640
641
642
643
644
645
646
647
648
649
650
651
652
  			goto out_unlock_free;
  		}
  		ss_add(msq, &s);
  		ipc_rcu_getref(msq);
  		msg_unlock(msq);
  		schedule();
  
  		ipc_lock_by_ptr(&msq->q_perm);
  		ipc_rcu_putref(msq);
  		if (msq->q_perm.deleted) {
  			err = -EIDRM;
  			goto out_unlock_free;
  		}
  		ss_del(&s);
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
653

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
654
  		if (signal_pending(current)) {
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
655
  			err = -ERESTARTNOHAND;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
656
657
658
659
660
661
  			goto out_unlock_free;
  		}
  	}
  
  	msq->q_lspid = current->tgid;
  	msq->q_stime = get_seconds();
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
662
  	if (!pipelined_send(msq, msg)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
663
  		/* noone is waiting for this message, enqueue it */
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
664
  		list_add_tail(&msg->m_list, &msq->q_messages);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
665
666
  		msq->q_cbytes += msgsz;
  		msq->q_qnum++;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
667
  		atomic_add(msgsz, &msg_bytes);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
668
669
  		atomic_inc(&msg_hdrs);
  	}
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
670

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
671
672
673
674
675
676
  	err = 0;
  	msg = NULL;
  
  out_unlock_free:
  	msg_unlock(msq);
  out_free:
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
677
  	if (msg != NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
678
679
680
  		free_msg(msg);
  	return err;
  }
651971cb7   suzuki   [PATCH] Fix the s...
681
682
683
684
685
686
687
688
689
  asmlinkage long
  sys_msgsnd(int msqid, struct msgbuf __user *msgp, size_t msgsz, int msgflg)
  {
  	long mtype;
  
  	if (get_user(mtype, &msgp->mtype))
  		return -EFAULT;
  	return do_msgsnd(msqid, mtype, msgp->mtext, msgsz, msgflg);
  }
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
690
  static inline int convert_mode(long *msgtyp, int msgflg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
691
  {
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
692
  	/*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
693
694
695
  	 *  find message of correct type.
  	 *  msgtyp = 0 => get first.
  	 *  msgtyp > 0 => get first message of matching type.
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
696
  	 *  msgtyp < 0 => get message with least type must be < abs(msgtype).
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
697
  	 */
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
698
  	if (*msgtyp == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
699
  		return SEARCH_ANY;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
700
701
  	if (*msgtyp < 0) {
  		*msgtyp = -*msgtyp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
702
703
  		return SEARCH_LESSEQUAL;
  	}
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
704
  	if (msgflg & MSG_EXCEPT)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
705
706
707
  		return SEARCH_NOTEQUAL;
  	return SEARCH_EQUAL;
  }
651971cb7   suzuki   [PATCH] Fix the s...
708
709
  long do_msgrcv(int msqid, long *pmtype, void __user *mtext,
  		size_t msgsz, long msgtyp, int msgflg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
710
711
712
713
  {
  	struct msg_queue *msq;
  	struct msg_msg *msg;
  	int mode;
1e7869373   Kirill Korotaev   [PATCH] IPC names...
714
  	struct ipc_namespace *ns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
715
716
717
  
  	if (msqid < 0 || (long) msgsz < 0)
  		return -EINVAL;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
718
  	mode = convert_mode(&msgtyp, msgflg);
1e7869373   Kirill Korotaev   [PATCH] IPC names...
719
  	ns = current->nsproxy->ipc_ns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
720

1e7869373   Kirill Korotaev   [PATCH] IPC names...
721
  	msq = msg_lock(ns, msqid);
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
722
  	if (msq == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
723
724
725
  		return -EINVAL;
  
  	msg = ERR_PTR(-EIDRM);
1e7869373   Kirill Korotaev   [PATCH] IPC names...
726
  	if (msg_checkid(ns, msq, msqid))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
727
728
729
730
  		goto out_unlock;
  
  	for (;;) {
  		struct msg_receiver msr_d;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
731
  		struct list_head *tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
732
733
  
  		msg = ERR_PTR(-EACCES);
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
734
  		if (ipcperms(&msq->q_perm, S_IRUGO))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
735
736
737
738
739
740
  			goto out_unlock;
  
  		msg = ERR_PTR(-EAGAIN);
  		tmp = msq->q_messages.next;
  		while (tmp != &msq->q_messages) {
  			struct msg_msg *walk_msg;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
741
742
743
744
745
  
  			walk_msg = list_entry(tmp, struct msg_msg, m_list);
  			if (testmsg(walk_msg, msgtyp, mode) &&
  			    !security_msg_queue_msgrcv(msq, walk_msg, current,
  						       msgtyp, mode)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
746
  				msg = walk_msg;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
747
748
749
750
  				if (mode == SEARCH_LESSEQUAL &&
  						walk_msg->m_type != 1) {
  					msg = walk_msg;
  					msgtyp = walk_msg->m_type - 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
751
  				} else {
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
752
  					msg = walk_msg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
754
755
756
757
  					break;
  				}
  			}
  			tmp = tmp->next;
  		}
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
758
759
760
761
762
  		if (!IS_ERR(msg)) {
  			/*
  			 * Found a suitable message.
  			 * Unlink it from the queue.
  			 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
763
764
765
766
767
768
769
770
771
  			if ((msgsz < msg->m_ts) && !(msgflg & MSG_NOERROR)) {
  				msg = ERR_PTR(-E2BIG);
  				goto out_unlock;
  			}
  			list_del(&msg->m_list);
  			msq->q_qnum--;
  			msq->q_rtime = get_seconds();
  			msq->q_lrpid = current->tgid;
  			msq->q_cbytes -= msg->m_ts;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
772
  			atomic_sub(msg->m_ts, &msg_bytes);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773
  			atomic_dec(&msg_hdrs);
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
774
  			ss_wakeup(&msq->q_senders, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
775
776
777
778
779
780
781
782
  			msg_unlock(msq);
  			break;
  		}
  		/* No message waiting. Wait for a message */
  		if (msgflg & IPC_NOWAIT) {
  			msg = ERR_PTR(-ENOMSG);
  			goto out_unlock;
  		}
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
783
  		list_add_tail(&msr_d.r_list, &msq->q_receivers);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
784
785
786
  		msr_d.r_tsk = current;
  		msr_d.r_msgtype = msgtyp;
  		msr_d.r_mode = mode;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
787
  		if (msgflg & MSG_NOERROR)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
788
  			msr_d.r_maxsize = INT_MAX;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
789
  		else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
  			msr_d.r_maxsize = msgsz;
  		msr_d.r_msg = ERR_PTR(-EAGAIN);
  		current->state = TASK_INTERRUPTIBLE;
  		msg_unlock(msq);
  
  		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
  		 * existance of msq:
  		 * 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
  		 * and the spin_lock() inside ipc_lock_by_ptr().
  		 */
  		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.
  		 */
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
814
  		msg = (struct msg_msg*)msr_d.r_msg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
815
816
  		while (msg == NULL) {
  			cpu_relax();
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
817
  			msg = (struct msg_msg *)msr_d.r_msg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
818
819
820
821
822
823
  		}
  
  		/* Lockless receive, part 3:
  		 * If there is a message or an error then accept it without
  		 * locking.
  		 */
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
824
  		if (msg != ERR_PTR(-EAGAIN)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
825
826
827
828
829
830
831
832
833
834
835
836
837
838
  			rcu_read_unlock();
  			break;
  		}
  
  		/* Lockless receive, part 3:
  		 * Acquire the queue spinlock.
  		 */
  		ipc_lock_by_ptr(&msq->q_perm);
  		rcu_read_unlock();
  
  		/* Lockless receive, part 4:
  		 * Repeat test after acquiring the spinlock.
  		 */
  		msg = (struct msg_msg*)msr_d.r_msg;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
839
  		if (msg != ERR_PTR(-EAGAIN))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
840
841
842
843
844
845
846
847
848
849
850
  			goto out_unlock;
  
  		list_del(&msr_d.r_list);
  		if (signal_pending(current)) {
  			msg = ERR_PTR(-ERESTARTNOHAND);
  out_unlock:
  			msg_unlock(msq);
  			break;
  		}
  	}
  	if (IS_ERR(msg))
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
851
  		return PTR_ERR(msg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
852
853
  
  	msgsz = (msgsz > msg->m_ts) ? msg->m_ts : msgsz;
651971cb7   suzuki   [PATCH] Fix the s...
854
855
  	*pmtype = msg->m_type;
  	if (store_msg(mtext, msg, msgsz))
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
856
  		msgsz = -EFAULT;
651971cb7   suzuki   [PATCH] Fix the s...
857

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
858
  	free_msg(msg);
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
859

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
860
861
  	return msgsz;
  }
651971cb7   suzuki   [PATCH] Fix the s...
862
863
864
865
866
867
868
869
870
871
872
873
874
875
  asmlinkage long sys_msgrcv(int msqid, struct msgbuf __user *msgp, size_t msgsz,
  			   long msgtyp, int msgflg)
  {
  	long err, mtype;
  
  	err =  do_msgrcv(msqid, &mtype, msgp->mtext, msgsz, msgtyp, msgflg);
  	if (err < 0)
  		goto out;
  
  	if (put_user(mtype, &msgp->mtype))
  		err = -EFAULT;
  out:
  	return err;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
876
  #ifdef CONFIG_PROC_FS
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
877
  static int sysvipc_msg_proc_show(struct seq_file *s, void *it)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
878
  {
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
879
880
881
  	struct msg_queue *msq = it;
  
  	return seq_printf(s,
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
  			"%10d %10d  %4o  %10lu %10lu %5u %5u %5u %5u %5u %5u %10lu %10lu %10lu
  ",
  			msq->q_perm.key,
  			msq->q_id,
  			msq->q_perm.mode,
  			msq->q_cbytes,
  			msq->q_qnum,
  			msq->q_lspid,
  			msq->q_lrpid,
  			msq->q_perm.uid,
  			msq->q_perm.gid,
  			msq->q_perm.cuid,
  			msq->q_perm.cgid,
  			msq->q_stime,
  			msq->q_rtime,
  			msq->q_ctime);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
898
899
  }
  #endif