Re: [PATCH] unified SysV and Posix mqueues as FS

From: Bill Davidsen (davidsen@tmr.com)
Date: Mon Oct 28 2002 - 17:18:23 EST


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;

- 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/



This archive was generated by hypermail 2b29 : Thu Oct 31 2002 - 22:00:39 EST