Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id ; Mon, 28 Oct 2002 17:15:55 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id ; Mon, 28 Oct 2002 17:15:25 -0500 Received: from tmr-02.dsl.thebiz.net ([216.238.38.204]:54027 "EHLO gatekeeper.tmr.com") by vger.kernel.org with ESMTP id ; Mon, 28 Oct 2002 17:12:38 -0500 Date: Mon, 28 Oct 2002 17:18:23 -0500 (EST) From: Bill Davidsen To: Peter Waechtler cc: linux-kernel@vger.kernel.org, jakub@redhat.com, torvalds@transmeta.com Subject: Re: [PATCH] unified SysV and Posix mqueues as FS In-Reply-To: <3DBC075B.AF32C23@mac.com> Message-ID: MIME-Version: 1.0 Content-Type: MULTIPART/MIXED; BOUNDARY=------------2C6609BA5B63E7B5E7A740EB Content-ID: Sender: linux-kernel-owner@vger.kernel.org X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 45648 Lines: 1740 This message is in MIME format. The first part should be readable text, while the remaining parts are likely unreadable without MIME-aware tools. Send mail to mime@docserver.cac.washington.edu for more info. --------------2C6609BA5B63E7B5E7A740EB Content-Type: TEXT/PLAIN; CHARSET=us-ascii Content-ID: 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 CTO, TMR Associates, Inc Doing interesting things with little computers since 1979. --------------2C6609BA5B63E7B5E7A740EB Content-Type: TEXT/PLAIN; CHARSET=iso-8859-1; NAME="posix-mqueue.txt" Content-Transfer-Encoding: QUOTED-PRINTABLE Content-ID: Content-Description: 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.000= 000000 +0200 +++ linux-2.5.44/Documentation/ioctl-number.txt 2002-10-27 15:33:23.00000= 0000 +0100 @@ -186,6 +186,7 @@ 0xB0 all RATIO devices in development: 0xB1 00-1F PPPoX +0xB2 00-1F linux/mqueue.h 0xCB 00-1F CBM serial IEC bus in development: = 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 +02= 00 @@ -0,0 +1,37 @@ +#ifndef _LINUX_MQUEUE_H +#define _LINUX_MQUEUE_H + +#include +#include +#include + +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/inc= lude/linux/msg.h --- vanilla-2.5.44/include/linux/msg.h 2002-08-10 00:09:02.000000000 +020= 0 +++ 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 +#include = /* ipcs ctl commands */ #define MSG_STAT 11 @@ -49,7 +50,7 @@ unsigned short msgseg; = }; = -#define MSGMNI 16 /* <=3D IPCMNI */ /* max # of msg queue ident= ifiers */ +#define MSGMNI 128 /* <=3D IPCMNI */ /* max # of msg queue ident= ifiers */ #define MSGMAX 8192 /* <=3D INT_MAX */ /* max size of message (byte= s) */ #define MSGMNB 16384 /* <=3D INT_MAX */ /* default max size of a mes= sage 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 wai= ting + 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 + * + * make it a filesystem (based on Christoph Rohland's work on shmfs), + * (c) 2000 Jakub Jelinek + * adapted and cleaned up for 2.5.44 by Peter W=E4chtler */ = #include #include -#include #include #include +#include #include #include +#include +#include +#include +#include #include #include #include "util.h" @@ -30,34 +38,87 @@ int msg_ctlmax =3D MSGMAX; int msg_ctlmnb =3D MSGMNB; int msg_ctlmni =3D 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, unsign= ed long); +static int msg_root_ioctl(struct inode *, struct file *, unsigned int, u= nsigned 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 *, si= ze_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_a= ttr *attr, int msgflg); = - struct msg_msg* volatile r_msg; +static struct file_system_type msg_fs_type =3D { + .name =3D "msgfs", + .get_sb =3D msg_read_super, + .kill_sb =3D 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 =3D { + .read_inode=3D msg_fill_inode, + .delete_inode=3D msg_delete, + .put_super=3D msg_put_super, + .statfs=3D msg_statfs, + .remount_fs=3D 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 =3D { + .readdir=3D msg_readdir, + .ioctl=3D 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 =3D { + .create=3D msg_create, + .lookup=3D msg_lookup, + .unlink=3D msg_unlink, +}; + +static struct file_operations msg_file_operations =3D { + .read=3D msg_read, + .write=3D msg_write, + .ioctl=3D msg_ioctl, +/* FIXME: Support poll on mq * + poll=3D msg_poll, + */ + .flush=3D msg_flush, + .release=3D msg_release, +}; + +static struct inode_operations msg_inode_operations =3D { + .setattr=3D msg_setattr, +}; + +static LIST_HEAD(mq_open_links); = static atomic_t msg_bytes =3D ATOMIC_INIT(0); static atomic_t msg_hdrs =3D 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 offse= t, 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 =3D 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 =3D msg_ctlmnb * msg_ctlmni; + int inodes =3D msg_ctlmni; + umode_t mode =3D msg_mode; + char *this_char, *value; + + this_char =3D NULL; + if ( options ) + this_char =3D strsep(&options,","); + for ( ; this_char; this_char =3D strsep(&options,",")) { + if ((value =3D strchr(this_char,'=3D')) !=3D NULL) + *value++ =3D 0; + if (!strcmp(this_char,"nr_blocks")) { + if (!value || !*value) + return 1; + blocks =3D simple_strtoul(value,&value,0); + if (*value) + return 1; + } + else if (!strcmp(this_char,"nr_inodes")) { + if (!value || !*value) + return 1; + inodes =3D simple_strtoul(value,&value,0); + if (*value) + return 1; + } + else if (!strcmp(this_char,"mode")) { + if (!value || !*value) + return 1; + mode =3D simple_strtoul(value,&value,8); + if (*value) + return 1; + } + else + return 1; + } +/* FIXME * + msg_ctlmni =3D inodes; + msg_ctlmnb =3D inodes ? blocks / inodes : 0; + */ + msg_mode =3D mode; + + return 0; +} + +static int +msg_fill_super (struct super_block *sb, void *data, int silent) +{ + struct inode * root_inode; + +/* FIXME * + msg_ctlmnb =3D MSGMNB; + msg_ctlmni =3D MSGMNI; + */ + msg_mode =3D S_IRWXUGO | S_ISVTX; + if (msg_parse_options (data)) { + printk(KERN_ERR "msg fs invalid option\n"); + return -EINVAL; + } + + sb->s_blocksize =3D PAGE_SIZE; + sb->s_blocksize_bits =3D PAGE_SHIFT; + sb->s_magic =3D MSG_FS_MAGIC; + sb->s_op =3D &msg_sops; + root_inode =3D iget (sb, SEQ_MULTIPLIER); + if (!root_inode) + return -ENOMEM; + root_inode->i_op =3D &msg_root_inode_operations; + root_inode->i_sb =3D sb; + root_inode->i_nlink =3D 2; + root_inode->i_mode =3D S_IFDIR | msg_mode; + sb->s_root =3D d_alloc_root(root_inode); + if (!sb->s_root) + goto out_no_root; + msg_sb =3D 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_ty= pe, + 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 *dat= a) +{ + 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 =3D 0; i <=3D msg_ids.max_id; i++) { + if (!(msq =3D 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 =3D MSG_FS_MAGIC; + buf->f_bsize =3D PAGE_SIZE; + buf->f_blocks =3D (msg_ctlmnb * msg_ctlmni) >> PAGE_SHIFT; + buf->f_bavail =3D buf->f_bfree =3D buf->f_blocks - (atomic_read(&msg_b= ytes) >> PAGE_SHIFT); + buf->f_files =3D msg_ctlmni; + buf->f_ffree =3D msg_ctlmni - atomic_read(&msg_hdrs); + buf->f_namelen =3D MSG_NAME_LEN; + return 0; +} + +static void msg_fill_inode(struct inode * inode) +{ + int id; + struct msg_queue *msq; + id =3D inode->i_ino; + inode->i_op =3D NULL; + inode->i_mode =3D 0; + + if (id < SEQ_MULTIPLIER) { + if (!(msq =3D msg_lock (id))) + return; + inode->i_mode =3D (msq->q_flags & S_IRWXUGO) | S_IFIFO; + inode->i_uid =3D msq->q_perm.uid; + inode->i_gid =3D msq->q_perm.gid; + inode->i_size =3D msq->q_cbytes; + inode->i_mtime =3D msq->q_stime; + inode->i_atime =3D msq->q_stime > msq->q_rtime ? msq->q_stime : ms= q->q_rtime; + inode->i_ctime =3D msq->q_ctime; + msg_unlock (id); + inode->i_op =3D &msg_inode_operations; + inode->i_fop =3D &msg_file_operations; + return; + } + inode->i_mtime =3D inode->i_atime =3D inode->i_ctime =3D CURRENT_TIME;= + inode->i_op =3D &msg_root_inode_operations; + inode->i_fop =3D &msg_root_operations; + inode->i_sb =3D msg_sb; + inode->i_nlink =3D 2; + inode->i_mode =3D S_IFDIR | msg_mode; + inode->i_uid =3D inode->i_gid =3D 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 =3D 32; + attr.mq_msgsize =3D 64; + p =3D &attr; + + down(&msg_ids.sem); + list_for_each(tmp, &mq_open_links) { + struct mq_link *l =3D list_entry(tmp, struct mq_link, link); + if (l->tsk =3D=3D current) { + p =3D l->attr; + break; + } + } + err =3D id =3D newque (IPC_PRIVATE, dent->d_name.name, dent->d_name.le= n, p, mode); + if (err < 0) + goto out; + + inode =3D iget (msg_sb, id % SEQ_MULTIPLIER); + if (!inode){ + err =3D -ENOMEM; + goto out; + } + err =3D 0; + down (&inode->i_sem); + inode->i_mode =3D (mode & S_IRWXUGO) | S_IFIFO; + inode->i_op =3D &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 filld= ir) +{ + struct inode * inode =3D filp->f_dentry->d_inode; + struct msg_queue *msq; + off_t nr; + + nr =3D filp->f_pos; + + switch(nr) + { + case 0: + if (filldir(dirent, ".", 1, nr, inode->i_ino, DT_DIR) < 0) + return 0; + filp->f_pos =3D ++nr; + /* fall through */ + case 1: + if (filldir(dirent, "..", 2, nr, inode->i_ino, DT_DIR) < 0) + return 0; + filp->f_pos =3D ++nr; + /* fall through */ + default: + down(&msg_ids.sem); + for (; nr-2 <=3D msg_ids.max_id; nr++) { + if (!(msq =3D msg_get (nr-2))) + continue; + if (msq->q_flags & MSG_UNLK) + continue; + if (filldir(dirent, msq->q_name, msq->q_namelen, nr, nr, DT_FI= FO) < 0) + break;; + } + filp->f_pos =3D 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 =3D 0; + struct msg_queue* msq; + struct inode *inode =3D NULL; + + if (dent->d_name.len > MSG_NAME_LEN) + return ERR_PTR(-ENAMETOOLONG); + + down(&msg_ids.sem); + for(i =3D 0; i <=3D msg_ids.max_id; i++) { + if (!(msq =3D msg_lock(i))) + continue; + if (!(msq->q_flags & MSG_UNLK) && + dent->d_name.len =3D=3D msq->q_namelen && + strncmp(dent->d_name.name, msq->q_name, msq->q_namelen) =3D=3D= 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 =3D=3D MSG_FMT_LEN && + memcmp (MSG_FMT, dent->d_name.name, MSG_FMT_LEN - 8) =3D=3D 0) + err =3D -EINVAL; /* EINVAL to give IPC_RMID the right error */ + + goto out; + +found: + msg_unlock(i); + inode =3D iget(dir->i_sb, i); + + if (!inode) + err =3D -EACCES; +out: + if (err =3D=3D 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 =3D dent->d_inode; + struct msg_queue *msq; + + down (&msg_ids.sem); + if (!(msq =3D msg_lock (inode->i_ino))) + BUG(); + if (sysv) { + int ret =3D 0; + + if (!(msq->q_flags & MSG_SYSV)) + ret =3D -EINVAL; + else if (current->euid !=3D msq->q_perm.cuid && + current->euid !=3D msq->q_perm.uid && !capable(CAP_SYS_ADMIN)= ) + ret =3D -EPERM; + if (ret) { + msg_unlock (inode->i_ino); + up (&msg_ids.sem); + return ret; + } + } + msq->q_flags |=3D MSG_UNLK; + msq->q_perm.key =3D IPC_PRIVATE; /* Do not find it any more */ + msg_unlock (inode->i_ino); + up (&msg_ids.sem); + inode->i_nlink -=3D 1; + /* + * If it's a reserved name we have to drop the dentry instead + * of creating a negative dentry + */ + if (dent->d_name.len =3D=3D MSG_FMT_LEN && + memcmp (MSG_FMT, dent->d_name.name, MSG_FMT_LEN - 8) =3D=3D 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 =3D dentry->d_inode; + struct msg_queue *msq; + + error =3D 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 =3D msg_lock(inode->i_ino))) + BUG(); + if (attr->ia_valid & ATTR_MODE) + msq->q_flags =3D (msq->q_flags & ~S_IRWXUGO) + | (S_IRWXUGO & attr->ia_mode); + if (attr->ia_valid & ATTR_UID) + msq->q_perm.uid =3D attr->ia_uid; + if (attr->ia_valid & ATTR_GID) + msq->q_perm.gid =3D attr->ia_gid; + msq->q_ctime =3D 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, uns= igned int cmd, unsigned long arg) +{ + struct mq_open o; + struct mq_link link; + int ret; + + if (cmd !=3D MQ_OPEN) + return -EINVAL; + ret =3D -EFAULT; + if (copy_from_user(&o, (struct mq_open *)arg, sizeof(struct mq_open)))= + goto out; + ret =3D -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 =3D &o.mq_attr; + link.tsk =3D 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 wit= hin the msg filesystem? + Otherwise people tracing the open(2) syscall might miss this place.= =2E. */ + ret =3D 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 =3D -EINVAL; + struct msg_queue *msq; + struct mq_sndrcv sr; + + switch (cmd) { + case MQ_GETATTR: { + struct mq_attr attr; + memset(&attr, 0, sizeof(attr)); + msq =3D msg_lock (inode->i_ino); + if (msq =3D=3D NULL) + BUG(); + attr.mq_maxmsg =3D msq->q_maxmsg; + attr.mq_msgsize =3D msq->q_msgsize; + attr.mq_curmsgs =3D msq->q_qnum; + attr.mq_flags =3D filp->f_flags & O_NONBLOCK; + msg_unlock (inode->i_ino); + ret =3D copy_to_user((struct mq_attr *)arg, &attr, sizeof(attr)) ?= -EFAULT : 0; + break; + } + case MQ_SEND: + ret =3D -EBADF; + if (!(filp->f_mode & FMODE_WRITE)) + break; + ret =3D -EFAULT; + if (copy_from_user(&sr, (struct mq_sndrcv *)arg, sizeof(sr))) + break; + ret =3D -EINVAL; + if (sr.mq_type <=3D 0) + break; + ret =3D msg_send (inode, filp, sr.mq_buf, sr.mq_len, sr.mq_type); + break; + case MQ_RECEIVE: + ret =3D -EBADF; + if (!(filp->f_mode & FMODE_READ)) + break; + ret =3D -EFAULT; + if (copy_from_user(&sr, (struct mq_sndrcv *)arg, sizeof(sr))) + break; + ret =3D msg_receive (inode, filp, sr.mq_buf, sr.mq_len, &sr.mq_typ= e); + if (!ret && put_user (sr.mq_type, &((struct mq_sndrcv *)arg)->mq_t= ype)) + ret =3D -EFAULT; + break; + case MQ_NOTIFY: { + struct sigevent sev; + struct msg_queue *msg; + ret =3D -EFAULT; + if (copy_from_user(&sev, (struct sigevent *)arg, sizeof(sev))) + break; + ret =3D -EINVAL; + if (sev.sigev_notify !=3D SIGEV_SIGNAL && sev.sigev_notify !=3D SI= GEV_NONE) + break; + if (sev.sigev_signo <=3D 0 || sev.sigev_signo > _NSIG) + break; + msg =3D msg_lock(inode->i_ino); + if (!msg) BUG(); + ret =3D 0; + if (msg->q_signo) + ret =3D -EBUSY; + else if (sev.sigev_notify =3D=3D SIGEV_SIGNAL) { + msg->q_signo =3D sev.sigev_signo; + msg->q_sigval =3D sev.sigev_value; + } else + msg->q_signo =3D 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 =3D msg_send(file->f_dentry->d_inode, file, buf, count, MQ_DEF= AULT_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 =3D msg_lock(ino->i_ino); + if (!msq) BUG(); + if (msq->q_signo && msq->q_pid =3D=3D current->pid) + msq->q_signo =3D 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 =3D (struct msg_queue *) kmalloc (sizeof (*msq), GFP_KERNEL); + if (namelen > MSG_NAME_LEN) + return -ENAMETOOLONG; + msq =3D (struct msg_queue *) kmalloc (sizeof (*msq) + namelen, GFP_KERN= EL); + if (!msq) = return -ENOMEM; = @@ -113,18 +670,94 @@ kfree(msq); return -ENOSPC; } + msq->q_flags =3D (msgflg & S_IRWXUGO); + msq->q_perm.key =3D key; = msq->q_stime =3D msq->q_rtime =3D 0; msq->q_ctime =3D CURRENT_TIME; msq->q_cbytes =3D msq->q_qnum =3D 0; msq->q_qbytes =3D msg_ctlmnb; msq->q_lspid =3D msq->q_lrpid =3D 0; + msq->q_signo =3D 0; + INIT_LIST_HEAD(&msq->q_messages); INIT_LIST_HEAD(&msq->q_receivers); INIT_LIST_HEAD(&msq->q_senders); + msq->id =3D msg_buildid(id, msq->q_perm.seq); + if (name) { + msq->q_maxmsg =3D attr->mq_maxmsg; + msq->q_msgsize =3D attr->mq_msgsize; + msq->q_qbytes =3D msq->q_maxmsg * msq->q_msgsize; + msq->q_namelen =3D namelen; + memcpy(msq->q_name, name, namelen); + } else { + msq->q_qbytes =3D msg_ctlmnb; + msq->q_maxmsg =3D msg_ctlmnb; + msq->q_msgsize =3D msg_ctlmax; + msq->q_flags |=3D MSG_SYSV; + msq->q_namelen =3D 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 =3D ino->i_ino; + struct msg_queue *msq; + + down(&msg_ids.sem); + msq =3D msg_lock(msgid); + if(msq=3D=3DNULL) + 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 =3D msg_lock(msqid); + if (msq =3D=3D NULL) + return -EINVAL; + id =3D 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=3Dmsg_sb->s_root; + down(&dir->d_inode->i_sem); + dentry =3D lookup_one_len(name, dir, strlen(name) ); + error =3D 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 =3D dir->d_inode; + down(&inode->i_sem); + error =3D 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 =3D len; @@ -213,7 +846,7 @@ return -1; len -=3D alen; dest =3D ((char*)dest)+alen; - seg=3Dseg->next; + seg =3D seg->next; } return 0; } @@ -272,7 +905,7 @@ expunge_all(msq,-EIDRM); ss_wakeup(&msq->q_senders,1); msg_unlock(id); - = + tmp =3D msq->q_messages.next; while(tmp !=3D &msq->q_messages) { struct msg_msg* msg =3D list_entry(tmp,struct msg_msg,m_list); @@ -292,12 +925,12 @@ = down(&msg_ids.sem); if (key =3D=3D IPC_PRIVATE) = - ret =3D newque(key, msgflg); + ret =3D newque(key, NULL, MSG_FMT_LEN + 1, NULL, msgflg); else if ((id =3D ipc_findkey(&msg_ids, key)) =3D=3D -1) { /* key not us= ed */ if (!(msgflg & IPC_CREAT)) ret =3D -ENOENT; else - ret =3D newque(key, msgflg); + ret =3D newque(key, NULL, MSG_FMT_LEN + 1, NULL, msgflg); } else if (msgflg & IPC_CREAT && msgflg & IPC_EXCL) { ret =3D -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 =3D=3D MSG_STAT) { + err =3D -EINVAL; + if (!(msq->q_flags & MSG_SYSV)) + goto out_unlock; success_return =3D msg_buildid(msqid, msq->q_perm.seq); } else { - err =3D -EIDRM; - if (msg_checkid(msq,msqid)) + err =3D msg_checkid(msq,msqid); + if (err) goto out_unlock; success_return =3D 0; } @@ -480,6 +1109,7 @@ goto out_unlock; = kernel_to_ipc64_perm(&msq->q_perm, &tbuf.msg_perm); + tbuf.msg_perm.mode &=3D S_IRWXUGO; tbuf.msg_stime =3D msq->q_stime; tbuf.msg_rtime =3D msq->q_rtime; tbuf.msg_ctime =3D 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 =3D=3D IPC_SET) { if (setbuf.qbytes > msg_ctlmnb && !capable(CAP_SYS_RESOURCE)) goto out_unlock_up; msq->q_qbytes =3D setbuf.qbytes; + msq->q_maxmsg =3D setbuf.qbytes; = ipcp->uid =3D setbuf.uid; ipcp->gid =3D setbuf.gid; @@ -542,11 +1171,6 @@ */ ss_wakeup(&msq->q_senders,0); msg_unlock(msqid); - break; - } - case IPC_RMID: - freeque (msqid); = - break; } err =3D 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 =3D *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 =3D TASK_RUNNING; + + *msqp =3D msq =3D msg_lock(msqid); + if(msq=3D=3DNULL) + 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 +=3D msgsz; + msq->q_qnum++; + atomic_add(msgsz,&msg_bytes); + atomic_inc(&msg_hdrs); + if (msq->q_qnum =3D=3D 1 && msq->q_signo) { + struct task_struct *p; + siginfo_t si; + read_lock(&tasklist_lock); + p =3D find_task_by_pid(msq->q_pid); + if (p) { + si.si_signo =3D msq->q_signo; + si.si_errno =3D 0; + si.si_code =3D SI_MESGQ; + si.si_pid =3D current->pid; + si.si_uid =3D current->euid; + si.si_value =3D 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 =3D 0; + } + } + + msq->q_lspid =3D current->pid; + msq->q_stime =3D CURRENT_TIME; + return 0; +} + +static ssize_t msg_send (struct inode *ino, struct file *filp, const cha= r *mtext, size_t msgsz, long mtype) +{ + struct msg_queue *msq; + struct msg_msg *msg; + int err =3D 0; + = + if (mtype < 1) + return -EINVAL; + msq =3D msg_lock(ino->i_ino); + if (!msq) BUG(); + if (msgsz > msq->q_msgsize) + err =3D -EMSGSIZE; + msg_unlock(ino->i_ino); + if (err) return err; + + msg =3D load_msg(mtext, msgsz); + if(IS_ERR(msg)) + return PTR_ERR(msg); + + msg->m_type =3D mtype; + msg->m_ts =3D msgsz; + + msq =3D msg_lock(ino->i_ino); + if (!msq) BUG(); + + do { + err =3D -EACCES; + if (msq->q_flags & MSG_SYSV && ipcperms(&msq->q_perm, S_IWUGO)) + break; + + err =3D msg_do_send(&msq, ino->i_ino, msg, msgsz, filp->f_flags & O_NO= NBLOCK); + + } while (err =3D=3D -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=3D-EINVAL; if(msq=3D=3DNULL) goto out_free; -retry: - err=3D -EIDRM; - if (msg_checkid(msq,msqid)) - goto out_unlock_free; - - err=3D-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=3D-EAGAIN; - goto out_unlock_free; - } - ss_add(msq, &s); - msg_unlock(msqid); - schedule(); - current->state=3D TASK_RUNNING; + do { + err=3D -EIDRM; + if (msg_checkid(msq,msqid)) + break; = - msq =3D msg_lock(msqid); - err =3D -EIDRM; - if(msq=3D=3DNULL) - goto out_free; - ss_del(&s); - = - if (signal_pending(current)) { - err=3D-EINTR; - goto out_unlock_free; - } - goto retry; - } + err=3D-EACCES; + if (ipcperms(&msq->q_perm, S_IWUGO)) + break; = - msq->q_lspid =3D current->pid; - msq->q_stime =3D CURRENT_TIME; + err =3D 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 +=3D msgsz; - msq->q_qnum++; - atomic_add(msgsz,&msg_bytes); - atomic_inc(&msg_hdrs); - } - = - err =3D 0; - msg =3D NULL; + } while (err =3D=3D -EBUSY); = -out_unlock_free: - msg_unlock(msqid); + if (msq) + msg_unlock(msqid); out_free: - if(msg!=3DNULL) + 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 =3D *msqidp; + + for (;;) { + if (msq->q_flags & MSG_SYSV && ipcperms (&msq->q_perm, S_IRUGO)) + return ERR_PTR(-EACCES); + + tmp =3D msq->q_messages.next; + found_msg =3D NULL; + while (tmp !=3D &msq->q_messages) { + msg =3D list_entry(tmp,struct msg_msg,m_list); + if(testmsg(msg, msgtyp, mode)) { + found_msg =3D msg; + if(mode =3D=3D SEARCH_LESSEQUAL && msg->m_type !=3D 1) + msgtyp =3D msg->m_type - 1; + else + break; + } + tmp =3D tmp->next; + } + if (found_msg) { + msg =3D 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 =3D CURRENT_TIME; + msq->q_lrpid =3D current->pid; + msq->q_cbytes -=3D 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 =3D current; + msr_d.r_msgtype =3D msgtyp; + msr_d.r_mode =3D mode; + if(msgflg & MSG_NOERROR) + msr_d.r_maxsize =3D INT_MAX; + else + msr_d.r_maxsize =3D msgsz; + msr_d.r_msg =3D ERR_PTR(-EAGAIN); + current->state =3D TASK_INTERRUPTIBLE; + msg_unlock(msqid); + + schedule(); + current->state =3D TASK_RUNNING; + + msg =3D (struct msg_msg*) msr_d.r_msg; + if(!IS_ERR(msg)) + return msg; + + t =3D msg_lock(msqid); + if(t =3D=3D NULL) + *msqidp =3D msqid =3D -1; + msg =3D (struct msg_msg*)msr_d.r_msg; + if(!IS_ERR(msg)) { + /* our message arived while we waited for + * the spinlock. Process it. + */ + if (msqid !=3D -1) + msg_unlock(msqid); + return msg; + } + if(PTR_ERR(msg) =3D=3D -EAGAIN) { + if(msqid =3D=3D -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 *mtex= t, + size_t msgsz, long *msgtypp) +{ + struct msg_queue *msq; + struct msg_msg *msg; + long msgtyp; + int err, mode, msqid =3D ino->i_ino; + + if (msgtypp) + msgtyp =3D *msgtypp; + else + msgtyp =3D -MQ_DEFAULT_TYPE; + mode =3D convert_mode(&msgtyp, 0); + msq =3D msg_lock(msqid); + if (!msq) BUG(); + if (msgtypp && msgsz < msq->q_msgsize) { + msg_unlock(msqid); + return -EMSGSIZE; + } + + msg =3D msg_do_receive (msq, &msqid, msgsz, msgtyp, mode, + (filp->f_flags & O_NONBLOCK) ? IPC_NOWAIT : 0); + if (!IS_ERR (msg)) { + msgsz =3D (msgsz > msg->m_ts) ? msg->m_ts : msgsz; + if (store_msg(mtext, msg, msgsz)) + msgsz =3D -EFAULT; + else if (msgtypp) + *msgtypp =3D msg->m_type; + free_msg(msg); + return msgsz; + } + if (msqid !=3D -1) + msg_unlock(msqid); + err =3D PTR_ERR(msg); + switch (err) { + case -ENOMSG: err =3D -EAGAIN; break; + case -E2BIG: err =3D -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 =3D convert_mode(&msgtyp,msgflg); + mode =3D convert_mode(&msgtyp, msgflg); = - msq =3D msg_lock(msqid); - if(msq=3D=3DNULL) + msq =3D msg_lock (msqid); + if (msq=3D=3DNULL) + return -EINVAL; + if (!(msq->q_flags & MSG_SYSV)) { + msg_unlock (msqid); return -EINVAL; -retry: - err =3D -EIDRM; - if (msg_checkid(msq,msqid)) - goto out_unlock; - - err=3D-EACCES; - if (ipcperms (&msq->q_perm, S_IRUGO)) - goto out_unlock; - - tmp =3D msq->q_messages.next; - found_msg=3DNULL; - while (tmp !=3D &msq->q_messages) { - msg =3D list_entry(tmp,struct msg_msg,m_list); - if(testmsg(msg,msgtyp,mode)) { - found_msg =3D msg; - if(mode =3D=3D SEARCH_LESSEQUAL && msg->m_type !=3D 1) { - found_msg=3Dmsg; - msgtyp=3Dmsg->m_type-1; - } else { - found_msg=3Dmsg; - break; - } - } - tmp =3D tmp->next; } - if(found_msg) { - msg=3Dfound_msg; - if ((msgsz < msg->m_ts) && !(msgflg & MSG_NOERROR)) { - err=3D-E2BIG; - goto out_unlock; - } - list_del(&msg->m_list); - msq->q_qnum--; - msq->q_rtime =3D CURRENT_TIME; - msq->q_lrpid =3D current->pid; - msq->q_cbytes -=3D 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 =3D msg_do_receive (msq, &msqid, msgsz, msgtyp, mode, msgflg); + if (!IS_ERR (msg)) { msgsz =3D (msgsz > msg->m_ts) ? msg->m_ts : msgsz; - if (put_user (msg->m_type, &msgp->mtype) || - store_msg(msgp->mtext, msg, msgsz)) { - msgsz =3D -EFAULT; - } - free_msg(msg); - return msgsz; - } else - { - struct msg_queue *t; - /* no message waiting. Prepare for pipelined - * receive. - */ - if (msgflg & IPC_NOWAIT) { - err=3D-ENOMSG; - goto out_unlock; - } - list_add_tail(&msr_d.r_list,&msq->q_receivers); - msr_d.r_tsk =3D current; - msr_d.r_msgtype =3D msgtyp; - msr_d.r_mode =3D mode; - if(msgflg & MSG_NOERROR) - msr_d.r_maxsize =3D INT_MAX; - else - msr_d.r_maxsize =3D msgsz; - msr_d.r_msg =3D ERR_PTR(-EAGAIN); - current->state =3D TASK_INTERRUPTIBLE; - msg_unlock(msqid); - - schedule(); - current->state =3D TASK_RUNNING; - - msg =3D (struct msg_msg*) msr_d.r_msg; - if(!IS_ERR(msg)) = - goto out_success; - - t =3D msg_lock(msqid); - if(t=3D=3DNULL) - msqid=3D-1; - msg =3D (struct msg_msg*)msr_d.r_msg; - if(!IS_ERR(msg)) { - /* our message arived while we waited for - * the spinlock. Process it. - */ - if(msqid!=3D-1) - msg_unlock(msqid); - goto out_success; - } - err =3D PTR_ERR(msg); - if(err =3D=3D -EAGAIN) { - if(msqid=3D=3D-1) - BUG(); - list_del(&msr_d.r_list); - if (signal_pending(current)) - err=3D-EINTR; - else - goto retry; - } - } -out_unlock: - if(msqid!=3D-1) - msg_unlock(msqid); - return err; + if (put_user (msg->m_type, &msgp->mtype) || + store_msg(msgp->mtext, msg, msgsz)) + msgsz =3D -EFAULT; + free_msg(msg); + return msgsz; + } + if (msqid !=3D -1) + msg_unlock(msqid); + return PTR_ERR(msg); } = #ifdef CONFIG_PROC_FS @@ -841,16 +1569,16 @@ int i, len =3D 0; = down(&msg_ids.sem); - len +=3D sprintf(buffer, " key msqid perms cbytes = qnum lspid lrpid uid gid cuid cgid stime rtime ctim= e\n"); + len +=3D sprintf(buffer, " key msqid perms cbytes = qnum lspid lrpid uid gid cuid cgid stime rtime ctim= e name(POSIX)\n"); = for(i =3D 0; i <=3D msg_ids.max_id; i++) { struct msg_queue * msq; msq =3D msg_lock(i); if(msq !=3D NULL) { - len +=3D sprintf(buffer + len, "%10d %10d %4o %10lu %10lu %5u %5u %= 5u %5u %5u %5u %10lu %10lu %10lu\n", + len +=3D 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 +=3D len; --------------2C6609BA5B63E7B5E7A740EB-- - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/