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.


---

 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;

_