From: Manfred Spraul Make the posix message queue mountable by the user. This replaces ipcs and ipcrm for posix message queue: The admin can check which queues exist with ls and remove stale queues with rm. I'd like a final confirmation from Ulrich that our SIGEV_THREAD approach is the right thing(tm): He's aware of the design and didn't object, but I think he hasn't seen the final API yet. --- ipc/mqueue.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 files changed, 83 insertions(+), 12 deletions(-) diff -puN ipc/mqueue.c~mq-05-linuxext-mount ipc/mqueue.c --- 25/ipc/mqueue.c~mq-05-linuxext-mount 2004-02-29 02:28:31.000000000 -0800 +++ 25-akpm/ipc/mqueue.c 2004-02-29 02:28:31.000000000 -0800 @@ -122,9 +122,18 @@ static struct inode *mqueue_get_inode(st info->notify_owner = 0; info->qsize = 0; info->attr.mq_curmsgs = 0; - info->messages = NULL; + info->attr.mq_maxmsg = DFLT_MSGMAX; + info->attr.mq_msgsize = DFLT_MSGSIZEMAX; + info->messages = kmalloc(DFLT_MSGMAX * sizeof(struct msg_msg *), GFP_KERNEL); + if (!info->messages) { + make_bad_inode(inode); + iput(inode); + inode = NULL; + } } else if (S_ISDIR(mode)) { inode->i_nlink++; + /* Some things misbehave if size == 0 on a directory */ + inode->i_size = 2 * DIRENT_SIZE; inode->i_op = &mqueue_dir_inode_operations; inode->i_fop = &simple_dir_operations; } @@ -136,7 +145,6 @@ static int mqueue_fill_super(struct supe { struct inode *inode; - sb->s_flags = MS_NOUSER; sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_magic = MQUEUE_MAGIC; @@ -231,6 +239,9 @@ static int mqueue_create(struct inode *d goto out_lock; } + dir->i_size += DIRENT_SIZE; + dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME; + d_instantiate(dentry, inode); dget(dentry); return 0; @@ -239,6 +250,62 @@ out_lock: return error; } +static int mqueue_unlink(struct inode *dir, struct dentry *dentry) +{ + struct inode *inode = dentry->d_inode; + + dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME; + dir->i_size -= DIRENT_SIZE; + inode->i_nlink--; + dput(dentry); + return 0; +} + +/* +* This is routine for system read from queue file. +* To avoid mess with doing here some sort of mq_receive we allow +* to read only queue size & notification info (the only values +* that are interesting from user point of view and aren't accessible +* through std routines) +*/ +static ssize_t mqueue_read_file(struct file *filp, char __user *u_data, + size_t count, loff_t * off) +{ + struct mqueue_inode_info *info = MQUEUE_I(filp->f_dentry->d_inode); + char buffer[FILENT_SIZE]; + size_t slen; + loff_t o; + + if (!count) + return 0; + + spin_lock(&info->lock); + snprintf(buffer, sizeof(buffer), + "QSIZE:%-10lu NOTIFY:%-5d SIGNO:%-5d NOTIFY_PID:%-6d\n", + info->qsize, + info->notify_owner ? info->notify.sigev_notify : SIGEV_NONE, + (info->notify_owner && info->notify.sigev_notify == SIGEV_SIGNAL ) ? + info->notify.sigev_signo : 0, + info->notify_owner); + spin_unlock(&info->lock); + buffer[sizeof(buffer)-1] = '\0'; + slen = strlen(buffer)+1; + + o = *off; + if (o > slen) + return 0; + + if (o + count > slen) + count = slen - o; + + if (copy_to_user(u_data, buffer + o, count)) + return -EFAULT; + + *off = o + count; + filp->f_dentry->d_inode->i_atime = filp->f_dentry->d_inode->i_ctime = CURRENT_TIME; + return count; +} + static int mqueue_flush_file(struct file *filp) { struct mqueue_inode_info *info = MQUEUE_I(filp->f_dentry->d_inode); @@ -545,13 +612,12 @@ static struct file *do_create(struct den attr.mq_msgsize > msgsize_max) return ERR_PTR(-EINVAL); } + msgs = kmalloc(attr.mq_maxmsg * sizeof(*msgs), GFP_KERNEL); + if (!msgs) + return ERR_PTR(-ENOMEM); } else { - attr.mq_maxmsg = DFLT_MSGMAX; - attr.mq_msgsize = DFLT_MSGSIZEMAX; + msgs = NULL; } - msgs = kmalloc(attr.mq_maxmsg * sizeof(*msgs), GFP_KERNEL); - if (!msgs) - return ERR_PTR(-ENOMEM); ret = vfs_create(dir->d_inode, dentry, mode, NULL); if (ret) { @@ -562,9 +628,12 @@ static struct file *do_create(struct den inode = dentry->d_inode; info = MQUEUE_I(inode); - info->attr.mq_maxmsg = attr.mq_maxmsg; - info->attr.mq_msgsize = attr.mq_msgsize; - info->messages = msgs; + if (msgs) { + info->attr.mq_maxmsg = attr.mq_maxmsg; + info->attr.mq_msgsize = attr.mq_msgsize; + kfree(info->messages); + info->messages = msgs; + } filp = dentry_open(dentry, mqueue_mnt, oflag); if (!IS_ERR(filp)) @@ -1050,12 +1119,13 @@ out: static struct inode_operations mqueue_dir_inode_operations = { .lookup = simple_lookup, .create = mqueue_create, - .unlink = simple_unlink, + .unlink = mqueue_unlink, }; static struct file_operations mqueue_file_operations = { .flush = mqueue_flush_file, .poll = mqueue_poll_file, + .read = mqueue_read_file, }; static struct file_operations mqueue_notify_fops = { @@ -1068,6 +1138,7 @@ static struct file_operations mqueue_not static struct super_operations mqueue_super_ops = { .alloc_inode = mqueue_alloc_inode, .destroy_inode = mqueue_destroy_inode, + .statfs = simple_statfs, .delete_inode = mqueue_delete_inode, .drop_inode = generic_delete_inode, }; @@ -1075,7 +1146,7 @@ static struct super_operations mqueue_su static struct file_system_type mqueue_fs_type = { .name = "mqueue", .get_sb = mqueue_get_sb, - .kill_sb = kill_anon_super, + .kill_sb = kill_litter_super, }; static int msg_max_limit_min = DFLT_MSGMAX; _