]>
Commit | Line | Data |
---|---|---|
f328a626 | 1 | diff -urN 2.6.0-test10-orig_2/arch/i386/kernel/entry.S 2.6.0-test10-patched_2/arch/i386/kernel/entry.S |
2 | --- 2.6.0-test10-orig_2/arch/i386/kernel/entry.S 2003-11-24 16:28:52.000000000 +0100 | |
3 | +++ 2.6.0-test10-patched_2/arch/i386/kernel/entry.S 2003-11-24 16:46:44.000000000 +0100 | |
4 | @@ -882,5 +882,12 @@ | |
5 | .long sys_utimes | |
6 | .long sys_fadvise64_64 | |
7 | .long sys_ni_syscall /* sys_vserver */ | |
8 | + .long sys_mq_open | |
9 | + .long sys_mq_unlink /* 275 */ | |
10 | + .long sys_mq_timedsend | |
11 | + .long sys_mq_timedreceive | |
12 | + .long sys_mq_notify | |
13 | + .long sys_mq_getattr | |
14 | + .long sys_mq_setattr | |
15 | ||
16 | syscall_table_size=(.-sys_call_table) | |
17 | diff -urN 2.6.0-test10-orig_2/CREDITS 2.6.0-test10-patched_2/CREDITS | |
18 | --- 2.6.0-test10-orig_2/CREDITS 2003-11-07 17:07:13.000000000 +0100 | |
19 | +++ 2.6.0-test10-patched_2/CREDITS 2003-11-21 16:48:21.000000000 +0100 | |
20 | @@ -289,6 +289,15 @@ | |
21 | S: Terni 05100 | |
22 | S: Italy | |
23 | ||
24 | +N: Krzysztof Benedyczak | |
25 | +E: golbi@mat.uni.torun.pl | |
26 | +W: http://www.mat.uni.torun.pl/~golbi | |
27 | +D: POSIX message queues fs (with M. Wronski) | |
28 | +S: ul. Podmiejska 52 | |
29 | +S: Radunica | |
30 | +S: 83-000 Pruszcz Gdanski | |
31 | +S: Poland | |
32 | + | |
33 | N: Randolph Bentson | |
34 | E: bentson@grieg.seaslug.org | |
35 | W: http://www.aa.net/~bentson/ | |
36 | @@ -3475,6 +3484,14 @@ | |
37 | S: Beaverton, OR 97005 | |
38 | S: USA | |
39 | ||
40 | +N: Michal Wronski | |
41 | +E: wrona@mat.uni.torun.pl | |
42 | +W: http://www.mat.uni.torun.pl/~wrona | |
43 | +D: POSIX message queues fs (with K. Benedyczak) | |
44 | +S: ul. Teczowa 23/12 | |
45 | +S: 80-680 Gdansk-Sobieszewo | |
46 | +S: Poland | |
47 | + | |
48 | N: Frank Xia | |
49 | E: qx@math.columbia.edu | |
50 | D: Xiafs filesystem [defunct] | |
51 | diff -urN 2.6.0-test10-orig_2/Documentation/filesystems/proc.txt 2.6.0-test10-patched_2/Documentation/filesystems/proc.txt | |
52 | --- 2.6.0-test10-orig_2/Documentation/filesystems/proc.txt 2003-11-07 17:07:13.000000000 +0100 | |
53 | +++ 2.6.0-test10-patched_2/Documentation/filesystems/proc.txt 2003-11-24 17:37:30.000000000 +0100 | |
54 | @@ -38,6 +38,7 @@ | |
55 | 2.8 /proc/sys/net/ipv4 - IPV4 settings | |
56 | 2.9 Appletalk | |
57 | 2.10 IPX | |
58 | + 2.11 /proc/sys/fs/mqueue - POSIX message queues filesystem | |
59 | ||
60 | ------------------------------------------------------------------------------ | |
61 | Preface | |
62 | @@ -1805,6 +1806,30 @@ | |
63 | gives the destination network, the router node (or Directly) and the network | |
64 | address of the router (or Connected) for internal networks. | |
65 | ||
66 | +2.11 /proc/sys/fs/mqueue - POSIX message queues filesystem | |
67 | +---------------------------------------------------------- | |
68 | + | |
69 | +The "mqueue" filesystem provides the necessary kernel features to enable the | |
70 | +creation of a user space library that implements the POSIX message queues | |
71 | +API (as noted by the MSG tag in the POSIX 1003.1-2001 version of the System | |
72 | +Interfaces specification.) | |
73 | + | |
74 | +The "mqueue" filesystem contains values for determining/setting the amount of | |
75 | +resources used by the file system. | |
76 | + | |
77 | +/proc/sys/fs/mqueue/queues_max is a read/write file for setting/getting the | |
78 | +maximum number of message queues allowed on the system. | |
79 | + | |
80 | +/proc/sys/fs/mqueue/msg_max is a read/write file for setting/getting the | |
81 | +maximum number of messages in a queue value. In fact it is the limiting value | |
82 | +for another (user) limit which is set in mq_open invocation. This attribute of | |
83 | +a queue must be less or equal then msg_max. | |
84 | + | |
85 | +/proc/sys/fs/mqueue/msgsize_max is a read/write file for setting/getting the | |
86 | +maximum message size value (it is every message queue's attribute set during | |
87 | +its creation). | |
88 | + | |
89 | + | |
90 | ------------------------------------------------------------------------------ | |
91 | Summary | |
92 | ------------------------------------------------------------------------------ | |
93 | diff -urN 2.6.0-test10-orig_2/fs/Kconfig 2.6.0-test10-patched_2/fs/Kconfig | |
94 | --- 2.6.0-test10-orig_2/fs/Kconfig 2003-11-07 17:07:13.000000000 +0100 | |
95 | +++ 2.6.0-test10-patched_2/fs/Kconfig 2003-11-21 16:59:14.000000000 +0100 | |
96 | @@ -893,6 +893,23 @@ | |
97 | To compile this as a module, choose M here: the module will be called | |
98 | ramfs. | |
99 | ||
100 | +config POSIX_MQUEUE_FS | |
101 | + bool "POSIX Message Queues" | |
102 | + ---help--- | |
103 | + POSIX variant of message queues is a part of IPC. In POSIX message | |
104 | + queues every message has a priority which decides about succession | |
105 | + of receiving it by a process. If you want to compile and run | |
106 | + programs written e.g. for Solaris with use of its POSIX message | |
107 | + queues (functions mq_*) say Y here. To use this feature you will | |
108 | + also need mqueue library, available from | |
109 | + <http://www.mat.uni.torun.pl/~wrona/posix_ipc/> | |
110 | + | |
111 | + POSIX message queues are visible as a filesystem called 'mqueue' | |
112 | + and can be mounted somewhere if you want to do filesystem | |
113 | + operations on message queues. | |
114 | + | |
115 | + If unsure, say N. | |
116 | + | |
117 | endmenu | |
118 | ||
119 | menu "Miscellaneous filesystems" | |
120 | diff -urN 2.6.0-test10-orig_2/include/asm-generic/siginfo.h 2.6.0-test10-patched_2/include/asm-generic/siginfo.h | |
121 | --- 2.6.0-test10-orig_2/include/asm-generic/siginfo.h 2003-11-07 17:07:13.000000000 +0100 | |
122 | +++ 2.6.0-test10-patched_2/include/asm-generic/siginfo.h 2003-11-21 16:48:21.000000000 +0100 | |
123 | @@ -118,6 +118,7 @@ | |
124 | #define __SI_FAULT (3 << 16) | |
125 | #define __SI_CHLD (4 << 16) | |
126 | #define __SI_RT (5 << 16) | |
127 | +#define __SI_MESGQ (6 << 16) | |
128 | #define __SI_CODE(T,N) ((T) | ((N) & 0xffff)) | |
129 | #else | |
130 | #define __SI_KILL 0 | |
131 | @@ -126,6 +127,7 @@ | |
132 | #define __SI_FAULT 0 | |
133 | #define __SI_CHLD 0 | |
134 | #define __SI_RT 0 | |
135 | +#define __SI_MESGQ 0 | |
136 | #define __SI_CODE(T,N) (N) | |
137 | #endif | |
138 | ||
139 | @@ -137,7 +139,7 @@ | |
140 | #define SI_KERNEL 0x80 /* sent by the kernel from somewhere */ | |
141 | #define SI_QUEUE -1 /* sent by sigqueue */ | |
142 | #define SI_TIMER __SI_CODE(__SI_TIMER,-2) /* sent by timer expiration */ | |
143 | -#define SI_MESGQ -3 /* sent by real time mesq state change */ | |
144 | +#define SI_MESGQ __SI_CODE(__SI_MESGQ,-3) /* sent by real time mesq state change */ | |
145 | #define SI_ASYNCIO -4 /* sent by AIO completion */ | |
146 | #define SI_SIGIO -5 /* sent by queued SIGIO */ | |
147 | #define SI_TKILL -6 /* sent by tkill system call */ | |
148 | diff -urN 2.6.0-test10-orig_2/include/asm-i386/unistd.h 2.6.0-test10-patched_2/include/asm-i386/unistd.h | |
149 | --- 2.6.0-test10-orig_2/include/asm-i386/unistd.h 2003-11-07 17:07:13.000000000 +0100 | |
150 | +++ 2.6.0-test10-patched_2/include/asm-i386/unistd.h 2003-11-21 16:48:21.000000000 +0100 | |
151 | @@ -279,8 +279,15 @@ | |
152 | #define __NR_utimes 271 | |
153 | #define __NR_fadvise64_64 272 | |
154 | #define __NR_vserver 273 | |
155 | - | |
156 | -#define NR_syscalls 274 | |
157 | +#define __NR_mq_open 274 | |
158 | +#define __NR_mq_unlink (__NR_mq_open+1) | |
159 | +#define __NR_mq_timedsend (__NR_mq_open+2) | |
160 | +#define __NR_mq_timedreceive (__NR_mq_open+3) | |
161 | +#define __NR_mq_notify (__NR_mq_open+4) | |
162 | +#define __NR_mq_getattr (__NR_mq_open+5) | |
163 | +#define __NR_mq_setattr (__NR_mq_open+6) | |
164 | + | |
165 | +#define NR_syscalls 281 | |
166 | ||
167 | /* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */ | |
168 | ||
169 | diff -urN 2.6.0-test10-orig_2/include/linux/mqueue.h 2.6.0-test10-patched_2/include/linux/mqueue.h | |
170 | --- 2.6.0-test10-orig_2/include/linux/mqueue.h 1970-01-01 01:00:00.000000000 +0100 | |
171 | +++ 2.6.0-test10-patched_2/include/linux/mqueue.h 2003-11-24 16:37:46.000000000 +0100 | |
172 | @@ -0,0 +1,64 @@ | |
173 | +/* Copyright (C) 2003 Krzysztof Benedyczak & Michal Wronski | |
174 | + | |
175 | + This program is free software; you can redistribute it and/or | |
176 | + modify it under the terms of the GNU Lesser General Public | |
177 | + License as published by the Free Software Foundation; either | |
178 | + version 2.1 of the License, or (at your option) any later version. | |
179 | + | |
180 | + It is distributed in the hope that it will be useful, | |
181 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
182 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
183 | + Lesser General Public License for more details. | |
184 | + | |
185 | + You should have received a copy of the GNU Lesser General Public | |
186 | + License along with this software; if not, write to the Free | |
187 | + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |
188 | + 02111-1307 USA. */ | |
189 | + | |
190 | +#ifndef _LINUX_MQUEUE_H | |
191 | +#define _LINUX_MQUEUE_H | |
192 | + | |
193 | +#define MQ_PRIO_MAX 32768 | |
194 | + | |
195 | +typedef int mqd_t; | |
196 | + | |
197 | +struct mq_attr { | |
198 | + long mq_flags; /* message queue flags */ | |
199 | + long mq_maxmsg; /* maximum number of messages */ | |
200 | + long mq_msgsize; /* maximum message size */ | |
201 | + long mq_curmsgs; /* number of messages currently queued */ | |
202 | +}; | |
203 | + | |
204 | +#ifdef __KERNEL__ | |
205 | +#include <linux/types.h> | |
206 | +#include <linux/time.h> | |
207 | +#include <linux/signal.h> | |
208 | +#include <linux/linkage.h> | |
209 | + | |
210 | +asmlinkage long sys_mq_open(const char __user *name, int oflag, mode_t mode, struct mq_attr __user *attr); | |
211 | +asmlinkage long sys_mq_unlink(const char __user *name); | |
212 | +asmlinkage long mq_timedsend(mqd_t mqdes, const char __user *msg_ptr, size_t msg_len, unsigned int msg_prio, const struct timespec __user *abs_timeout); | |
213 | +asmlinkage ssize_t mq_timedreceive(mqd_t mqdes, char __user *msg_ptr, size_t msg_len, unsigned int __user *msg_prio, const struct timespec __user *abs_timeout); | |
214 | +asmlinkage long mq_notify(mqd_t mqdes, const struct sigevent __user *notification); | |
215 | +asmlinkage long mq_getattr(mqd_t mqdes, struct mq_attr __user *mqstat); | |
216 | +asmlinkage long mq_setattr(mqd_t mqdes, const struct mq_attr __user *mqstat, struct mq_attr __user *omqstat); | |
217 | + | |
218 | +#else | |
219 | + | |
220 | +#include <signal.h> | |
221 | +#include <fcntl.h> | |
222 | +#include <time.h> | |
223 | + | |
224 | +mqd_t mq_open(const char *name, int oflag, /* mode_t mode, struct mq_attr *attr */ ...); | |
225 | +int mq_close(mqd_t mqdes); | |
226 | +int mq_unlink(const char *name); | |
227 | +int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned int msg_prio); | |
228 | +int mq_timedsend(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned int msg_prio, const struct timespec *abs_timeout); | |
229 | +ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio); | |
230 | +ssize_t mq_timedreceive(mqd_t mqdes, char *__restrict msg_ptr, size_t msg_len, unsigned int *__restrict msg_prio, const struct timespec *__restrict abs_timeout); | |
231 | +int mq_notify(mqd_t mqdes, const struct sigevent *notification); | |
232 | +int mq_getattr(mqd_t mqdes, struct mq_attr *mqstat); | |
233 | +int mq_setattr(mqd_t mqdes, const struct mq_attr *__restrict mqstat, struct mq_attr *__restrict omqstat); | |
234 | +#endif | |
235 | + | |
236 | +#endif | |
237 | diff -urN 2.6.0-test10-orig_2/ipc/Makefile 2.6.0-test10-patched_2/ipc/Makefile | |
238 | --- 2.6.0-test10-orig_2/ipc/Makefile 2003-11-07 17:07:13.000000000 +0100 | |
239 | +++ 2.6.0-test10-patched_2/ipc/Makefile 2003-11-21 16:48:21.000000000 +0100 | |
240 | @@ -5,3 +5,4 @@ | |
241 | obj-y := util.o | |
242 | ||
243 | obj-$(CONFIG_SYSVIPC) += msg.o sem.o shm.o | |
244 | +obj-$(CONFIG_POSIX_MQUEUE_FS) += mqueue.o | |
245 | diff -urN 2.6.0-test10-orig_2/ipc/mqueue.c 2.6.0-test10-patched_2/ipc/mqueue.c | |
246 | --- 2.6.0-test10-orig_2/ipc/mqueue.c 1970-01-01 01:00:00.000000000 +0100 | |
247 | +++ 2.6.0-test10-patched_2/ipc/mqueue.c 2003-11-24 16:37:46.000000000 +0100 | |
248 | @@ -0,0 +1,1260 @@ | |
249 | +/* | |
250 | + * POSIX message queues filesystem for Linux. | |
251 | + * | |
252 | + * Copyright (C) 2003 Krzysztof Benedyczak (golbi@mat.uni.torun.pl) | |
253 | + * Michal Wronski (wrona@mat.uni.torun.pl) | |
254 | + * | |
255 | + * Spinlocks: Mohamed Abbas (abbas.mohamed@intel.com) | |
256 | + * | |
257 | + * This file is released under the GPL. | |
258 | + */ | |
259 | + | |
260 | +#include <linux/mqueue.h> | |
261 | +#include <linux/msg.h> | |
262 | +#include <linux/list.h> | |
263 | +#include <linux/poll.h> | |
264 | +#include <linux/init.h> | |
265 | +#include <linux/pagemap.h> | |
266 | +#include <linux/file.h> | |
267 | +#include <linux/mount.h> | |
268 | +#include <linux/namei.h> | |
269 | +#include <linux/sysctl.h> | |
270 | +#include "util.h" | |
271 | + | |
272 | +#define MQUEUE_MAGIC 0x19800202 | |
273 | +#define DIRENT_SIZE 20 | |
274 | +#define FILENT_SIZE 60 | |
275 | +#define SEND 0 | |
276 | +#define RECV 1 | |
277 | + | |
278 | +#define ERRNO_OK_SIGNAL 0 | |
279 | +#define ERRNO_OK_THREAD 1 | |
280 | +#define ERRNO_REMOVE_THREAD 2 | |
281 | + | |
282 | +/* used by sysctl */ | |
283 | +#define FS_MQUEUE 1 | |
284 | +#define CTL_QUEUESMAX 2 | |
285 | +#define CTL_MSGMAX 3 | |
286 | +#define CTL_MSGSIZEMAX 4 | |
287 | + | |
288 | +/* default values */ | |
289 | +#define DFLT_QUEUESMAX 64 /* max number of message queues */ | |
290 | +#define DFLT_MSGMAX 40 /* max number of messages in each queue */ | |
291 | +#define DFLT_MSGSIZEMAX 16384 /* max message size */ | |
292 | + | |
293 | +struct ext_wait_queue { /* queue of sleeping tasks */ | |
294 | + struct task_struct *task; | |
295 | + struct list_head list; | |
296 | +}; | |
297 | + | |
298 | +struct mqueue_inode_info { | |
299 | + struct mq_attr attr; | |
300 | + struct msg_msg **messages; | |
301 | + | |
302 | + struct sigevent notify; | |
303 | + pid_t notify_task; | |
304 | + pid_t notify_owner; /* == tgid of notify_task */ | |
305 | + | |
306 | + /* for tasks waiting for free space or message (respectively) */ | |
307 | + /* this is left mainly because of poll */ | |
308 | + wait_queue_head_t wait_q[2]; | |
309 | + /* avoids extra invocations of wake_up */ | |
310 | + wait_queue_head_t wait_q2[2]; | |
311 | + struct ext_wait_queue e_wait_q[2]; /* 0=free space 1=message */ | |
312 | + | |
313 | + __u32 qsize; /* size of queue in memory (msgs & struct) */ | |
314 | + spinlock_t lock; | |
315 | + struct inode vfs_inode; | |
316 | +}; | |
317 | + | |
318 | +static struct inode_operations mqueue_dir_inode_operations; | |
319 | +static struct file_operations mqueue_file_operations; | |
320 | +static struct super_operations mqueue_super_ops; | |
321 | +static inline void remove_notification(struct mqueue_inode_info *info); | |
322 | + | |
323 | +static spinlock_t mq_lock; | |
324 | +static kmem_cache_t *mqueue_inode_cachep; | |
325 | +static struct vfsmount *mqueue_mnt; | |
326 | + | |
327 | +static unsigned int queues_count; | |
328 | +static unsigned int queues_max = DFLT_QUEUESMAX; | |
329 | +static unsigned int msg_max = DFLT_MSGMAX; | |
330 | +static unsigned int msgsize_max = DFLT_MSGSIZEMAX; | |
331 | + | |
332 | +static struct ctl_table_header * mq_sysctl_table; | |
333 | + | |
334 | + | |
335 | +static inline struct mqueue_inode_info *MQUEUE_I(struct inode *ino) | |
336 | +{ | |
337 | + return list_entry(ino, struct mqueue_inode_info, vfs_inode); | |
338 | +} | |
339 | + | |
340 | +static struct inode *mqueue_get_inode(struct super_block *sb, int mode) | |
341 | +{ | |
342 | + struct inode *inode; | |
343 | + struct mqueue_inode_info *ino_extra; | |
344 | + struct msg_msg **msgs = NULL; | |
345 | + int size = msg_max; | |
346 | + | |
347 | + if ((mode & S_IFMT) == S_IFREG) { | |
348 | + msgs = (struct msg_msg **)kmalloc(size * sizeof(struct msg_msg *), GFP_KERNEL); | |
349 | + if (!msgs) | |
350 | + return NULL; | |
351 | + } | |
352 | + | |
353 | + inode = new_inode(sb); | |
354 | + if (inode) { | |
355 | + inode->i_mode = mode; | |
356 | + inode->i_uid = current->fsuid; | |
357 | + inode->i_gid = current->fsgid; | |
358 | + inode->i_blksize = PAGE_CACHE_SIZE; | |
359 | + inode->i_blocks = 0; | |
360 | + inode->i_mtime = inode->i_ctime = inode->i_atime = CURRENT_TIME; | |
361 | + | |
362 | + if ((mode & S_IFMT) == S_IFREG) { | |
363 | + inode->i_fop = &mqueue_file_operations; | |
364 | + inode->i_size = FILENT_SIZE; | |
365 | + /* mqueue specific info */ | |
366 | + ino_extra = MQUEUE_I(inode); | |
367 | + spin_lock_init(&(ino_extra->lock)); | |
368 | + init_waitqueue_head((&(ino_extra->wait_q[0]))); | |
369 | + init_waitqueue_head((&(ino_extra->wait_q[1]))); | |
370 | + init_waitqueue_head((&(ino_extra->wait_q2[0]))); | |
371 | + init_waitqueue_head((&(ino_extra->wait_q2[1]))); | |
372 | + INIT_LIST_HEAD(&(ino_extra->e_wait_q[0].list)); | |
373 | + INIT_LIST_HEAD(&(ino_extra->e_wait_q[1].list)); | |
374 | + ino_extra->notify_task = 0; | |
375 | + ino_extra->notify_owner = 0; | |
376 | + ino_extra->notify.sigev_signo = 0; | |
377 | + ino_extra->notify.sigev_notify = SIGEV_NONE; | |
378 | + ino_extra->qsize = sizeof(struct mqueue_inode_info); | |
379 | + ino_extra->attr.mq_curmsgs = 0; | |
380 | + /* fill up with defaults */ | |
381 | + ino_extra->attr.mq_maxmsg = size; | |
382 | + ino_extra->attr.mq_msgsize = msgsize_max; | |
383 | + ino_extra->messages = msgs; | |
384 | + } else if ((mode & S_IFMT) == S_IFDIR) { | |
385 | + inode->i_nlink++; | |
386 | + /* Some things misbehave if size == 0 on a directory */ | |
387 | + inode->i_size = 2 * DIRENT_SIZE; | |
388 | + inode->i_op = &mqueue_dir_inode_operations; | |
389 | + inode->i_fop = &simple_dir_operations; | |
390 | + } | |
391 | + } else if (msgs) | |
392 | + kfree(msgs); | |
393 | + return inode; | |
394 | +} | |
395 | + | |
396 | + | |
397 | +static int mqueue_fill_super(struct super_block *sb, void *data, int silent) | |
398 | +{ | |
399 | + struct inode *inode; | |
400 | + | |
401 | + sb->s_blocksize = PAGE_CACHE_SIZE; | |
402 | + sb->s_blocksize_bits = PAGE_CACHE_SHIFT; | |
403 | + sb->s_magic = MQUEUE_MAGIC; | |
404 | + sb->s_op = &mqueue_super_ops; | |
405 | + | |
406 | + inode = mqueue_get_inode(sb, S_IFDIR | S_IRWXUGO); | |
407 | + if (!inode) | |
408 | + return -ENOMEM; | |
409 | + | |
410 | + sb->s_root = d_alloc_root(inode); | |
411 | + if (!sb->s_root) { | |
412 | + iput(inode); | |
413 | + return -ENOMEM; | |
414 | + } | |
415 | + | |
416 | + return 0; | |
417 | +} | |
418 | + | |
419 | +static struct super_block *mqueue_get_sb(struct file_system_type *fs_type, | |
420 | + int flags, const char *dev_name, | |
421 | + void *data) | |
422 | +{ | |
423 | + return get_sb_single(fs_type, flags, data, mqueue_fill_super); | |
424 | +} | |
425 | + | |
426 | +static void init_once(void *foo, kmem_cache_t * cachep, unsigned long flags) | |
427 | +{ | |
428 | + struct mqueue_inode_info *p = (struct mqueue_inode_info *) foo; | |
429 | + | |
430 | + if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) == SLAB_CTOR_CONSTRUCTOR) | |
431 | + inode_init_once(&p->vfs_inode); | |
432 | +} | |
433 | + | |
434 | +static struct inode *mqueue_alloc_inode(struct super_block *sb) | |
435 | +{ | |
436 | + struct mqueue_inode_info *ei; | |
437 | + | |
438 | + ei = (struct mqueue_inode_info *)kmem_cache_alloc(mqueue_inode_cachep, SLAB_KERNEL); | |
439 | + if (!ei) | |
440 | + return NULL; | |
441 | + return &ei->vfs_inode; | |
442 | +} | |
443 | + | |
444 | +static void mqueue_destroy_inode(struct inode *inode) | |
445 | +{ | |
446 | + kmem_cache_free(mqueue_inode_cachep, MQUEUE_I(inode)); | |
447 | +} | |
448 | + | |
449 | +static void mqueue_delete_inode(struct inode *ino) | |
450 | +{ | |
451 | + struct mqueue_inode_info *info; | |
452 | + int i; | |
453 | + | |
454 | + if ((ino->i_mode & S_IFMT) == S_IFDIR) { | |
455 | + clear_inode(ino); | |
456 | + return; | |
457 | + } | |
458 | + info = MQUEUE_I(ino); | |
459 | + spin_lock(&info->lock); | |
460 | + for (i = 0; i < info->attr.mq_curmsgs; i++) | |
461 | + free_msg(info->messages[i]); | |
462 | + kfree(info->messages); | |
463 | + spin_unlock(&info->lock); | |
464 | + | |
465 | + clear_inode(ino); | |
466 | + | |
467 | + spin_lock(&mq_lock); | |
468 | + queues_count--; | |
469 | + spin_unlock(&mq_lock); | |
470 | +} | |
471 | + | |
472 | +static int mqueue_unlink(struct inode *dir, struct dentry *dent) | |
473 | +{ | |
474 | + struct inode *inode = dent->d_inode; | |
475 | + dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME; | |
476 | + dir->i_size -= DIRENT_SIZE; | |
477 | + inode->i_nlink--; | |
478 | + dput(dent); | |
479 | + return 0; | |
480 | +} | |
481 | + | |
482 | +static struct dentry *mqueue_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd) | |
483 | +{ | |
484 | + if (dentry->d_name.len > NAME_MAX) | |
485 | + return ERR_PTR(-ENAMETOOLONG); | |
486 | + | |
487 | + d_add(dentry, NULL); | |
488 | + return NULL; | |
489 | +} | |
490 | + | |
491 | +static int mqueue_create(struct inode *dir, struct dentry *dent, int mode, struct nameidata *nd) | |
492 | +{ | |
493 | + struct inode *ino; | |
494 | + int error; | |
495 | + | |
496 | + spin_lock(&mq_lock); | |
497 | + if (queues_count >= queues_max) { | |
498 | + error = -ENOSPC; | |
499 | + goto out_lock; | |
500 | + } | |
501 | + queues_count++; | |
502 | + spin_unlock(&mq_lock); | |
503 | + | |
504 | + ino = mqueue_get_inode(dir->i_sb, mode); | |
505 | + if (!ino) { | |
506 | + error = -ENOMEM; | |
507 | + spin_lock(&mq_lock); | |
508 | + queues_count--; | |
509 | + goto out_lock; | |
510 | + } | |
511 | + | |
512 | + dir->i_size += DIRENT_SIZE; | |
513 | + dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME; | |
514 | + | |
515 | + d_instantiate(dent, ino); | |
516 | + dget(dent); | |
517 | + return 0; | |
518 | +out_lock: | |
519 | + spin_unlock(&mq_lock); | |
520 | + return error; | |
521 | +} | |
522 | + | |
523 | +/* | |
524 | +* This is routine for system read from queue file. | |
525 | +* To avoid mess with doing here some sort of mq_receive we allow | |
526 | +* to read only queue size & notification info (the only values | |
527 | +* that are interesting from user point of view and aren't accessible | |
528 | +* through std routines) | |
529 | +*/ | |
530 | +static ssize_t mqueue_read_file(struct file *filp, char __user *data, | |
531 | + size_t count, loff_t * off) | |
532 | +{ | |
533 | + size_t pos; | |
534 | + ssize_t retval; | |
535 | + char buffer[FILENT_SIZE + 1]; | |
536 | + struct mqueue_inode_info *info = MQUEUE_I(filp->f_dentry->d_inode); | |
537 | + | |
538 | + pos = *off; | |
539 | + if ((ssize_t) count < 0) | |
540 | + return -EINVAL; | |
541 | + if (!count) | |
542 | + return 0; | |
543 | + if (pos >= FILENT_SIZE) | |
544 | + return 0; | |
545 | + if (pos + count >= FILENT_SIZE) | |
546 | + count = FILENT_SIZE - pos - 1; | |
547 | + | |
548 | + if (!access_ok(VERIFY_WRITE, data, count)) | |
549 | + return -EFAULT; | |
550 | + | |
551 | + snprintf(buffer, FILENT_SIZE + 1, | |
552 | + "QSIZE:%-10u NOTIFY:%-5d SIGNO:%-5d NOTIFY_PID:%-6d\n", | |
553 | + info->qsize, info->notify.sigev_notify, | |
554 | + info->notify.sigev_signo, info->notify_owner); | |
555 | + | |
556 | + retval = FILENT_SIZE - *off; | |
557 | + if (copy_to_user(data, buffer + pos, retval)) { | |
558 | + retval = (ssize_t)-EFAULT; | |
559 | + goto out; | |
560 | + } | |
561 | + *off += retval; | |
562 | + filp->f_dentry->d_inode->i_atime = filp->f_dentry->d_inode->i_ctime = CURRENT_TIME; | |
563 | +out: | |
564 | + return retval; | |
565 | +} | |
566 | + | |
567 | + | |
568 | +static int mqueue_release_file(struct inode *ino, struct file *filp) | |
569 | +{ | |
570 | + struct mqueue_inode_info *info = MQUEUE_I(ino); | |
571 | + | |
572 | + spin_lock(&info->lock); | |
573 | + if (current->tgid == info->notify_owner) | |
574 | + remove_notification(info); | |
575 | + | |
576 | + spin_unlock(&info->lock); | |
577 | + return 0; | |
578 | +} | |
579 | + | |
580 | + | |
581 | +static unsigned int mqueue_poll_file(struct file *filp, struct poll_table_struct *poll_tab) | |
582 | +{ | |
583 | + struct mqueue_inode_info *info = MQUEUE_I(filp->f_dentry->d_inode); | |
584 | + int retval = 0; | |
585 | + | |
586 | + poll_wait(filp, &info->wait_q[0], poll_tab); | |
587 | + poll_wait(filp, &info->wait_q[1], poll_tab); | |
588 | + | |
589 | + spin_lock(&info->lock); | |
590 | + if (info->attr.mq_curmsgs) | |
591 | + retval = POLLIN | POLLRDNORM; | |
592 | + | |
593 | + if (info->attr.mq_curmsgs < info->attr.mq_maxmsg) | |
594 | + retval |= POLLOUT | POLLWRNORM; | |
595 | + spin_unlock(&info->lock); | |
596 | + | |
597 | + return retval; | |
598 | +} | |
599 | + | |
600 | +/* | |
601 | +* This cut&paste version of wait_event() without event checking & with | |
602 | +* exclusive adding to queue. | |
603 | +*/ | |
604 | +void inline wait_exclusive(wait_queue_head_t * wq, | |
605 | + struct mqueue_inode_info *i) | |
606 | +{ | |
607 | + wait_queue_t wait; | |
608 | + init_waitqueue_entry(&wait, current); | |
609 | + | |
610 | + add_wait_queue_exclusive(wq, &wait); | |
611 | + set_current_state(TASK_UNINTERRUPTIBLE); | |
612 | + | |
613 | + spin_unlock(&i->lock); | |
614 | + schedule(); | |
615 | + spin_lock(&i->lock); | |
616 | + | |
617 | + current->state = TASK_RUNNING; | |
618 | + remove_wait_queue(wq, &wait); | |
619 | +} | |
620 | + | |
621 | +/* Removes from info->e_wait_q[sr] current task */ | |
622 | +static void wq_remove(struct mqueue_inode_info *info, int sr) | |
623 | +{ | |
624 | + struct ext_wait_queue *ptr; | |
625 | + | |
626 | + if (!list_empty(&(info->e_wait_q[sr].list))) | |
627 | + list_for_each_entry(ptr, &(info->e_wait_q[sr].list), list) { | |
628 | + if (ptr->task == current) { | |
629 | + list_del(&(ptr->list)); | |
630 | + kfree(ptr); | |
631 | + break; | |
632 | + } | |
633 | + } | |
634 | +} | |
635 | + | |
636 | +/* adds current to info->e_wait_q[sr] before element with smaller prio */ | |
637 | +static inline void wq_add(struct mqueue_inode_info *info, int sr, | |
638 | + struct ext_wait_queue *tmp) | |
639 | +{ | |
640 | + struct ext_wait_queue *ptr; | |
641 | + | |
642 | + tmp->task = current; | |
643 | + | |
644 | + if (list_empty(&info->e_wait_q[sr].list)) | |
645 | + list_add(&tmp->list, &info->e_wait_q[sr].list); | |
646 | + else { | |
647 | + list_for_each_entry(ptr, &info->e_wait_q[sr].list, list) | |
648 | + if (ptr->task->static_prio <= current->static_prio) { | |
649 | + /* we add before ptr element */ | |
650 | + __list_add(&tmp->list, ptr->list.prev, &ptr->list); | |
651 | + return; | |
652 | + } | |
653 | + /* we add on tail */ | |
654 | + list_add_tail(&tmp->list, &info->e_wait_q[sr].list); | |
655 | + } | |
656 | + return; | |
657 | +} | |
658 | + | |
659 | +/* removes from info->e_wait_q[sr] current task. | |
660 | + * Only for wq_sleep(): as we are here current must be one | |
661 | + * before-first (last) (meaning first in order as our 'queue' is inversed) */ | |
662 | +static inline void wq_remove_last(struct mqueue_inode_info *info, int sr) | |
663 | +{ | |
664 | + struct ext_wait_queue *tmp = list_entry(info->e_wait_q[sr].list.prev, struct ext_wait_queue, list); | |
665 | + list_del(&(tmp->list)); | |
666 | + kfree(tmp); | |
667 | +} | |
668 | + | |
669 | +/* | |
670 | + * puts current task to sleep | |
671 | + * sr: SEND or RECV | |
672 | + */ | |
673 | +static int wq_sleep(struct mqueue_inode_info *info, int sr, | |
674 | + signed long timeout, struct ext_wait_queue *wq_ptr) | |
675 | +{ | |
676 | + wait_queue_t __wait; | |
677 | + long error; | |
678 | + | |
679 | + wq_add(info, sr, wq_ptr); | |
680 | + | |
681 | + init_waitqueue_entry(&__wait, current); | |
682 | + | |
683 | + for (;;) { | |
684 | + set_current_state(TASK_INTERRUPTIBLE); | |
685 | + if ((current == (list_entry(info->e_wait_q[sr].list.prev, struct ext_wait_queue, list))->task) | |
686 | + && ((info->attr.mq_curmsgs > 0 && sr == RECV) | |
687 | + || (info->attr.mq_curmsgs < info->attr.mq_maxmsg && sr == SEND))) | |
688 | + break; | |
689 | + | |
690 | + if (signal_pending(current)) { | |
691 | + current->state = TASK_RUNNING; | |
692 | + wq_remove(info, sr); | |
693 | + return -EINTR; | |
694 | + } | |
695 | + | |
696 | + spin_unlock(&info->lock); | |
697 | + error = schedule_timeout(timeout); | |
698 | + spin_lock(&info->lock); | |
699 | + | |
700 | + if ((!error) && (!signal_pending(current))) { | |
701 | + wq_remove(info, sr); | |
702 | + return -ETIMEDOUT; | |
703 | + } | |
704 | + } | |
705 | + current->state = TASK_RUNNING; | |
706 | + wq_remove_last(info, sr); | |
707 | + | |
708 | + return 0; | |
709 | +} | |
710 | + | |
711 | +/* wakes up sleeping task */ | |
712 | +static void wq_wakeup(struct mqueue_inode_info *info, int sr) | |
713 | +{ | |
714 | + if (sr == SEND) { | |
715 | + /* We can't invoke wake_up for tasks waiting for free space | |
716 | + * if there is less then MAXMSG-1 messages - then wake_up was | |
717 | + * invoked previously (and finished) but mq_sleep() of proper | |
718 | + * (only one) task didn't start to continue running yet, | |
719 | + * thus we must wait until this task receives IT'S message | |
720 | + */ | |
721 | + if ((info->attr.mq_curmsgs < info->attr.mq_maxmsg - 1) | |
722 | + && (!list_empty(&info->e_wait_q[sr].list))) | |
723 | + wait_exclusive(&(info->wait_q2[sr]), info); | |
724 | + } else { | |
725 | + /* As above but for tasks waiting for new message */ | |
726 | + if ((info->attr.mq_curmsgs > 1) && (!list_empty(&info->e_wait_q[sr].list))) | |
727 | + wait_exclusive(&(info->wait_q2[sr]), info); | |
728 | + } | |
729 | + /* We can wake up now - either all are sleeping or queue is empty. */ | |
730 | + if (!list_empty(&info->e_wait_q[sr].list)) | |
731 | + wake_up_process((list_entry(info->e_wait_q[sr].list.prev, struct ext_wait_queue, list))->task); | |
732 | + /* for poll */ | |
733 | + wake_up_interruptible(&(info->wait_q[sr])); | |
734 | +} | |
735 | + | |
736 | + | |
737 | +/* Auxiliary functions to manipulate messages' list */ | |
738 | +static inline void msg_insert(struct msg_msg *ptr, struct mqueue_inode_info *info) | |
739 | +{ | |
740 | + int k; | |
741 | + | |
742 | + k = (info->attr.mq_curmsgs)-1; | |
743 | + while ((k >= 0) && (info->messages[k]->m_type >= ptr->m_type)) { | |
744 | + info->messages[k + 1] = info->messages[k]; | |
745 | + k--; | |
746 | + } | |
747 | + (info->attr.mq_curmsgs)++; | |
748 | + info->messages[k + 1] = ptr; | |
749 | +} | |
750 | + | |
751 | +static inline struct msg_msg *msg_get(struct mqueue_inode_info *info) | |
752 | +{ | |
753 | + return info->messages[--(info->attr.mq_curmsgs)]; | |
754 | +} | |
755 | + | |
756 | +/* | |
757 | + * The next function is only to split too long sys_mq_timedsend | |
758 | + */ | |
759 | +static inline void __do_notify(struct mqueue_inode_info *info) | |
760 | +{ | |
761 | + struct siginfo sig_i; | |
762 | + struct task_struct *p; | |
763 | + | |
764 | + /* notification | |
765 | + * invoked when there is registered process and there isn't process | |
766 | + * waiting synchronously for message AND state of queue changed from | |
767 | + * empty to not empty */ | |
768 | + if ((info->notify.sigev_notify != SIGEV_NONE) && list_empty(&info->e_wait_q[RECV].list) | |
769 | + && info->attr.mq_curmsgs == 1) { | |
770 | + | |
771 | + sig_i.si_signo = info->notify.sigev_signo; | |
772 | + sig_i.si_errno = ERRNO_OK_SIGNAL; | |
773 | + sig_i.si_code = SI_MESGQ; | |
774 | + sig_i.si_value = info->notify.sigev_value; | |
775 | + sig_i.si_pid = current->tgid; | |
776 | + sig_i.si_uid = current->uid; | |
777 | + | |
778 | + /* sends signal */ | |
779 | + if (info->notify.sigev_notify == SIGEV_SIGNAL) { | |
780 | + kill_proc_info(info->notify.sigev_signo, | |
781 | + &sig_i, info->notify_task); | |
782 | + } else if (info->notify.sigev_notify == SIGEV_THREAD || | |
783 | + info->notify.sigev_notify == SIGEV_THREAD_ID) { | |
784 | + sig_i.si_errno = ERRNO_OK_THREAD; | |
785 | + read_lock(&tasklist_lock); | |
786 | + p = find_task_by_pid(info->notify_task); | |
787 | + if (p && (p->tgid == info->notify_owner)) | |
788 | + send_sig_info(info->notify.sigev_signo, &sig_i, p); | |
789 | + read_unlock(&tasklist_lock); | |
790 | + } | |
791 | + /* after notification unregisters process */ | |
792 | + info->notify_task = 0; | |
793 | + info->notify_owner = 0; | |
794 | + info->notify.sigev_signo = 0; | |
795 | + info->notify.sigev_notify = SIGEV_NONE; | |
796 | + } | |
797 | +} | |
798 | + | |
799 | +static inline long prepare_timeout(const struct timespec __user *arg) | |
800 | +{ | |
801 | + struct timespec ts, nowts; | |
802 | + long timeout; | |
803 | + | |
804 | + if (arg) { | |
805 | + if (copy_from_user(&ts, arg, sizeof(struct timespec))) | |
806 | + return -EFAULT; | |
807 | + | |
808 | + if (ts.tv_nsec < 0 || ts.tv_sec < 0 | |
809 | + || ts.tv_nsec >= NSEC_PER_SEC) | |
810 | + return -EINVAL; | |
811 | + nowts = CURRENT_TIME; | |
812 | + /* first subtract as jiffies can't be too big */ | |
813 | + ts.tv_sec -= nowts.tv_sec; | |
814 | + if (ts.tv_nsec < nowts.tv_nsec) { | |
815 | + ts.tv_nsec += NSEC_PER_SEC; | |
816 | + ts.tv_sec--; | |
817 | + } | |
818 | + ts.tv_nsec -= nowts.tv_nsec; | |
819 | + if (ts.tv_sec < 0) | |
820 | + return 0; | |
821 | + | |
822 | + timeout = timespec_to_jiffies(&ts) + 1; | |
823 | + } else | |
824 | + return MAX_SCHEDULE_TIMEOUT; | |
825 | + | |
826 | + return timeout; | |
827 | +} | |
828 | + | |
829 | + | |
830 | +static inline void remove_notification(struct mqueue_inode_info *info) | |
831 | +{ | |
832 | + struct siginfo sig_i; | |
833 | + struct task_struct *p; | |
834 | + | |
835 | + if (info->notify.sigev_notify == SIGEV_THREAD) { | |
836 | + /* cancel waiting thread */ | |
837 | + sig_i.si_signo = info->notify.sigev_signo; | |
838 | + sig_i.si_errno = ERRNO_REMOVE_THREAD; | |
839 | + sig_i.si_code = SI_MESGQ; | |
840 | + sig_i.si_value = info->notify.sigev_value; | |
841 | + sig_i.si_pid = current->tgid; | |
842 | + sig_i.si_uid = current->uid; | |
843 | + | |
844 | + read_lock(&tasklist_lock); | |
845 | + p = find_task_by_pid(info->notify_task); | |
846 | + | |
847 | + if (p && (p->tgid == info->notify_owner)) | |
848 | + send_sig_info(info->notify.sigev_signo, &sig_i, p); | |
849 | + read_unlock(&tasklist_lock); | |
850 | + } | |
851 | + info->notify_task = 0; | |
852 | + info->notify_owner = 0; | |
853 | + info->notify.sigev_signo = 0; | |
854 | + info->notify.sigev_notify = SIGEV_NONE; | |
855 | +} | |
856 | + | |
857 | +/* | |
858 | + * Invoked when creating a new queue via sys_mq_open | |
859 | + */ | |
860 | +static struct file *do_create(struct dentry *dir, struct dentry *dentry, | |
861 | + int oflag, mode_t mode, struct mq_attr __user *u_attr) | |
862 | +{ | |
863 | + struct file *filp; | |
864 | + struct inode *ino; | |
865 | + struct mqueue_inode_info *info; | |
866 | + struct msg_msg **msgs = NULL; | |
867 | + struct mq_attr attr; | |
868 | + int ret; | |
869 | + | |
870 | + if (u_attr != NULL) { | |
871 | + if (copy_from_user(&attr, u_attr, sizeof(struct mq_attr))) | |
872 | + return ERR_PTR(-EFAULT); | |
873 | + | |
874 | + if (attr.mq_maxmsg <= 0 || attr.mq_msgsize <= 0 | |
875 | + || attr.mq_maxmsg > msg_max || attr.mq_msgsize > msgsize_max) | |
876 | + return ERR_PTR(-EINVAL); | |
877 | + msgs = (struct msg_msg **)kmalloc(attr.mq_maxmsg * sizeof(struct msg_msg *), GFP_KERNEL); | |
878 | + if (!msgs) | |
879 | + return ERR_PTR(-ENOMEM); | |
880 | + } | |
881 | + | |
882 | + ret = vfs_create(dir->d_inode, dentry, mode, NULL); | |
883 | + if (ret) { | |
884 | + if (msgs) | |
885 | + kfree(msgs); | |
886 | + return ERR_PTR(ret); | |
887 | + } | |
888 | + | |
889 | + ino = dentry->d_inode; | |
890 | + info = MQUEUE_I(ino); | |
891 | + if (u_attr != NULL) { | |
892 | + info->attr.mq_maxmsg = attr.mq_maxmsg; | |
893 | + info->attr.mq_msgsize = attr.mq_msgsize; | |
894 | + kfree(info->messages); | |
895 | + info->messages = msgs; | |
896 | + } | |
897 | + | |
898 | + filp = dentry_open(dentry, mqueue_mnt, oflag); | |
899 | + if (!IS_ERR(filp)) | |
900 | + dget(dentry); | |
901 | + | |
902 | + return filp; | |
903 | +} | |
904 | + | |
905 | +/* opens existing queue */ | |
906 | +static struct file *do_open(struct dentry *dentry, int oflag) | |
907 | +{ | |
908 | + struct file *filp; | |
909 | + static int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE, MAY_READ | MAY_WRITE }; | |
910 | + | |
911 | + if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY)) | |
912 | + return ERR_PTR(-EINVAL); | |
913 | + | |
914 | + if (permission(dentry->d_inode, oflag2acc[oflag & O_ACCMODE], NULL)) | |
915 | + return ERR_PTR(-EACCES); | |
916 | + | |
917 | + filp = dentry_open(dentry, mqueue_mnt, oflag); | |
918 | + | |
919 | + if (!IS_ERR(filp)) | |
920 | + dget(dentry); | |
921 | + | |
922 | + return filp; | |
923 | +} | |
924 | + | |
925 | +asmlinkage long sys_mq_open(const char __user *u_name, int oflag, mode_t mode, | |
926 | + struct mq_attr __user *attr) | |
927 | +{ | |
928 | + struct dentry *dentry; | |
929 | + struct file *filp; | |
930 | + char *name; | |
931 | + int fd, error; | |
932 | + | |
933 | + if (IS_ERR(name = getname(u_name))) | |
934 | + return PTR_ERR(name); | |
935 | + | |
936 | + fd = get_unused_fd(); | |
937 | + if (fd < 0) | |
938 | + goto out_putname; | |
939 | + | |
940 | + down(&mqueue_mnt->mnt_root->d_inode->i_sem); | |
941 | + dentry = lookup_one_len(name, mqueue_mnt->mnt_root, strlen(name)); | |
942 | + if (IS_ERR(dentry)) { | |
943 | + error = PTR_ERR(dentry); | |
944 | + goto out_err; | |
945 | + } | |
946 | + mntget(mqueue_mnt); | |
947 | + | |
948 | + if (oflag & O_CREAT) { | |
949 | + if (dentry->d_inode) { /* entry already exists */ | |
950 | + filp = (oflag & O_EXCL) ? ERR_PTR(-EEXIST) : do_open(dentry, oflag); | |
951 | + } else { | |
952 | + filp = do_create(mqueue_mnt->mnt_root, dentry, oflag, mode, attr); | |
953 | + } | |
954 | + } else | |
955 | + filp = (dentry->d_inode) ? do_open(dentry, oflag) : ERR_PTR(-ENOENT); | |
956 | + | |
957 | + dput(dentry); | |
958 | + | |
959 | + if (IS_ERR(filp)) { | |
960 | + error = PTR_ERR(filp); | |
961 | + goto out_putfd; | |
962 | + } | |
963 | + | |
964 | + fd_install(fd, filp); | |
965 | + goto out_upsem; | |
966 | + | |
967 | +out_putfd: | |
968 | + mntput(mqueue_mnt); | |
969 | + put_unused_fd(fd); | |
970 | +out_err: | |
971 | + fd = error; | |
972 | +out_upsem: | |
973 | + up(&mqueue_mnt->mnt_root->d_inode->i_sem); | |
974 | +out_putname: | |
975 | + putname(name); | |
976 | + return fd; | |
977 | +} | |
978 | + | |
979 | + | |
980 | +asmlinkage long sys_mq_unlink(const char __user *u_name) | |
981 | +{ | |
982 | + int err; | |
983 | + char *name; | |
984 | + struct dentry *dentry; | |
985 | + struct inode *ino = NULL; | |
986 | + | |
987 | + name = getname(u_name); | |
988 | + if (IS_ERR(name)) | |
989 | + return PTR_ERR(name); | |
990 | + | |
991 | + down(&mqueue_mnt->mnt_root->d_inode->i_sem); | |
992 | + dentry = lookup_one_len(name, mqueue_mnt->mnt_root, strlen(name)); | |
993 | + if (IS_ERR(dentry)) { | |
994 | + err = PTR_ERR(dentry); | |
995 | + goto out_unlock; | |
996 | + } | |
997 | + | |
998 | + if (!dentry->d_inode) { | |
999 | + err = -ENOENT; | |
1000 | + goto out_unlock; | |
1001 | + } | |
1002 | + | |
1003 | + if (permission(dentry->d_inode, MAY_WRITE, NULL)) { | |
1004 | + err = -EACCES; | |
1005 | + goto out_err; | |
1006 | + } | |
1007 | + ino = dentry->d_inode; | |
1008 | + if (ino) | |
1009 | + atomic_inc(&ino->i_count); | |
1010 | + | |
1011 | + err = vfs_unlink(dentry->d_parent->d_inode, dentry); | |
1012 | +out_err: | |
1013 | + dput(dentry); | |
1014 | + | |
1015 | +out_unlock: | |
1016 | + up(&mqueue_mnt->mnt_root->d_inode->i_sem); | |
1017 | + putname(name); | |
1018 | + if (ino) | |
1019 | + iput(ino); | |
1020 | + | |
1021 | + return err; | |
1022 | +} | |
1023 | + | |
1024 | + | |
1025 | +static long do_mq_timedsend(mqd_t mqdes, const char __user *u_msg_ptr, | |
1026 | + size_t msg_len, unsigned int msg_prio, const long timeout) | |
1027 | +{ | |
1028 | + struct file *filp; | |
1029 | + struct inode *ino; | |
1030 | + struct ext_wait_queue *wq_ptr; | |
1031 | + struct msg_msg *msg_ptr; | |
1032 | + int ret; | |
1033 | + struct mqueue_inode_info *info = MQUEUE_I(ino); | |
1034 | + | |
1035 | + ret = -EBADF; | |
1036 | + filp = fget(mqdes); | |
1037 | + if (!filp) | |
1038 | + goto out; | |
1039 | + | |
1040 | + ino = filp->f_dentry->d_inode; | |
1041 | + if (ino->i_sb->s_magic != MQUEUE_MAGIC) | |
1042 | + goto out_fput; | |
1043 | + info = MQUEUE_I(ino); | |
1044 | + | |
1045 | + if ((filp->f_flags & O_ACCMODE) == O_RDONLY) | |
1046 | + goto out_fput; | |
1047 | + | |
1048 | + /* first try to allocate memory, before doing anything with | |
1049 | + * existing queues */ | |
1050 | + msg_ptr = load_msg((void *)u_msg_ptr, msg_len); | |
1051 | + if (IS_ERR(msg_ptr)) { | |
1052 | + ret = PTR_ERR(msg_ptr); | |
1053 | + goto out_fput; | |
1054 | + } | |
1055 | + | |
1056 | + /* This memory may be unnecessary but we must alloc it here | |
1057 | + * because of spinlock. kfree is called in wq_remove(_last) */ | |
1058 | + wq_ptr = kmalloc(sizeof(struct ext_wait_queue), GFP_KERNEL); | |
1059 | + if (wq_ptr == NULL) { | |
1060 | + ret = -ENOMEM; | |
1061 | + goto out_free; | |
1062 | + } | |
1063 | + | |
1064 | + spin_lock(&info->lock); | |
1065 | + | |
1066 | + if ((filp->f_flags & O_NONBLOCK) && (info->attr.mq_curmsgs == info->attr.mq_maxmsg)) { | |
1067 | + ret = -EAGAIN; | |
1068 | + goto out_1unlock; | |
1069 | + } | |
1070 | + | |
1071 | + if (msg_len > info->attr.mq_msgsize) { | |
1072 | + ret = -EMSGSIZE; | |
1073 | + goto out_1unlock; | |
1074 | + } | |
1075 | + | |
1076 | + /* checks if queue is full -> I'm waiting as O_NONBLOCK isn't | |
1077 | + * set then. mq_receive wakes up only 1 task */ | |
1078 | + if (info->attr.mq_curmsgs == info->attr.mq_maxmsg) { | |
1079 | + ret = wq_sleep(info, SEND, timeout, wq_ptr); | |
1080 | + if (ret) | |
1081 | + goto out_1unlock_nofree; | |
1082 | + } else | |
1083 | + kfree(wq_ptr); | |
1084 | + | |
1085 | + /* adds message to the queue */ | |
1086 | + msg_ptr->m_ts = msg_len; | |
1087 | + msg_ptr->m_type = msg_prio; | |
1088 | + | |
1089 | + msg_insert(msg_ptr, info); | |
1090 | + | |
1091 | + info->qsize += msg_len; | |
1092 | + ino->i_atime = ino->i_mtime = ino->i_ctime = CURRENT_TIME; | |
1093 | + __do_notify(info); | |
1094 | + | |
1095 | + /* after sending message we must wake up (ONLY 1 no matter which) */ | |
1096 | + /* task sleeping in wq_wakeup() */ | |
1097 | + wake_up(&(info->wait_q2[SEND])); | |
1098 | + | |
1099 | + /* wakes up task waiting for message */ | |
1100 | + wq_wakeup(info, RECV); | |
1101 | + | |
1102 | + spin_unlock(&info->lock); | |
1103 | + ret = 0; | |
1104 | + goto out_fput; | |
1105 | + | |
1106 | + /* I hate this goto convention... */ | |
1107 | +out_1unlock: | |
1108 | + kfree(wq_ptr); | |
1109 | +out_1unlock_nofree: | |
1110 | + spin_unlock(&info->lock); | |
1111 | +out_free: | |
1112 | + free_msg(msg_ptr); | |
1113 | +out_fput: | |
1114 | + fput(filp); | |
1115 | +out: | |
1116 | + return ret; | |
1117 | +} | |
1118 | + | |
1119 | +asmlinkage long sys_mq_timedsend(mqd_t mqdes, const char __user *u_msg_ptr, | |
1120 | + size_t msg_len, unsigned int msg_prio, const struct timespec __user *u_abs_timeout) | |
1121 | +{ | |
1122 | + long timeout; | |
1123 | + | |
1124 | + if (msg_prio >= (unsigned long) MQ_PRIO_MAX) | |
1125 | + return -EINVAL; | |
1126 | + | |
1127 | + if ((timeout = prepare_timeout(u_abs_timeout)) < 0) | |
1128 | + return timeout; | |
1129 | + return do_mq_timedsend(mqdes, u_msg_ptr, msg_len, msg_prio, timeout); | |
1130 | +} | |
1131 | + | |
1132 | + | |
1133 | +static ssize_t do_mq_timedreceive(mqd_t mqdes, char __user *u_msg_ptr, | |
1134 | + size_t msg_len, unsigned int __user *u_msg_prio, const long timeout) | |
1135 | +{ | |
1136 | + ssize_t ret; | |
1137 | + struct msg_msg *msg_ptr; | |
1138 | + struct file *filp; | |
1139 | + struct inode *ino; | |
1140 | + struct mqueue_inode_info *info; | |
1141 | + struct ext_wait_queue *wq_ptr; | |
1142 | + | |
1143 | + ret = -EBADF; | |
1144 | + filp = fget(mqdes); | |
1145 | + if (!filp) | |
1146 | + goto out; | |
1147 | + | |
1148 | + ino = filp->f_dentry->d_inode; | |
1149 | + if (ino->i_sb->s_magic != MQUEUE_MAGIC) | |
1150 | + goto out_fput; | |
1151 | + info = MQUEUE_I(ino); | |
1152 | + | |
1153 | + if ((filp->f_flags & O_ACCMODE) == O_WRONLY) | |
1154 | + goto out_fput; | |
1155 | + | |
1156 | + /* The same as in send */ | |
1157 | + wq_ptr = kmalloc(sizeof(struct ext_wait_queue), GFP_KERNEL); | |
1158 | + if (wq_ptr == NULL) { | |
1159 | + ret = -ENOMEM; | |
1160 | + goto out_fput; | |
1161 | + } | |
1162 | + | |
1163 | + spin_lock(&info->lock); | |
1164 | + | |
1165 | + /* checks if O_NONBLOCK is set and queue is empty */ | |
1166 | + if ((filp->f_flags & O_NONBLOCK) && (info->attr.mq_curmsgs == 0)) { | |
1167 | + ret = -EAGAIN; | |
1168 | + goto out_1unlock; | |
1169 | + } | |
1170 | + | |
1171 | + /* checks if buffer is big enough */ | |
1172 | + if (msg_len < info->attr.mq_msgsize) { | |
1173 | + ret = -EMSGSIZE; | |
1174 | + goto out_1unlock; | |
1175 | + } | |
1176 | + | |
1177 | + /* checks if queue is empty -> as O_NONBLOCK isn't set then | |
1178 | + * we must wait */ | |
1179 | + if (info->attr.mq_curmsgs == 0) { | |
1180 | + ret = wq_sleep(info, RECV, timeout, wq_ptr); | |
1181 | + if (ret < 0) | |
1182 | + goto out_unlock_only; | |
1183 | + } else | |
1184 | + kfree(wq_ptr); | |
1185 | + | |
1186 | + msg_ptr = msg_get(info); | |
1187 | + ret = msg_ptr->m_ts; | |
1188 | + | |
1189 | + info->qsize -= ret; | |
1190 | + ino->i_atime = ino->i_mtime = ino->i_ctime = CURRENT_TIME; | |
1191 | + | |
1192 | + /* after receive we can wakeup 1 task waiting in wq_wakeup */ | |
1193 | + wake_up(&(info->wait_q2[RECV])); | |
1194 | + /* wakes up task waiting for sending message */ | |
1195 | + wq_wakeup(info, SEND); | |
1196 | + | |
1197 | + spin_unlock(&info->lock); | |
1198 | + | |
1199 | + if (u_msg_prio) { | |
1200 | + if (put_user(msg_ptr->m_type, u_msg_prio)) { | |
1201 | + ret = -EFAULT; | |
1202 | + goto out_2free; | |
1203 | + } | |
1204 | + } | |
1205 | + if (store_msg(u_msg_ptr, msg_ptr, msg_ptr->m_ts)) | |
1206 | + ret = -EFAULT; | |
1207 | + | |
1208 | +out_2free: | |
1209 | + free_msg(msg_ptr); | |
1210 | + goto out_fput; | |
1211 | +out_1unlock: | |
1212 | + kfree(wq_ptr); | |
1213 | +out_unlock_only: | |
1214 | + spin_unlock(&info->lock); | |
1215 | +out_fput: | |
1216 | + fput(filp); | |
1217 | +out: | |
1218 | + return ret; | |
1219 | +} | |
1220 | + | |
1221 | +asmlinkage ssize_t sys_mq_timedreceive(mqd_t mqdes, char __user *u_msg_ptr, | |
1222 | + size_t msg_len, unsigned int __user *u_msg_prio, | |
1223 | + const struct timespec __user *u_abs_timeout) | |
1224 | +{ | |
1225 | + long timeout; | |
1226 | + | |
1227 | + if ((timeout = prepare_timeout(u_abs_timeout)) < 0) | |
1228 | + return timeout; | |
1229 | + return do_mq_timedreceive(mqdes, u_msg_ptr, msg_len, u_msg_prio, timeout); | |
1230 | +} | |
1231 | + | |
1232 | + | |
1233 | +/* Notes: the case when user wants us to deregister (with NULL as pointer or SIGEV_NONE) | |
1234 | + * and he isn't currently owner of notification will be silently discarded. | |
1235 | + * It isn't explicitly defined in the POSIX. | |
1236 | + */ | |
1237 | +asmlinkage long sys_mq_notify(mqd_t mqdes, const struct sigevent __user *u_notification) | |
1238 | +{ | |
1239 | + int ret; | |
1240 | + struct file *filp; | |
1241 | + struct inode *ino; | |
1242 | + struct sigevent notification; | |
1243 | + struct mqueue_inode_info *info; | |
1244 | + | |
1245 | + if (u_notification != NULL) { | |
1246 | + if (copy_from_user(¬ification, u_notification, sizeof(struct sigevent))) | |
1247 | + return -EFAULT; | |
1248 | + | |
1249 | + if (unlikely(notification.sigev_notify != SIGEV_NONE && | |
1250 | + notification.sigev_notify != SIGEV_SIGNAL && | |
1251 | + notification.sigev_notify != SIGEV_THREAD)) | |
1252 | + return -EINVAL; | |
1253 | + } | |
1254 | + | |
1255 | + ret = -EBADF; | |
1256 | + filp = fget(mqdes); | |
1257 | + if (!filp) | |
1258 | + goto out; | |
1259 | + | |
1260 | + ino = filp->f_dentry->d_inode; | |
1261 | + if (ino->i_sb->s_magic != MQUEUE_MAGIC) | |
1262 | + goto out_fput; | |
1263 | + info = MQUEUE_I(ino); | |
1264 | + | |
1265 | + ret = 0; | |
1266 | + spin_lock(&info->lock); | |
1267 | + | |
1268 | + if (u_notification == NULL || notification.sigev_notify == SIGEV_NONE) { | |
1269 | + if (info->notify_owner == current->tgid) | |
1270 | + remove_notification(info); | |
1271 | + goto out_unlock; | |
1272 | + } | |
1273 | + | |
1274 | + if (info->notify_task) { | |
1275 | + ret = -EBUSY; | |
1276 | + goto out_unlock; | |
1277 | + } | |
1278 | + /* add notification */ | |
1279 | + if (notification.sigev_signo < 0 || notification.sigev_signo > _NSIG) | |
1280 | + ret = -EINVAL; | |
1281 | + else { | |
1282 | + info->notify_task = current->pid; | |
1283 | + info->notify_owner = current->tgid; | |
1284 | + info->notify.sigev_signo = notification.sigev_signo; | |
1285 | + info->notify.sigev_notify = notification.sigev_notify; | |
1286 | + info->notify.sigev_value = notification.sigev_value; | |
1287 | + } | |
1288 | +out_unlock: | |
1289 | + ino->i_atime = ino->i_ctime = CURRENT_TIME; | |
1290 | + spin_unlock(&info->lock); | |
1291 | +out_fput: | |
1292 | + fput(filp); | |
1293 | +out: | |
1294 | + return ret; | |
1295 | +} | |
1296 | + | |
1297 | +asmlinkage long sys_mq_getattr(mqd_t mqdes, struct mq_attr __user *u_mqstat) | |
1298 | +{ | |
1299 | + int ret; | |
1300 | + struct mq_attr attr; | |
1301 | + struct file *filp; | |
1302 | + struct inode *ino; | |
1303 | + struct mqueue_inode_info *info; | |
1304 | + | |
1305 | + if (u_mqstat == NULL) | |
1306 | + return -EINVAL; | |
1307 | + | |
1308 | + ret = -EBADF; | |
1309 | + filp = fget(mqdes); | |
1310 | + if (!filp) | |
1311 | + goto out; | |
1312 | + | |
1313 | + ino = filp->f_dentry->d_inode; | |
1314 | + if (ino->i_sb->s_magic != MQUEUE_MAGIC) | |
1315 | + goto out_fput; | |
1316 | + info = MQUEUE_I(ino); | |
1317 | + | |
1318 | + spin_lock(&info->lock); | |
1319 | + attr = info->attr; | |
1320 | + attr.mq_flags = filp->f_flags; | |
1321 | + ino->i_atime = ino->i_ctime = CURRENT_TIME; | |
1322 | + | |
1323 | + spin_unlock(&info->lock); | |
1324 | + | |
1325 | + ret = 0; | |
1326 | + if (copy_to_user(u_mqstat, &attr, sizeof(struct mq_attr))) | |
1327 | + ret = -EFAULT; | |
1328 | + | |
1329 | +out_fput: | |
1330 | + fput(filp); | |
1331 | +out: | |
1332 | + return ret; | |
1333 | +} | |
1334 | + | |
1335 | +asmlinkage long sys_mq_setattr(mqd_t mqdes, const struct mq_attr __user *u_mqstat, | |
1336 | + struct mq_attr __user *u_omqstat) | |
1337 | +{ | |
1338 | + int ret; | |
1339 | + struct mq_attr mqstat, omqstat; | |
1340 | + struct file *filp; | |
1341 | + struct inode *ino; | |
1342 | + struct mqueue_inode_info *info; | |
1343 | + | |
1344 | + if (u_mqstat == NULL) | |
1345 | + return -EINVAL; | |
1346 | + | |
1347 | + if (copy_from_user(&mqstat, u_mqstat, sizeof (struct mq_attr))) | |
1348 | + return -EFAULT; | |
1349 | + | |
1350 | + ret = -EBADF; | |
1351 | + filp = fget(mqdes); | |
1352 | + if (!filp) | |
1353 | + goto out; | |
1354 | + | |
1355 | + ino = filp->f_dentry->d_inode; | |
1356 | + if (ino->i_sb->s_magic != MQUEUE_MAGIC) | |
1357 | + goto out_fput; | |
1358 | + info = MQUEUE_I(ino); | |
1359 | + | |
1360 | + spin_lock(&info->lock); | |
1361 | + | |
1362 | + omqstat = info->attr; | |
1363 | + omqstat.mq_flags = filp->f_flags; | |
1364 | + | |
1365 | + if (mqstat.mq_flags & O_NONBLOCK) | |
1366 | + filp->f_flags |= O_NONBLOCK; | |
1367 | + else | |
1368 | + filp->f_flags &= ~O_NONBLOCK; | |
1369 | + | |
1370 | + ino->i_atime = ino->i_ctime = CURRENT_TIME; | |
1371 | + | |
1372 | + spin_unlock(&info->lock); | |
1373 | + | |
1374 | + ret = 0; | |
1375 | + if (u_omqstat != NULL && copy_to_user(u_omqstat, &omqstat, sizeof(struct mq_attr))) | |
1376 | + ret = -EFAULT; | |
1377 | + | |
1378 | +out_fput: | |
1379 | + fput(filp); | |
1380 | +out: | |
1381 | + return ret; | |
1382 | +} | |
1383 | + | |
1384 | + | |
1385 | +static struct inode_operations mqueue_dir_inode_operations = { | |
1386 | + .lookup = mqueue_lookup, | |
1387 | + .create = mqueue_create, | |
1388 | + .unlink = mqueue_unlink, | |
1389 | +}; | |
1390 | + | |
1391 | +static struct file_operations mqueue_file_operations = { | |
1392 | + .release = mqueue_release_file, | |
1393 | + .poll = mqueue_poll_file, | |
1394 | + .read = mqueue_read_file, | |
1395 | +}; | |
1396 | + | |
1397 | +static struct super_operations mqueue_super_ops = { | |
1398 | + .alloc_inode = mqueue_alloc_inode, | |
1399 | + .destroy_inode = mqueue_destroy_inode, | |
1400 | + .statfs = simple_statfs, | |
1401 | + .delete_inode = mqueue_delete_inode, | |
1402 | + .drop_inode = generic_delete_inode, | |
1403 | +}; | |
1404 | + | |
1405 | +static struct file_system_type mqueue_fs_type = { | |
1406 | + .name = "mqueue", | |
1407 | + .get_sb = mqueue_get_sb, | |
1408 | + .kill_sb = kill_litter_super, | |
1409 | +}; | |
1410 | + | |
1411 | +static ctl_table mq_sysctls[] = { | |
1412 | + { | |
1413 | + .ctl_name = CTL_QUEUESMAX, | |
1414 | + .procname = "queues_max", | |
1415 | + .data = &queues_max, | |
1416 | + .maxlen = sizeof(int), | |
1417 | + .mode = 0644, | |
1418 | + .proc_handler = &proc_dointvec, | |
1419 | + }, | |
1420 | + { | |
1421 | + .ctl_name = CTL_MSGMAX, | |
1422 | + .procname = "msg_max", | |
1423 | + .data = &msg_max, | |
1424 | + .maxlen = sizeof(int), | |
1425 | + .mode = 0644, | |
1426 | + .proc_handler = &proc_dointvec, | |
1427 | + }, | |
1428 | + { | |
1429 | + .ctl_name = CTL_MSGSIZEMAX, | |
1430 | + .procname = "msgsize_max", | |
1431 | + .data = &msgsize_max, | |
1432 | + .maxlen = sizeof(int), | |
1433 | + .mode = 0644, | |
1434 | + .proc_handler = &proc_dointvec, | |
1435 | + }, | |
1436 | + { .ctl_name = 0 } | |
1437 | +}; | |
1438 | + | |
1439 | +static ctl_table mq_sysctl_dir[] = { | |
1440 | + { | |
1441 | + .ctl_name = FS_MQUEUE, | |
1442 | + .procname = "mqueue", | |
1443 | + .mode = 0555, | |
1444 | + .child = mq_sysctls, | |
1445 | + }, | |
1446 | + { .ctl_name = 0 } | |
1447 | +}; | |
1448 | + | |
1449 | +static ctl_table mq_sysctl_root[] = { | |
1450 | + { | |
1451 | + .ctl_name = CTL_FS, | |
1452 | + .procname = "fs", | |
1453 | + .mode = 0555, | |
1454 | + .child = mq_sysctl_dir, | |
1455 | + }, | |
1456 | + { .ctl_name = 0 } | |
1457 | +}; | |
1458 | + | |
1459 | + | |
1460 | +static int __init init_mqueue_fs(void) | |
1461 | +{ | |
1462 | + int error; | |
1463 | + | |
1464 | + mqueue_inode_cachep = kmem_cache_create("mqueue_inode_cache", | |
1465 | + sizeof(struct mqueue_inode_info), 0, SLAB_HWCACHE_ALIGN, init_once, NULL); | |
1466 | + | |
1467 | + if (mqueue_inode_cachep == NULL) | |
1468 | + return -ENOMEM; | |
1469 | + | |
1470 | + mq_sysctl_table = register_sysctl_table(mq_sysctl_root, 0); | |
1471 | + if (!mq_sysctl_table) { | |
1472 | + error = -ENOMEM; | |
1473 | + goto out_inodecache; | |
1474 | + } | |
1475 | + | |
1476 | + error = register_filesystem(&mqueue_fs_type); | |
1477 | + if (error) | |
1478 | + goto out_inodecache; | |
1479 | + | |
1480 | + if (IS_ERR(mqueue_mnt = kern_mount(&mqueue_fs_type))) { | |
1481 | + unregister_filesystem(&mqueue_fs_type); | |
1482 | + unregister_sysctl_table(mq_sysctl_table); | |
1483 | + error = PTR_ERR(mqueue_mnt); | |
1484 | + goto out_inodecache; | |
1485 | + } | |
1486 | + | |
1487 | + /* internal initialization - not common for vfs */ | |
1488 | + queues_count = 0; | |
1489 | + spin_lock_init(&mq_lock); | |
1490 | + | |
1491 | + return 0; | |
1492 | + | |
1493 | +out_inodecache: | |
1494 | + if (kmem_cache_destroy(mqueue_inode_cachep)) | |
1495 | + printk(KERN_INFO "mqueue_inode_cache: not all structures were freed\n"); | |
1496 | + return error; | |
1497 | +} | |
1498 | + | |
1499 | +static void __exit exit_mqueue_fs(void) | |
1500 | +{ | |
1501 | + unregister_filesystem(&mqueue_fs_type); | |
1502 | + unregister_sysctl_table(mq_sysctl_table); | |
1503 | + | |
1504 | + if (kmem_cache_destroy(mqueue_inode_cachep)) | |
1505 | + printk(KERN_INFO "mqueue_inode_cache: not all structures were freed\n"); | |
1506 | +} | |
1507 | + | |
1508 | +__initcall(init_mqueue_fs); | |
1509 | diff -urN 2.6.0-test10-orig_2/ipc/util.c 2.6.0-test10-patched_2/ipc/util.c | |
1510 | --- 2.6.0-test10-orig_2/ipc/util.c 2003-11-21 17:11:17.000000000 +0100 | |
1511 | +++ 2.6.0-test10-patched_2/ipc/util.c 2003-11-24 17:47:23.000000000 +0100 | |
1512 | @@ -24,10 +24,13 @@ | |
1513 | #include <linux/security.h> | |
1514 | #include <linux/rcupdate.h> | |
1515 | #include <linux/workqueue.h> | |
1516 | +#include <linux/mqueue.h> | |
1517 | ||
1518 | -#if defined(CONFIG_SYSVIPC) | |
1519 | - | |
1520 | +#if defined(CONFIG_SYSVIPC) || defined(CONFIG_POSIX_MQUEUE_FS) | |
1521 | #include "util.h" | |
1522 | +#endif | |
1523 | + | |
1524 | +#if defined(CONFIG_SYSVIPC) | |
1525 | ||
1526 | /** | |
1527 | * ipc_init - initialise IPC subsystem | |
1528 | @@ -612,7 +615,7 @@ | |
1529 | ||
1530 | #endif /* CONFIG_SYSVIPC */ | |
1531 | ||
1532 | -#ifdef CONFIG_SYSVIPC | |
1533 | +#if defined(CONFIG_POSIX_MQUEUE_FS) || defined(CONFIG_SYSVIPC) | |
1534 | ||
1535 | void free_msg(struct msg_msg* msg) | |
1536 | { | |
1537 | @@ -714,4 +717,51 @@ | |
1538 | return 0; | |
1539 | } | |
1540 | ||
1541 | -#endif /* CONFIG_SYSVIPC */ | |
1542 | +#endif /* CONFIG_POSIX_MQUEUE_FS || CONFIG_SYSVIPC */ | |
1543 | + | |
1544 | +#if !defined(CONFIG_POSIX_MQUEUE_FS) | |
1545 | + | |
1546 | +/* | |
1547 | + * Return ENOSYS when posix mqueue filesystem is not compiled in | |
1548 | + */ | |
1549 | + | |
1550 | +asmlinkage long sys_mq_open(const char *name, int oflag, mode_t mode, | |
1551 | + struct mq_attr *attr) | |
1552 | +{ | |
1553 | + return (mqd_t)-ENOSYS; | |
1554 | +} | |
1555 | + | |
1556 | +asmlinkage long sys_mq_unlink(const char *name) | |
1557 | +{ | |
1558 | + return -ENOSYS; | |
1559 | +} | |
1560 | + | |
1561 | +asmlinkage long sys_mq_timedsend(mqd_t mqdes, const char *msg_ptr, | |
1562 | + size_t msg_len, unsigned int msg_prio, const struct timespec *abs_timeout) | |
1563 | +{ | |
1564 | + return -ENOSYS; | |
1565 | +} | |
1566 | + | |
1567 | +asmlinkage ssize_t sys_mq_timedreceive(mqd_t mqdes, char *msg_ptr, | |
1568 | + size_t msg_len, unsigned int *msg_prio, const struct timespec *abs_timeout) | |
1569 | +{ | |
1570 | + return -ENOSYS; | |
1571 | +} | |
1572 | + | |
1573 | +asmlinkage long sys_mq_notify(mqd_t mqdes, const struct sigevent *notification) | |
1574 | +{ | |
1575 | + return -ENOSYS; | |
1576 | +} | |
1577 | + | |
1578 | +asmlinkage long sys_mq_getattr(mqd_t mqdes, struct mq_attr *mqstat) | |
1579 | +{ | |
1580 | + return -ENOSYS; | |
1581 | +} | |
1582 | + | |
1583 | +asmlinkage long sys_mq_setattr(mqd_t mqdes, const struct mq_attr *mqstat, | |
1584 | + struct mq_attr *omqstat) | |
1585 | +{ | |
1586 | + return -ENOSYS; | |
1587 | +} | |
1588 | + | |
1589 | +#endif /* ! CONFIG_POSIX_MQUEUE_FS */ | |
1590 | diff -urN 2.6.0-test10-orig_2/kernel/signal.c 2.6.0-test10-patched_2/kernel/signal.c | |
1591 | --- 2.6.0-test10-orig_2/kernel/signal.c 2003-11-24 16:28:58.000000000 +0100 | |
1592 | +++ 2.6.0-test10-patched_2/kernel/signal.c 2003-11-24 16:51:48.000000000 +0100 | |
1593 | @@ -2044,6 +2044,7 @@ | |
1594 | err |= __put_user(from->si_stime, &to->si_stime); | |
1595 | break; | |
1596 | case __SI_RT: /* This is not generated by the kernel as of now. */ | |
1597 | + case __SI_MESGQ: /* But this is */ | |
1598 | err |= __put_user(from->si_pid, &to->si_pid); | |
1599 | err |= __put_user(from->si_uid, &to->si_uid); | |
1600 | err |= __put_user(from->si_int, &to->si_int); |