lkml.org 
[lkml]   [2002]   [Oct]   [28]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    SubjectRe: [PATCH] unified SysV and Posix mqueues as FS
    On Sun, 27 Oct 2002, Peter Waechtler wrote:

    > I applied the patch from Jakub against 2.5.44
    > There are still open issues but it's important to get this in before
    > feature freeze.
    >
    > While you can implement Posix mqueues in userland (Irix is doing this
    > with fcntl(fd,F_SETLKW,) and shmem) a kernel implementation has some advantages:
    >
    > a) no hassle with locks in case an app crashes
    > b) guaranteed notification with signals (you can have two apps with
    > different uid that can acces the queue but aren't allowed to
    > send signals)
    > c) surprisingly, seems a little faster - did not test with NPT

    Surprises me, But I don't question it's possible. As long as it doesn't
    make the SysV stuff slower, 2.5 in general has more latency than 2.4, so I
    am sensitive to that.

    >
    > Open issues are:
    >
    > - notification not tested
    > - still linear search in queues
    > - I would really enhance the sys_ipc for handling posix mqueue as well
    > (yes, perhaps it's more ugly - but it fits naturally, you can't
    > specify a priority with a read() - ending up with ioctl())
    > - funny "locking" in ipc/util.c
    > - check the ipc ids

    --
    bill davidsen <davidsen@tmr.com>
    CTO, TMR Associates, Inc
    Doing interesting things with little computers since 1979.
    diff -Nur -X dontdiff vanilla-2.5.44/Documentation/ioctl-number.txt linux-2.5.44/Documentation/ioctl-number.txt
    --- vanilla-2.5.44/Documentation/ioctl-number.txt 2002-04-20 18:22:08.000000000 +0200
    +++ linux-2.5.44/Documentation/ioctl-number.txt 2002-10-27 15:33:23.000000000 +0100
    @@ -186,6 +186,7 @@
    0xB0 all RATIO devices in development:
    <mailto:vgo@ratio.de>
    0xB1 00-1F PPPoX <mailto:mostrows@styx.uwaterloo.ca>
    +0xB2 00-1F linux/mqueue.h
    0xCB 00-1F CBM serial IEC bus in development:
    <mailto:michael.klein@puffin.lb.shuttle.de>

    diff -Nur -X dontdiff vanilla-2.5.44/include/linux/mqueue.h linux-2.5.44/include/linux/mqueue.h
    --- vanilla-2.5.44/include/linux/mqueue.h 1970-01-01 01:00:00.000000000 +0100
    +++ linux-2.5.44/include/linux/mqueue.h 2002-10-23 14:48:31.000000000 +0200
    @@ -0,0 +1,37 @@
    +#ifndef _LINUX_MQUEUE_H
    +#define _LINUX_MQUEUE_H
    +
    +#include <linux/types.h>
    +#include <linux/ioctl.h>
    +#include <asm/siginfo.h>
    +
    +struct mq_attr {
    + long mq_flags; /* O_NONBLOCK or 0 */
    + long mq_maxmsg; /* Maximum number of messages in the queue */
    + long mq_msgsize; /* Maximum size of one message in bytes */
    + long mq_curmsgs; /* Current number of messages in the queue */
    + long __pad[2];
    +};
    +
    +struct mq_open {
    + char *mq_name; /* pathname */
    + int mq_oflag; /* flags */
    + mode_t mq_mode; /* mode */
    + struct mq_attr mq_attr; /* attributes */
    +};
    +
    +struct mq_sndrcv {
    + size_t mq_len; /* message length */
    + long mq_type; /* message type */
    + char *mq_buf; /* message buffer */
    +};
    +
    +#define MQ_OPEN _IOW(0xB2, 0, struct mq_open)
    +#define MQ_GETATTR _IOR(0xB2, 1, struct mq_attr)
    +#define MQ_SEND _IOW(0xB2, 2, struct mq_sndrcv)
    +#define MQ_RECEIVE _IOWR(0xB2, 3, struct mq_sndrcv)
    +#define MQ_NOTIFY _IOW(0xB2, 4, struct sigevent)
    +
    +#define MQ_DEFAULT_TYPE 0x7FFFFFFE
    +
    +#endif /* _LINUX_MQUEUE_H */
    diff -Nur -X dontdiff vanilla-2.5.44/include/linux/msg.h linux-2.5.44/include/linux/msg.h
    --- vanilla-2.5.44/include/linux/msg.h 2002-08-10 00:09:02.000000000 +0200
    +++ linux-2.5.44/include/linux/msg.h 2002-10-25 20:06:47.000000000 +0200
    @@ -2,6 +2,7 @@
    #define _LINUX_MSG_H

    #include <linux/ipc.h>
    +#include <linux/signal.h>

    /* ipcs ctl commands */
    #define MSG_STAT 11
    @@ -49,7 +50,7 @@
    unsigned short msgseg;
    };

    -#define MSGMNI 16 /* <= IPCMNI */ /* max # of msg queue identifiers */
    +#define MSGMNI 128 /* <= IPCMNI */ /* max # of msg queue identifiers */
    #define MSGMAX 8192 /* <= INT_MAX */ /* max size of message (bytes) */
    #define MSGMNB 16384 /* <= INT_MAX */ /* default max size of a message queue */

    @@ -63,33 +64,88 @@

    #ifdef __KERNEL__

    +#define SEARCH_ANY 1
    +#define SEARCH_EQUAL 2
    +#define SEARCH_NOTEQUAL 3
    +#define SEARCH_LESSEQUAL 4
    +
    +#define DATALEN_MSG (PAGE_SIZE-sizeof(struct msg_msg))
    +#define DATALEN_SEG (PAGE_SIZE-sizeof(struct msg_msgseg))
    +
    +/* used by sys_msgctl(,IPC_SET,) */
    +struct msq_setbuf {
    + unsigned long qbytes;
    + uid_t uid;
    + gid_t gid;
    + mode_t mode;
    +};
    +
    +/* one msg_receiver structure for each sleeping receiver */
    +struct msg_receiver {
    + struct list_head r_list;
    + struct task_struct *r_tsk;
    +
    + int r_mode;
    + long r_msgtype;
    + long r_maxsize;
    +
    + struct msg_msg* volatile r_msg;
    +};
    +
    +/* one msg_sender for each sleeping sender */
    +struct msg_sender {
    + struct list_head list;
    + struct task_struct *tsk;
    +};
    +
    +struct msg_msgseg {
    + struct msg_msgseg *next;
    + /* the next part of the message follows immediately */
    +};
    +
    /* one msg_msg structure for each message */
    struct msg_msg {
    struct list_head m_list;
    long m_type;
    int m_ts; /* message text size */
    - struct msg_msgseg* next;
    + struct msg_msgseg *next;
    /* the actual message follows immediately */
    };

    -#define DATALEN_MSG (PAGE_SIZE-sizeof(struct msg_msg))
    -#define DATALEN_SEG (PAGE_SIZE-sizeof(struct msg_msgseg))
    +struct mq_link {
    + struct list_head link;
    + struct task_struct *tsk;
    + struct mq_attr *attr;
    +};

    /* one msq_queue structure for each present queue on the system */
    struct msg_queue {
    struct kern_ipc_perm q_perm;
    - time_t q_stime; /* last msgsnd time */
    - time_t q_rtime; /* last msgrcv time */
    - time_t q_ctime; /* last change time */
    - unsigned long q_cbytes; /* current number of bytes on queue */
    - unsigned long q_qnum; /* number of messages in queue */
    - unsigned long q_qbytes; /* max number of bytes on queue */
    - pid_t q_lspid; /* pid of last msgsnd */
    - pid_t q_lrpid; /* last receive pid */
    +#define q_flags q_perm.mode
    + time_t q_stime; /* last msgsnd time */
    + time_t q_rtime; /* last msgrcv time */
    + time_t q_ctime; /* last change time */
    + unsigned long q_cbytes; /* current number of bytes on queue */
    + unsigned long q_qnum; /* number of messages in queue */
    + unsigned long q_qbytes; /* max number of bytes on queue */
    +
    + unsigned int q_msgsize; /* max number of bytes for one message */
    + unsigned int q_maxmsg; /* max number of outstanding messages */
    +
    + pid_t q_lspid; /* pid of last msgsnd */
    + pid_t q_lrpid; /* last receive pid */
    +
    + int q_signo; /* signal to be sent if empty queue with no waiting
    + receivers should be sent */
    + pid_t q_pid; /* to which pid */
    + sigval_t q_sigval; /* which value to pass */
    + int id;

    struct list_head q_messages;
    struct list_head q_receivers;
    struct list_head q_senders;
    + unsigned int q_namelen;
    + unsigned char q_name[0];
    };

    asmlinkage long sys_msgget (key_t key, int msgflg);
    diff -Nur -X dontdiff vanilla-2.5.44/ipc/msg.c linux-2.5.44/ipc/msg.c
    --- vanilla-2.5.44/ipc/msg.c 2002-10-13 23:03:57.000000000 +0200
    +++ linux-2.5.44/ipc/msg.c 2002-10-27 15:42:12.000000000 +0100
    @@ -13,15 +13,23 @@
    * mostly rewritten, threaded and wake-one semantics added
    * MSGMAX limit removed, sysctl's added
    * (c) 1999 Manfred Spraul <manfreds@colorfullife.com>
    + *
    + * make it a filesystem (based on Christoph Rohland's work on shmfs),
    + * (c) 2000 Jakub Jelinek <jakub@redhat.com>
    + * adapted and cleaned up for 2.5.44 by Peter Wächtler <pwaechtler@mac.com>
    */

    #include <linux/config.h>
    #include <linux/slab.h>
    -#include <linux/msg.h>
    #include <linux/spinlock.h>
    #include <linux/init.h>
    +#include <linux/fs.h>
    #include <linux/proc_fs.h>
    #include <linux/list.h>
    +#include <linux/signal.h>
    +#include <linux/mqueue.h>
    +#include <linux/msg.h>
    +#include <linux/namei.h>
    #include <linux/security.h>
    #include <asm/uaccess.h>
    #include "util.h"
    @@ -30,34 +38,87 @@
    int msg_ctlmax = MSGMAX;
    int msg_ctlmnb = MSGMNB;
    int msg_ctlmni = MSGMNI;
    +static int msg_mode;
    +
    +#define MSG_FS_MAGIC 822419456
    +
    +#define MSG_NAME_LEN NAME_MAX
    +#define MSG_FMT ".IPC_%08x"
    +#define MSG_FMT_LEN 13
    +
    +#define MSG_UNLK 0010000 /* filename is unlinked */
    +#define MSG_SYSV 0020000 /* It is a SYSV message queue */
    +
    +static struct super_block * msg_sb;
    +
    +static struct super_block *msg_read_super(struct file_system_type *,int , char *, void *);
    +static void msg_put_super(struct super_block *);
    +static int msg_remount_fs(struct super_block *, int *, char *);
    +static void msg_fill_inode(struct inode *);
    +static int msg_statfs(struct super_block *, struct statfs *);
    +static int msg_create(struct inode *,struct dentry *,int);
    +static struct dentry *msg_lookup(struct inode *,struct dentry *);
    +static int msg_unlink(struct inode *,struct dentry *);
    +static int msg_setattr(struct dentry *dent, struct iattr *attr);
    +static void msg_delete(struct inode *);
    +static int msg_readdir(struct file *, void *, filldir_t);
    +static int msg_remove_name(int id);
    +static int msg_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
    +static int msg_root_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
    +static ssize_t msg_read(struct file *, char *, size_t, loff_t *);
    +static ssize_t msg_write(struct file *, const char *, size_t, loff_t *);
    +/* FIXME: Support poll on mq
    +static unsigned int msg_poll(struct file *, poll_table *);
    + */
    +static ssize_t msg_send (struct inode *, struct file *, const char *, size_t, long);
    +static ssize_t msg_receive (struct inode *, struct file *, char *, size_t, long *);
    +static int msg_flush (struct file *);
    +static int msg_release (struct inode *, struct file *);

    -/* one msg_receiver structure for each sleeping receiver */
    -struct msg_receiver {
    - struct list_head r_list;
    - struct task_struct* r_tsk;
    -
    - int r_mode;
    - long r_msgtype;
    - long r_maxsize;
    +static void freeque (int id);
    +static int newque (key_t key, const char *name, int namelen, struct mq_attr *attr, int msgflg);

    - struct msg_msg* volatile r_msg;
    +static struct file_system_type msg_fs_type = {
    + .name = "msgfs",
    + .get_sb = msg_read_super,
    + .kill_sb = kill_litter_super,
    };

    -/* one msg_sender for each sleeping sender */
    -struct msg_sender {
    - struct list_head list;
    - struct task_struct* tsk;
    +static struct super_operations msg_sops = {
    + .read_inode= msg_fill_inode,
    + .delete_inode= msg_delete,
    + .put_super= msg_put_super,
    + .statfs= msg_statfs,
    + .remount_fs= msg_remount_fs,
    };

    -struct msg_msgseg {
    - struct msg_msgseg* next;
    - /* the next part of the message follows immediately */
    +static struct file_operations msg_root_operations = {
    + .readdir= msg_readdir,
    + .ioctl= msg_root_ioctl,
    };

    -#define SEARCH_ANY 1
    -#define SEARCH_EQUAL 2
    -#define SEARCH_NOTEQUAL 3
    -#define SEARCH_LESSEQUAL 4
    +static struct inode_operations msg_root_inode_operations = {
    + .create= msg_create,
    + .lookup= msg_lookup,
    + .unlink= msg_unlink,
    +};
    +
    +static struct file_operations msg_file_operations = {
    + .read= msg_read,
    + .write= msg_write,
    + .ioctl= msg_ioctl,
    +/* FIXME: Support poll on mq *
    + poll= msg_poll,
    + */
    + .flush= msg_flush,
    + .release= msg_release,
    +};
    +
    +static struct inode_operations msg_inode_operations = {
    + .setattr= msg_setattr,
    +};
    +
    +static LIST_HEAD(mq_open_links);

    static atomic_t msg_bytes = ATOMIC_INIT(0);
    static atomic_t msg_hdrs = ATOMIC_INIT(0);
    @@ -67,33 +128,529 @@
    #define msg_lock(id) ((struct msg_queue*)ipc_lock(&msg_ids,id))
    #define msg_unlock(id) ipc_unlock(&msg_ids,id)
    #define msg_rmid(id) ((struct msg_queue*)ipc_rmid(&msg_ids,id))
    -#define msg_checkid(msq, msgid) \
    - ipc_checkid(&msg_ids,&msq->q_perm,msgid)
    -#define msg_buildid(id, seq) \
    - ipc_buildid(&msg_ids, id, seq)
    +#define msg_get(id) ((struct msg_queue*)ipc_get(&msg_ids,id))
    +#define msg_buildid(id, seq) ipc_buildid(&msg_ids, id, seq)

    -static void freeque (int id);
    -static int newque (key_t key, int msgflg);
    #ifdef CONFIG_PROC_FS
    static int sysvipc_msg_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
    #endif

    void __init msg_init (void)
    {
    + struct vfsmount *res;
    ipc_init_ids(&msg_ids,msg_ctlmni);
    -
    + register_filesystem (&msg_fs_type);
    + res = kern_mount(&msg_fs_type);
    + if (IS_ERR(res)) {
    + unregister_filesystem(&msg_fs_type);
    + return;
    + }
    #ifdef CONFIG_PROC_FS
    create_proc_read_entry("sysvipc/msg", 0, 0, sysvipc_msg_read_proc, NULL);
    #endif
    }

    -static int newque (key_t key, int msgflg)
    +static int msg_parse_options(char *options)
    +{
    + int blocks = msg_ctlmnb * msg_ctlmni;
    + int inodes = msg_ctlmni;
    + umode_t mode = msg_mode;
    + char *this_char, *value;
    +
    + this_char = NULL;
    + if ( options )
    + this_char = strsep(&options,",");
    + for ( ; this_char; this_char = strsep(&options,",")) {
    + if ((value = strchr(this_char,'=')) != NULL)
    + *value++ = 0;
    + if (!strcmp(this_char,"nr_blocks")) {
    + if (!value || !*value)
    + return 1;
    + blocks = simple_strtoul(value,&value,0);
    + if (*value)
    + return 1;
    + }
    + else if (!strcmp(this_char,"nr_inodes")) {
    + if (!value || !*value)
    + return 1;
    + inodes = simple_strtoul(value,&value,0);
    + if (*value)
    + return 1;
    + }
    + else if (!strcmp(this_char,"mode")) {
    + if (!value || !*value)
    + return 1;
    + mode = simple_strtoul(value,&value,8);
    + if (*value)
    + return 1;
    + }
    + else
    + return 1;
    + }
    +/* FIXME *
    + msg_ctlmni = inodes;
    + msg_ctlmnb = inodes ? blocks / inodes : 0;
    + */
    + msg_mode = mode;
    +
    + return 0;
    +}
    +
    +static int
    +msg_fill_super (struct super_block *sb, void *data, int silent)
    +{
    + struct inode * root_inode;
    +
    +/* FIXME *
    + msg_ctlmnb = MSGMNB;
    + msg_ctlmni = MSGMNI;
    + */
    + msg_mode = S_IRWXUGO | S_ISVTX;
    + if (msg_parse_options (data)) {
    + printk(KERN_ERR "msg fs invalid option\n");
    + return -EINVAL;
    + }
    +
    + sb->s_blocksize = PAGE_SIZE;
    + sb->s_blocksize_bits = PAGE_SHIFT;
    + sb->s_magic = MSG_FS_MAGIC;
    + sb->s_op = &msg_sops;
    + root_inode = iget (sb, SEQ_MULTIPLIER);
    + if (!root_inode)
    + return -ENOMEM;
    + root_inode->i_op = &msg_root_inode_operations;
    + root_inode->i_sb = sb;
    + root_inode->i_nlink = 2;
    + root_inode->i_mode = S_IFDIR | msg_mode;
    + sb->s_root = d_alloc_root(root_inode);
    + if (!sb->s_root)
    + goto out_no_root;
    + msg_sb = sb;
    + return 0;
    +
    +out_no_root:
    + printk(KERN_ERR "msg_fill_super: get root inode failed\n");
    + iput(root_inode);
    + return -ENOMEM;
    +}
    +
    +static struct super_block *msg_read_super(struct file_system_type *fs_type,
    + int flags, char *dev_name, void *data)
    +{
    + return get_sb_single (fs_type, flags, data, msg_fill_super);
    +}
    +
    +static int msg_remount_fs (struct super_block *sb, int *flags, char *data)
    +{
    + if (msg_parse_options (data))
    + return -EINVAL;
    + return 0;
    +}
    +
    +static inline int msg_checkid(struct msg_queue *msq, int id)
    +{
    + if (!(msq->q_flags & MSG_SYSV))
    + return -EINVAL;
    + if (ipc_checkid(&msg_ids,&msq->q_perm,id))
    + return -EIDRM;
    + return 0;
    +}
    +
    +static void msg_put_super(struct super_block *sb)
    +{
    + int i;
    + struct msg_queue *msq;
    +
    + down(&msg_ids.sem);
    + for(i = 0; i <= msg_ids.max_id; i++) {
    + if (!(msq = msg_lock (i)))
    + continue;
    + freeque(i);
    + }
    + dput (sb->s_root);
    + up(&msg_ids.sem);
    +}
    +
    +static int msg_statfs(struct super_block *sb, struct statfs *buf)
    +{
    + buf->f_type = MSG_FS_MAGIC;
    + buf->f_bsize = PAGE_SIZE;
    + buf->f_blocks = (msg_ctlmnb * msg_ctlmni) >> PAGE_SHIFT;
    + buf->f_bavail = buf->f_bfree = buf->f_blocks - (atomic_read(&msg_bytes) >> PAGE_SHIFT);
    + buf->f_files = msg_ctlmni;
    + buf->f_ffree = msg_ctlmni - atomic_read(&msg_hdrs);
    + buf->f_namelen = MSG_NAME_LEN;
    + return 0;
    +}
    +
    +static void msg_fill_inode(struct inode * inode)
    +{
    + int id;
    + struct msg_queue *msq;
    + id = inode->i_ino;
    + inode->i_op = NULL;
    + inode->i_mode = 0;
    +
    + if (id < SEQ_MULTIPLIER) {
    + if (!(msq = msg_lock (id)))
    + return;
    + inode->i_mode = (msq->q_flags & S_IRWXUGO) | S_IFIFO;
    + inode->i_uid = msq->q_perm.uid;
    + inode->i_gid = msq->q_perm.gid;
    + inode->i_size = msq->q_cbytes;
    + inode->i_mtime = msq->q_stime;
    + inode->i_atime = msq->q_stime > msq->q_rtime ? msq->q_stime : msq->q_rtime;
    + inode->i_ctime = msq->q_ctime;
    + msg_unlock (id);
    + inode->i_op = &msg_inode_operations;
    + inode->i_fop = &msg_file_operations;
    + return;
    + }
    + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
    + inode->i_op = &msg_root_inode_operations;
    + inode->i_fop = &msg_root_operations;
    + inode->i_sb = msg_sb;
    + inode->i_nlink = 2;
    + inode->i_mode = S_IFDIR | msg_mode;
    + inode->i_uid = inode->i_gid = 0;
    +}
    +
    +static int msg_create (struct inode *dir, struct dentry *dent, int mode)
    +{
    + int id, err;
    + struct inode *inode;
    + struct mq_attr attr, *p;
    + struct list_head *tmp;
    +
    + attr.mq_maxmsg = 32;
    + attr.mq_msgsize = 64;
    + p = &attr;
    +
    + down(&msg_ids.sem);
    + list_for_each(tmp, &mq_open_links) {
    + struct mq_link *l = list_entry(tmp, struct mq_link, link);
    + if (l->tsk == current) {
    + p = l->attr;
    + break;
    + }
    + }
    + err = id = newque (IPC_PRIVATE, dent->d_name.name, dent->d_name.len, p, mode);
    + if (err < 0)
    + goto out;
    +
    + inode = iget (msg_sb, id % SEQ_MULTIPLIER);
    + if (!inode){
    + err = -ENOMEM;
    + goto out;
    + }
    + err = 0;
    + down (&inode->i_sem);
    + inode->i_mode = (mode & S_IRWXUGO) | S_IFIFO;
    + inode->i_op = &msg_inode_operations;
    + d_instantiate(dent, inode);
    + up (&inode->i_sem);
    +
    +out:
    + up(&msg_ids.sem);
    + return err;
    +}
    +
    +static int msg_readdir (struct file *filp, void *dirent, filldir_t filldir)
    +{
    + struct inode * inode = filp->f_dentry->d_inode;
    + struct msg_queue *msq;
    + off_t nr;
    +
    + nr = filp->f_pos;
    +
    + switch(nr)
    + {
    + case 0:
    + if (filldir(dirent, ".", 1, nr, inode->i_ino, DT_DIR) < 0)
    + return 0;
    + filp->f_pos = ++nr;
    + /* fall through */
    + case 1:
    + if (filldir(dirent, "..", 2, nr, inode->i_ino, DT_DIR) < 0)
    + return 0;
    + filp->f_pos = ++nr;
    + /* fall through */
    + default:
    + down(&msg_ids.sem);
    + for (; nr-2 <= msg_ids.max_id; nr++) {
    + if (!(msq = msg_get (nr-2)))
    + continue;
    + if (msq->q_flags & MSG_UNLK)
    + continue;
    + if (filldir(dirent, msq->q_name, msq->q_namelen, nr, nr, DT_FIFO) < 0)
    + break;;
    + }
    + filp->f_pos = nr;
    + up(&msg_ids.sem);
    + break;
    + }
    +
    + UPDATE_ATIME(inode);
    + return 0;
    +}
    +
    +static struct dentry *msg_lookup (struct inode *dir, struct dentry *dent)
    +{
    + int i, err = 0;
    + struct msg_queue* msq;
    + struct inode *inode = NULL;
    +
    + if (dent->d_name.len > MSG_NAME_LEN)
    + return ERR_PTR(-ENAMETOOLONG);
    +
    + down(&msg_ids.sem);
    + for(i = 0; i <= msg_ids.max_id; i++) {
    + if (!(msq = msg_lock(i)))
    + continue;
    + if (!(msq->q_flags & MSG_UNLK) &&
    + dent->d_name.len == msq->q_namelen &&
    + strncmp(dent->d_name.name, msq->q_name, msq->q_namelen) == 0)
    + goto found;
    + msg_unlock(i);
    + }
    +
    + /*
    + * prevent the reserved names as negative dentries.
    + * This also prevents object creation through the filesystem
    + */
    + if (dent->d_name.len == MSG_FMT_LEN &&
    + memcmp (MSG_FMT, dent->d_name.name, MSG_FMT_LEN - 8) == 0)
    + err = -EINVAL; /* EINVAL to give IPC_RMID the right error */
    +
    + goto out;
    +
    +found:
    + msg_unlock(i);
    + inode = iget(dir->i_sb, i);
    +
    + if (!inode)
    + err = -EACCES;
    +out:
    + if (err == 0)
    + d_add (dent, inode);
    + up (&msg_ids.sem);
    + return ERR_PTR(err);
    +}
    +
    +static inline int msg_do_unlink (struct inode *dir, struct dentry *dent, int sysv)
    +{
    + struct inode * inode = dent->d_inode;
    + struct msg_queue *msq;
    +
    + down (&msg_ids.sem);
    + if (!(msq = msg_lock (inode->i_ino)))
    + BUG();
    + if (sysv) {
    + int ret = 0;
    +
    + if (!(msq->q_flags & MSG_SYSV))
    + ret = -EINVAL;
    + else if (current->euid != msq->q_perm.cuid &&
    + current->euid != msq->q_perm.uid && !capable(CAP_SYS_ADMIN))
    + ret = -EPERM;
    + if (ret) {
    + msg_unlock (inode->i_ino);
    + up (&msg_ids.sem);
    + return ret;
    + }
    + }
    + msq->q_flags |= MSG_UNLK;
    + msq->q_perm.key = IPC_PRIVATE; /* Do not find it any more */
    + msg_unlock (inode->i_ino);
    + up (&msg_ids.sem);
    + inode->i_nlink -= 1;
    + /*
    + * If it's a reserved name we have to drop the dentry instead
    + * of creating a negative dentry
    + */
    + if (dent->d_name.len == MSG_FMT_LEN &&
    + memcmp (MSG_FMT, dent->d_name.name, MSG_FMT_LEN - 8) == 0)
    + d_drop (dent);
    + return 0;
    +}
    +
    +static int msg_unlink (struct inode *dir, struct dentry *dent)
    +{
    + return msg_do_unlink (dir, dent, 0);
    +}
    +static int msg_setattr (struct dentry *dentry, struct iattr *attr)
    +{
    + int error;
    + struct inode *inode = dentry->d_inode;
    + struct msg_queue *msq;
    +
    + error = inode_change_ok(inode, attr);
    + if (error)
    + return error;
    + if (attr->ia_valid & ATTR_SIZE)
    + return -EINVAL;
    +
    + if (attr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)) {
    + if (!(msq = msg_lock(inode->i_ino)))
    + BUG();
    + if (attr->ia_valid & ATTR_MODE)
    + msq->q_flags = (msq->q_flags & ~S_IRWXUGO)
    + | (S_IRWXUGO & attr->ia_mode);
    + if (attr->ia_valid & ATTR_UID)
    + msq->q_perm.uid = attr->ia_uid;
    + if (attr->ia_valid & ATTR_GID)
    + msq->q_perm.gid = attr->ia_gid;
    + msq->q_ctime = attr->ia_ctime;
    + msg_unlock (inode->i_ino);
    + }
    +
    + inode_setattr(inode, attr);
    + return error;
    +}
    +
    +static int msg_root_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, unsigned long arg)
    +{
    + struct mq_open o;
    + struct mq_link link;
    + int ret;
    +
    + if (cmd != MQ_OPEN)
    + return -EINVAL;
    + ret = -EFAULT;
    + if (copy_from_user(&o, (struct mq_open *)arg, sizeof(struct mq_open)))
    + goto out;
    + ret = -EINVAL;
    + if ((unsigned long)o.mq_attr.mq_msgsize > msg_ctlmnb ||
    + (unsigned long)o.mq_attr.mq_maxmsg > msg_ctlmnb ||
    + o.mq_attr.mq_msgsize * o.mq_attr.mq_maxmsg > msg_ctlmnb)
    + goto out;
    + link.attr = &o.mq_attr;
    + link.tsk = current;
    + down(&msg_ids.sem);
    + list_add(&link.link, &mq_open_links);
    + up(&msg_ids.sem);
    + /* FIXME: Shouldn't we check here whether mq_name is really a file within the msg filesystem?
    + Otherwise people tracing the open(2) syscall might miss this place... */
    + ret = sys_open(o.mq_name, o.mq_oflag, o.mq_mode);
    + down(&msg_ids.sem);
    + list_del(&link.link);
    + up(&msg_ids.sem);
    +out:
    + return ret;
    +}
    +
    +static int msg_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, unsigned long arg)
    +{
    + int ret = -EINVAL;
    + struct msg_queue *msq;
    + struct mq_sndrcv sr;
    +
    + switch (cmd) {
    + case MQ_GETATTR: {
    + struct mq_attr attr;
    + memset(&attr, 0, sizeof(attr));
    + msq = msg_lock (inode->i_ino);
    + if (msq == NULL)
    + BUG();
    + attr.mq_maxmsg = msq->q_maxmsg;
    + attr.mq_msgsize = msq->q_msgsize;
    + attr.mq_curmsgs = msq->q_qnum;
    + attr.mq_flags = filp->f_flags & O_NONBLOCK;
    + msg_unlock (inode->i_ino);
    + ret = copy_to_user((struct mq_attr *)arg, &attr, sizeof(attr)) ? -EFAULT : 0;
    + break;
    + }
    + case MQ_SEND:
    + ret = -EBADF;
    + if (!(filp->f_mode & FMODE_WRITE))
    + break;
    + ret = -EFAULT;
    + if (copy_from_user(&sr, (struct mq_sndrcv *)arg, sizeof(sr)))
    + break;
    + ret = -EINVAL;
    + if (sr.mq_type <= 0)
    + break;
    + ret = msg_send (inode, filp, sr.mq_buf, sr.mq_len, sr.mq_type);
    + break;
    + case MQ_RECEIVE:
    + ret = -EBADF;
    + if (!(filp->f_mode & FMODE_READ))
    + break;
    + ret = -EFAULT;
    + if (copy_from_user(&sr, (struct mq_sndrcv *)arg, sizeof(sr)))
    + break;
    + ret = msg_receive (inode, filp, sr.mq_buf, sr.mq_len, &sr.mq_type);
    + if (!ret && put_user (sr.mq_type, &((struct mq_sndrcv *)arg)->mq_type))
    + ret = -EFAULT;
    + break;
    + case MQ_NOTIFY: {
    + struct sigevent sev;
    + struct msg_queue *msg;
    + ret = -EFAULT;
    + if (copy_from_user(&sev, (struct sigevent *)arg, sizeof(sev)))
    + break;
    + ret = -EINVAL;
    + if (sev.sigev_notify != SIGEV_SIGNAL && sev.sigev_notify != SIGEV_NONE)
    + break;
    + if (sev.sigev_signo <= 0 || sev.sigev_signo > _NSIG)
    + break;
    + msg = msg_lock(inode->i_ino);
    + if (!msg) BUG();
    + ret = 0;
    + if (msg->q_signo)
    + ret = -EBUSY;
    + else if (sev.sigev_notify == SIGEV_SIGNAL) {
    + msg->q_signo = sev.sigev_signo;
    + msg->q_sigval = sev.sigev_value;
    + } else
    + msg->q_signo = 0;
    + msg_unlock(inode->i_ino);
    + }
    + default:
    + break;
    + }
    + return ret;
    +}
    +
    +static ssize_t msg_write(struct file * file,
    + const char * buf, size_t count, loff_t *ppos)
    +{
    + int ret = msg_send(file->f_dentry->d_inode, file, buf, count, MQ_DEFAULT_TYPE);
    + return ret ?: count;
    +}
    +
    +static ssize_t msg_read(struct file * file,
    + char * buf, size_t count, loff_t *ppos)
    +{
    + return msg_receive(file->f_dentry->d_inode, file, buf, count, NULL);
    +}
    +
    +static int msg_release (struct inode *ino, struct file *filp)
    +{
    + struct msg_queue *msq = msg_lock(ino->i_ino);
    + if (!msq) BUG();
    + if (msq->q_signo && msq->q_pid == current->pid)
    + msq->q_signo = 0;
    + msg_unlock(ino->i_ino);
    + return 0;
    +}
    +
    +static int msg_flush (struct file *filp)
    +{
    + return msg_release(filp->f_dentry->d_inode, filp);
    +}
    +
    +static int newque (key_t key, const char *name, int namelen,
    + struct mq_attr *attr, int msgflg)
    {
    int id;
    int retval;
    struct msg_queue *msq;

    - msq = (struct msg_queue *) kmalloc (sizeof (*msq), GFP_KERNEL);
    + if (namelen > MSG_NAME_LEN)
    + return -ENAMETOOLONG;
    + msq = (struct msg_queue *) kmalloc (sizeof (*msq) + namelen, GFP_KERNEL);
    +
    if (!msq)
    return -ENOMEM;

    @@ -113,18 +670,94 @@
    kfree(msq);
    return -ENOSPC;
    }
    + msq->q_flags = (msgflg & S_IRWXUGO);
    + msq->q_perm.key = key;

    msq->q_stime = msq->q_rtime = 0;
    msq->q_ctime = CURRENT_TIME;
    msq->q_cbytes = msq->q_qnum = 0;
    msq->q_qbytes = msg_ctlmnb;
    msq->q_lspid = msq->q_lrpid = 0;
    + msq->q_signo = 0;
    +
    INIT_LIST_HEAD(&msq->q_messages);
    INIT_LIST_HEAD(&msq->q_receivers);
    INIT_LIST_HEAD(&msq->q_senders);
    + msq->id = msg_buildid(id, msq->q_perm.seq);
    + if (name) {
    + msq->q_maxmsg = attr->mq_maxmsg;
    + msq->q_msgsize = attr->mq_msgsize;
    + msq->q_qbytes = msq->q_maxmsg * msq->q_msgsize;
    + msq->q_namelen = namelen;
    + memcpy(msq->q_name, name, namelen);
    + } else {
    + msq->q_qbytes = msg_ctlmnb;
    + msq->q_maxmsg = msg_ctlmnb;
    + msq->q_msgsize = msg_ctlmax;
    + msq->q_flags |= MSG_SYSV;
    + msq->q_namelen = sprintf(msq->q_name, MSG_FMT, msq->id);
    + }
    msg_unlock(id);

    - return msg_buildid(id,msq->q_perm.seq);
    + return msq->id;
    +}
    +
    +/* FIXME: maybe we need lock_kernel() here */
    +static void msg_delete (struct inode *ino)
    +{
    + int msgid = ino->i_ino;
    + struct msg_queue *msq;
    +
    + down(&msg_ids.sem);
    + msq = msg_lock(msgid);
    + if(msq==NULL)
    + BUG();
    + freeque(msgid);
    + up(&msg_ids.sem);
    + clear_inode(ino);
    +}
    +
    +static int msg_remove_name(int msqid)
    +{
    + struct dentry *dir;
    + struct dentry *dentry;
    + struct msg_queue *msq;
    + int error, id;
    + char name[MSG_FMT_LEN+1];
    +
    + down(&msg_ids.sem);
    + msq = msg_lock(msqid);
    + if (msq == NULL)
    + return -EINVAL;
    + id = msq->id;
    + if (msg_checkid (msq, msqid)) {
    + msg_unlock(msqid);
    + return -EIDRM;
    + }
    + msg_unlock(msqid);
    + up(&msg_ids.sem);
    + sprintf (name, MSG_FMT, id);
    + dir=msg_sb->s_root;
    + down(&dir->d_inode->i_sem);
    + dentry = lookup_one_len(name, dir, strlen(name) );
    + error = PTR_ERR(dentry);
    + if (!IS_ERR(dentry)) {
    + /*
    + * We have to do our own unlink to prevent the vfs
    + * permission check. We'll do the SYSV IPC style check
    + * inside of msg_do_unlink when we hold msg lock and
    + * msg_ids semaphore.
    + */
    + struct inode *inode = dir->d_inode;
    + down(&inode->i_sem);
    + error = msg_do_unlink(inode, dentry, 1);
    + if (!error)
    + d_delete(dentry);
    + up(&inode->i_sem);
    + dput(dentry);
    + }
    + up(&dir->d_inode->i_sem);
    + return error;
    }

    static void free_msg(struct msg_msg* msg)
    @@ -139,7 +772,7 @@
    }
    }

    -static struct msg_msg* load_msg(void* src, int len)
    +static struct msg_msg* load_msg(const char * src, int len)
    {
    struct msg_msg* msg;
    struct msg_msgseg** pseg;
    @@ -191,9 +824,9 @@
    return ERR_PTR(err);
    }

    -static int store_msg(void* dest, struct msg_msg* msg, int len)
    +static int store_msg(void* dest, struct msg_msg* msg, size_t len)
    {
    - int alen;
    + size_t alen;
    struct msg_msgseg *seg;

    alen = len;
    @@ -213,7 +846,7 @@
    return -1;
    len -= alen;
    dest = ((char*)dest)+alen;
    - seg=seg->next;
    + seg = seg->next;
    }
    return 0;
    }
    @@ -272,7 +905,7 @@
    expunge_all(msq,-EIDRM);
    ss_wakeup(&msq->q_senders,1);
    msg_unlock(id);
    -
    +
    tmp = msq->q_messages.next;
    while(tmp != &msq->q_messages) {
    struct msg_msg* msg = list_entry(tmp,struct msg_msg,m_list);
    @@ -292,12 +925,12 @@

    down(&msg_ids.sem);
    if (key == IPC_PRIVATE)
    - ret = newque(key, msgflg);
    + ret = newque(key, NULL, MSG_FMT_LEN + 1, NULL, msgflg);
    else if ((id = ipc_findkey(&msg_ids, key)) == -1) { /* key not used */
    if (!(msgflg & IPC_CREAT))
    ret = -ENOENT;
    else
    - ret = newque(key, msgflg);
    + ret = newque(key, NULL, MSG_FMT_LEN + 1, NULL, msgflg);
    } else if (msgflg & IPC_CREAT && msgflg & IPC_EXCL) {
    ret = -EEXIST;
    } else {
    @@ -358,13 +991,6 @@
    }
    }

    -struct msq_setbuf {
    - unsigned long qbytes;
    - uid_t uid;
    - gid_t gid;
    - mode_t mode;
    -};
    -
    static inline unsigned long copy_msqid_from_user(struct msq_setbuf *out, void *buf, int version)
    {
    switch(version) {
    @@ -468,10 +1094,13 @@
    return -EINVAL;

    if(cmd == MSG_STAT) {
    + err = -EINVAL;
    + if (!(msq->q_flags & MSG_SYSV))
    + goto out_unlock;
    success_return = msg_buildid(msqid, msq->q_perm.seq);
    } else {
    - err = -EIDRM;
    - if (msg_checkid(msq,msqid))
    + err = msg_checkid(msq,msqid);
    + if (err)
    goto out_unlock;
    success_return = 0;
    }
    @@ -480,6 +1109,7 @@
    goto out_unlock;

    kernel_to_ipc64_perm(&msq->q_perm, &tbuf.msg_perm);
    + tbuf.msg_perm.mode &= S_IRWXUGO;
    tbuf.msg_stime = msq->q_stime;
    tbuf.msg_rtime = msq->q_rtime;
    tbuf.msg_ctime = msq->q_ctime;
    @@ -500,7 +1130,7 @@
    return -EFAULT;
    break;
    case IPC_RMID:
    - break;
    + return msg_remove_name(msqid);
    default:
    return -EINVAL;
    }
    @@ -521,12 +1151,11 @@
    /* We _could_ check for CAP_CHOWN above, but we don't */
    goto out_unlock_up;

    - switch (cmd) {
    - case IPC_SET:
    - {
    + if (cmd == IPC_SET) {
    if (setbuf.qbytes > msg_ctlmnb && !capable(CAP_SYS_RESOURCE))
    goto out_unlock_up;
    msq->q_qbytes = setbuf.qbytes;
    + msq->q_maxmsg = setbuf.qbytes;

    ipcp->uid = setbuf.uid;
    ipcp->gid = setbuf.gid;
    @@ -542,11 +1171,6 @@
    */
    ss_wakeup(&msq->q_senders,0);
    msg_unlock(msqid);
    - break;
    - }
    - case IPC_RMID:
    - freeque (msqid);
    - break;
    }
    err = 0;
    out_up:
    @@ -608,6 +1232,105 @@
    return 0;
    }

    +static int msg_do_send (struct msg_queue **msqp, int msqid,
    + struct msg_msg *msg, size_t msgsz, int nowait)
    +{
    + struct msg_queue *msq = *msqp;
    +
    + if(msgsz + msq->q_cbytes > msq->q_qbytes ||
    + 1 + msq->q_qnum > msq->q_maxmsg) {
    + struct msg_sender s;
    +
    + if(nowait)
    + return -EAGAIN;
    +
    + ss_add(msq, &s);
    + msg_unlock(msqid);
    + schedule();
    + current->state = TASK_RUNNING;
    +
    + *msqp = msq = msg_lock(msqid);
    + if(msq==NULL)
    + return -EIDRM;
    + ss_del(&s);
    +
    + if (signal_pending(current))
    + return -EINTR;
    + return -EBUSY;
    + }
    +
    + if(!pipelined_send(msq,msg)) {
    + /* noone is waiting for this message, enqueue it */
    + list_add_tail(&msg->m_list,&msq->q_messages);
    + msq->q_cbytes += msgsz;
    + msq->q_qnum++;
    + atomic_add(msgsz,&msg_bytes);
    + atomic_inc(&msg_hdrs);
    + if (msq->q_qnum == 1 && msq->q_signo) {
    + struct task_struct *p;
    + siginfo_t si;
    + read_lock(&tasklist_lock);
    + p = find_task_by_pid(msq->q_pid);
    + if (p) {
    + si.si_signo = msq->q_signo;
    + si.si_errno = 0;
    + si.si_code = SI_MESGQ;
    + si.si_pid = current->pid;
    + si.si_uid = current->euid;
    + si.si_value = msq->q_sigval;
    + if (!send_sig_info(msq->q_signo, &si, p))
    + send_sig(msq->q_signo, p, 1);
    + }
    + read_unlock(&tasklist_lock);
    + msq->q_signo = 0;
    + }
    + }
    +
    + msq->q_lspid = current->pid;
    + msq->q_stime = CURRENT_TIME;
    + return 0;
    +}
    +
    +static ssize_t msg_send (struct inode *ino, struct file *filp, const char *mtext, size_t msgsz, long mtype)
    +{
    + struct msg_queue *msq;
    + struct msg_msg *msg;
    + int err = 0;
    +
    + if (mtype < 1)
    + return -EINVAL;
    + msq = msg_lock(ino->i_ino);
    + if (!msq) BUG();
    + if (msgsz > msq->q_msgsize)
    + err = -EMSGSIZE;
    + msg_unlock(ino->i_ino);
    + if (err) return err;
    +
    + msg = load_msg(mtext, msgsz);
    + if(IS_ERR(msg))
    + return PTR_ERR(msg);
    +
    + msg->m_type = mtype;
    + msg->m_ts = msgsz;
    +
    + msq = msg_lock(ino->i_ino);
    + if (!msq) BUG();
    +
    + do {
    + err = -EACCES;
    + if (msq->q_flags & MSG_SYSV && ipcperms(&msq->q_perm, S_IWUGO))
    + break;
    +
    + err = msg_do_send(&msq, ino->i_ino, msg, msgsz, filp->f_flags & O_NONBLOCK);
    +
    + } while (err == -EBUSY);
    +
    + msg_unlock(ino->i_ino);
    + if (msg && err)
    + free_msg(msg);
    + return err;
    +}
    +
    asmlinkage long sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
    {
    struct msg_queue *msq;
    @@ -633,60 +1356,23 @@
    err=-EINVAL;
    if(msq==NULL)
    goto out_free;
    -retry:
    - err= -EIDRM;
    - if (msg_checkid(msq,msqid))
    - goto out_unlock_free;
    -
    - err=-EACCES;
    - if (ipcperms(&msq->q_perm, S_IWUGO))
    - goto out_unlock_free;
    -
    - if(msgsz + msq->q_cbytes > msq->q_qbytes ||
    - 1 + msq->q_qnum > msq->q_qbytes) {
    - struct msg_sender s;
    -
    - if(msgflg&IPC_NOWAIT) {
    - err=-EAGAIN;
    - goto out_unlock_free;
    - }
    - ss_add(msq, &s);
    - msg_unlock(msqid);
    - schedule();
    - current->state= TASK_RUNNING;
    + do {
    + err= -EIDRM;
    + if (msg_checkid(msq,msqid))
    + break;

    - msq = msg_lock(msqid);
    - err = -EIDRM;
    - if(msq==NULL)
    - goto out_free;
    - ss_del(&s);
    -
    - if (signal_pending(current)) {
    - err=-EINTR;
    - goto out_unlock_free;
    - }
    - goto retry;
    - }
    + err=-EACCES;
    + if (ipcperms(&msq->q_perm, S_IWUGO))
    + break;

    - msq->q_lspid = current->pid;
    - msq->q_stime = CURRENT_TIME;
    + err = msg_do_send(&msq, msqid, msg, msgsz, msgflg & IPC_NOWAIT);

    - if(!pipelined_send(msq,msg)) {
    - /* noone is waiting for this message, enqueue it */
    - list_add_tail(&msg->m_list,&msq->q_messages);
    - msq->q_cbytes += msgsz;
    - msq->q_qnum++;
    - atomic_add(msgsz,&msg_bytes);
    - atomic_inc(&msg_hdrs);
    - }
    -
    - err = 0;
    - msg = NULL;
    + } while (err == -EBUSY);

    -out_unlock_free:
    - msg_unlock(msqid);
    + if (msq)
    + msg_unlock(msqid);
    out_free:
    - if(msg!=NULL)
    + if (msg && err)
    free_msg(msg);
    return err;
    }
    @@ -710,127 +1396,169 @@
    return SEARCH_EQUAL;
    }

    +static struct msg_msg *
    +msg_do_receive (struct msg_queue *msq, int *msqidp, size_t msgsz,
    + long msgtyp, int mode, int msgflg)
    +{
    + struct msg_receiver msr_d;
    + struct list_head *tmp;
    + struct msg_msg *msg, *found_msg;
    + int msqid = *msqidp;
    +
    + for (;;) {
    + if (msq->q_flags & MSG_SYSV && ipcperms (&msq->q_perm, S_IRUGO))
    + return ERR_PTR(-EACCES);
    +
    + tmp = msq->q_messages.next;
    + found_msg = NULL;
    + while (tmp != &msq->q_messages) {
    + msg = list_entry(tmp,struct msg_msg,m_list);
    + if(testmsg(msg, msgtyp, mode)) {
    + found_msg = msg;
    + if(mode == SEARCH_LESSEQUAL && msg->m_type != 1)
    + msgtyp = msg->m_type - 1;
    + else
    + break;
    + }
    + tmp = tmp->next;
    + }
    + if (found_msg) {
    + msg = found_msg;
    + if ((msgsz < msg->m_ts) && !(msgflg & MSG_NOERROR))
    + return ERR_PTR(-E2BIG);
    + list_del(&msg->m_list);
    + msq->q_qnum--;
    + msq->q_rtime = CURRENT_TIME;
    + msq->q_lrpid = current->pid;
    + msq->q_cbytes -= msg->m_ts;
    + atomic_sub(msg->m_ts,&msg_bytes);
    + atomic_dec(&msg_hdrs);
    + ss_wakeup(&msq->q_senders,0);
    + msg_unlock(msqid);
    + return msg;
    + } else {
    + struct msg_queue *t;
    + /* no message waiting. Prepare for pipelined
    + * receive.
    + */
    + if (msgflg & IPC_NOWAIT)
    + return ERR_PTR(-ENOMSG);
    + list_add_tail(&msr_d.r_list,&msq->q_receivers);
    + msr_d.r_tsk = current;
    + msr_d.r_msgtype = msgtyp;
    + msr_d.r_mode = mode;
    + if(msgflg & MSG_NOERROR)
    + msr_d.r_maxsize = INT_MAX;
    + else
    + msr_d.r_maxsize = msgsz;
    + msr_d.r_msg = ERR_PTR(-EAGAIN);
    + current->state = TASK_INTERRUPTIBLE;
    + msg_unlock(msqid);
    +
    + schedule();
    + current->state = TASK_RUNNING;
    +
    + msg = (struct msg_msg*) msr_d.r_msg;
    + if(!IS_ERR(msg))
    + return msg;
    +
    + t = msg_lock(msqid);
    + if(t == NULL)
    + *msqidp = msqid = -1;
    + msg = (struct msg_msg*)msr_d.r_msg;
    + if(!IS_ERR(msg)) {
    + /* our message arived while we waited for
    + * the spinlock. Process it.
    + */
    + if (msqid != -1)
    + msg_unlock(msqid);
    + return msg;
    + }
    + if(PTR_ERR(msg) == -EAGAIN) {
    + if(msqid == -1)
    + BUG();
    + list_del(&msr_d.r_list);
    + if (signal_pending(current))
    + return ERR_PTR(-EINTR);
    + else
    + continue;
    + }
    + return msg;
    + }
    + }
    +}
    +
    +static int msg_receive (struct inode *ino, struct file *filp, char *mtext,
    + size_t msgsz, long *msgtypp)
    +{
    + struct msg_queue *msq;
    + struct msg_msg *msg;
    + long msgtyp;
    + int err, mode, msqid = ino->i_ino;
    +
    + if (msgtypp)
    + msgtyp = *msgtypp;
    + else
    + msgtyp = -MQ_DEFAULT_TYPE;
    + mode = convert_mode(&msgtyp, 0);
    + msq = msg_lock(msqid);
    + if (!msq) BUG();
    + if (msgtypp && msgsz < msq->q_msgsize) {
    + msg_unlock(msqid);
    + return -EMSGSIZE;
    + }
    +
    + msg = msg_do_receive (msq, &msqid, msgsz, msgtyp, mode,
    + (filp->f_flags & O_NONBLOCK) ? IPC_NOWAIT : 0);
    + if (!IS_ERR (msg)) {
    + msgsz = (msgsz > msg->m_ts) ? msg->m_ts : msgsz;
    + if (store_msg(mtext, msg, msgsz))
    + msgsz = -EFAULT;
    + else if (msgtypp)
    + *msgtypp = msg->m_type;
    + free_msg(msg);
    + return msgsz;
    + }
    + if (msqid != -1)
    + msg_unlock(msqid);
    + err = PTR_ERR(msg);
    + switch (err) {
    + case -ENOMSG: err = -EAGAIN; break;
    + case -E2BIG: err = -EMSGSIZE; break;
    + }
    + return err;
    +}
    +
    asmlinkage long sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz,
    long msgtyp, int msgflg)
    {
    struct msg_queue *msq;
    - struct msg_receiver msr_d;
    - struct list_head* tmp;
    - struct msg_msg* msg, *found_msg;
    - int err;
    + struct msg_msg *msg;
    int mode;

    if (msqid < 0 || (long) msgsz < 0)
    return -EINVAL;
    - mode = convert_mode(&msgtyp,msgflg);
    + mode = convert_mode(&msgtyp, msgflg);

    - msq = msg_lock(msqid);
    - if(msq==NULL)
    + msq = msg_lock (msqid);
    + if (msq==NULL)
    + return -EINVAL;
    + if (!(msq->q_flags & MSG_SYSV)) {
    + msg_unlock (msqid);
    return -EINVAL;
    -retry:
    - err = -EIDRM;
    - if (msg_checkid(msq,msqid))
    - goto out_unlock;
    -
    - err=-EACCES;
    - if (ipcperms (&msq->q_perm, S_IRUGO))
    - goto out_unlock;
    -
    - tmp = msq->q_messages.next;
    - found_msg=NULL;
    - while (tmp != &msq->q_messages) {
    - msg = list_entry(tmp,struct msg_msg,m_list);
    - if(testmsg(msg,msgtyp,mode)) {
    - found_msg = msg;
    - if(mode == SEARCH_LESSEQUAL && msg->m_type != 1) {
    - found_msg=msg;
    - msgtyp=msg->m_type-1;
    - } else {
    - found_msg=msg;
    - break;
    - }
    - }
    - tmp = tmp->next;
    }
    - if(found_msg) {
    - msg=found_msg;
    - if ((msgsz < msg->m_ts) && !(msgflg & MSG_NOERROR)) {
    - err=-E2BIG;
    - goto out_unlock;
    - }
    - list_del(&msg->m_list);
    - msq->q_qnum--;
    - msq->q_rtime = CURRENT_TIME;
    - msq->q_lrpid = current->pid;
    - msq->q_cbytes -= msg->m_ts;
    - atomic_sub(msg->m_ts,&msg_bytes);
    - atomic_dec(&msg_hdrs);
    - ss_wakeup(&msq->q_senders,0);
    - msg_unlock(msqid);
    -out_success:
    + msg = msg_do_receive (msq, &msqid, msgsz, msgtyp, mode, msgflg);
    + if (!IS_ERR (msg)) {
    msgsz = (msgsz > msg->m_ts) ? msg->m_ts : msgsz;
    - if (put_user (msg->m_type, &msgp->mtype) ||
    - store_msg(msgp->mtext, msg, msgsz)) {
    - msgsz = -EFAULT;
    - }
    - free_msg(msg);
    - return msgsz;
    - } else
    - {
    - struct msg_queue *t;
    - /* no message waiting. Prepare for pipelined
    - * receive.
    - */
    - if (msgflg & IPC_NOWAIT) {
    - err=-ENOMSG;
    - goto out_unlock;
    - }
    - list_add_tail(&msr_d.r_list,&msq->q_receivers);
    - msr_d.r_tsk = current;
    - msr_d.r_msgtype = msgtyp;
    - msr_d.r_mode = mode;
    - if(msgflg & MSG_NOERROR)
    - msr_d.r_maxsize = INT_MAX;
    - else
    - msr_d.r_maxsize = msgsz;
    - msr_d.r_msg = ERR_PTR(-EAGAIN);
    - current->state = TASK_INTERRUPTIBLE;
    - msg_unlock(msqid);
    -
    - schedule();
    - current->state = TASK_RUNNING;
    -
    - msg = (struct msg_msg*) msr_d.r_msg;
    - if(!IS_ERR(msg))
    - goto out_success;
    -
    - t = msg_lock(msqid);
    - if(t==NULL)
    - msqid=-1;
    - msg = (struct msg_msg*)msr_d.r_msg;
    - if(!IS_ERR(msg)) {
    - /* our message arived while we waited for
    - * the spinlock. Process it.
    - */
    - if(msqid!=-1)
    - msg_unlock(msqid);
    - goto out_success;
    - }
    - err = PTR_ERR(msg);
    - if(err == -EAGAIN) {
    - if(msqid==-1)
    - BUG();
    - list_del(&msr_d.r_list);
    - if (signal_pending(current))
    - err=-EINTR;
    - else
    - goto retry;
    - }
    - }
    -out_unlock:
    - if(msqid!=-1)
    - msg_unlock(msqid);
    - return err;
    + if (put_user (msg->m_type, &msgp->mtype) ||
    + store_msg(msgp->mtext, msg, msgsz))
    + msgsz = -EFAULT;
    + free_msg(msg);
    + return msgsz;
    + }
    + if (msqid != -1)
    + msg_unlock(msqid);
    + return PTR_ERR(msg);
    }

    #ifdef CONFIG_PROC_FS
    @@ -841,16 +1569,16 @@
    int i, len = 0;

    down(&msg_ids.sem);
    - len += sprintf(buffer, " key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n");
    + len += sprintf(buffer, " key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime name(POSIX)\n");

    for(i = 0; i <= msg_ids.max_id; i++) {
    struct msg_queue * msq;
    msq = msg_lock(i);
    if(msq != NULL) {
    - len += sprintf(buffer + len, "%10d %10d %4o %10lu %10lu %5u %5u %5u %5u %5u %5u %10lu %10lu %10lu\n",
    + len += sprintf(buffer + len, "%10d %10d %4o %10lu %10lu %5u %5u %5u %5u %5u %5u %10lu %10lu %10lu %.*s%s\n",
    msq->q_perm.key,
    msg_buildid(i,msq->q_perm.seq),
    - msq->q_perm.mode,
    + msq->q_flags & S_IRWXUGO,
    msq->q_cbytes,
    msq->q_qnum,
    msq->q_lspid,
    @@ -861,7 +1589,10 @@
    msq->q_perm.cgid,
    msq->q_stime,
    msq->q_rtime,
    - msq->q_ctime);
    + msq->q_ctime,
    + msq->q_namelen,
    + msq->q_name,
    + msq->q_flags & MSG_UNLK ? " (deleted)" : "");
    msg_unlock(i);

    pos += len;
    \
     
     \ /
      Last update: 2005-03-22 13:30    [W:0.114 / U:29.936 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site