summaryrefslogtreecommitdiff
path: root/ipc/mqueue.c
diff options
context:
space:
mode:
authorAndrew Morton <akpm@osdl.org>2004-04-11 22:54:42 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-04-11 22:54:42 -0700
commitb95db64258b96d862b2d24ba825b98ac05f9c2fd (patch)
tree62db22ecdde1e641e8ff9a9ca0687d65f7d8ece0 /ipc/mqueue.c
parent0301b50bb63dd4149019b1fdb5fc7b168c6c12f7 (diff)
[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.
Diffstat (limited to 'ipc/mqueue.c')
-rw-r--r--ipc/mqueue.c95
1 files changed, 83 insertions, 12 deletions
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 4755a6040e32..c9a3e652a026 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -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 @@ 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 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 @@ 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 = {
@@ -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;