Commit b95db642 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] posix message queues: made user mountable

From: Manfred Spraul <manfred@colorfullife.com>

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.
parent 0301b50b
......@@ -122,9 +122,18 @@ static struct inode *mqueue_get_inode(struct super_block *sb, int mode)
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 super_block *sb, void *data, int silent)
{
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 *dir, struct dentry *dentry,
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 @@ static int mqueue_create(struct inode *dir, struct dentry *dentry,
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 dentry *dir, struct dentry *dentry,
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 dentry *dir, struct dentry *dentry,
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))
......@@ -1054,12 +1123,13 @@ asmlinkage long sys_mq_getsetattr(mqd_t mqdes,
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 = {
......@@ -1072,6 +1142,7 @@ static struct file_operations mqueue_notify_fops = {
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,
};
......@@ -1079,7 +1150,7 @@ static struct super_operations mqueue_super_ops = {
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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment