]> git.pld-linux.org Git - packages/kernel.git/blob - 2.6.0-t10-POSIX_message_queues-2of2-lkml.patch
- obsolete
[packages/kernel.git] / 2.6.0-t10-POSIX_message_queues-2of2-lkml.patch
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(&notification, 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);
This page took 0.199453 seconds and 3 git commands to generate.