
From: Chris Wright <chrisw@osdl.org>

Add a user_struct to the mq_inode_info structure.  Charge the maximum number
of bytes that could be allocated to a mqueue to the user who creates the
mqueue.  This is checked against the per user rlimit.


---

 25-akpm/ipc/mqueue.c |   44 +++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 39 insertions(+), 5 deletions(-)

diff -puN ipc/mqueue.c~rlim-enforce-rlimits-for-posix-mqueue-allocation ipc/mqueue.c
--- 25/ipc/mqueue.c~rlim-enforce-rlimits-for-posix-mqueue-allocation	Tue May 11 15:21:21 2004
+++ 25-akpm/ipc/mqueue.c	Tue May 11 15:21:21 2004
@@ -67,6 +67,7 @@ struct mqueue_inode_info {
 
 	struct sigevent notify;
 	pid_t notify_owner;
+ 	struct user_struct *user;	/* user who created, for accouting */
 	struct sock *notify_sock;
 	struct sk_buff *notify_cookie;
 
@@ -114,6 +115,9 @@ static struct inode *mqueue_get_inode(st
 
 		if (S_ISREG(mode)) {
 			struct mqueue_inode_info *info;
+			struct task_struct *p = current;
+			struct user_struct *u = p->user;
+			unsigned long mq_bytes, mq_msg_tblsz;
 
 			inode->i_fop = &mqueue_file_operations;
 			inode->i_size = FILENT_SIZE;
@@ -123,8 +127,10 @@ static struct inode *mqueue_get_inode(st
 			init_waitqueue_head(&info->wait_q);
 			INIT_LIST_HEAD(&info->e_wait_q[0].list);
 			INIT_LIST_HEAD(&info->e_wait_q[1].list);
+			info->messages = NULL;
 			info->notify_owner = 0;
 			info->qsize = 0;
+			info->user = NULL;	/* set when all is ok */
 			memset(&info->attr, 0, sizeof(info->attr));
 			info->attr.mq_maxmsg = DFLT_MSGMAX;
 			info->attr.mq_msgsize = DFLT_MSGSIZEMAX;
@@ -132,12 +138,29 @@ static struct inode *mqueue_get_inode(st
 				info->attr.mq_maxmsg = attr->mq_maxmsg;
 				info->attr.mq_msgsize = attr->mq_msgsize;
 			}
-			info->messages = kmalloc(info->attr.mq_maxmsg * sizeof(struct msg_msg *), GFP_KERNEL);
+			mq_msg_tblsz = info->attr.mq_maxmsg * sizeof(struct msg_msg *);
+			mq_bytes = (mq_msg_tblsz +
+				(info->attr.mq_maxmsg * info->attr.mq_msgsize));
+
+			spin_lock(&mq_lock);
+			if (u->mq_bytes + mq_bytes < u->mq_bytes ||
+		 	    u->mq_bytes + mq_bytes >
+			    p->rlim[RLIMIT_MSGQUEUE].rlim_cur) {
+				spin_unlock(&mq_lock);
+				goto out_inode;
+			}
+			u->mq_bytes += mq_bytes;
+			spin_unlock(&mq_lock);
+
+			info->messages = kmalloc(mq_msg_tblsz, GFP_KERNEL);
 			if (!info->messages) {
-				make_bad_inode(inode);
-				iput(inode);
-				inode = NULL;
+				spin_lock(&mq_lock);
+				u->mq_bytes -= mq_bytes;
+				spin_unlock(&mq_lock);
+				goto out_inode;
 			}
+			/* all is ok */
+			info->user = get_uid(u);
 		} else if (S_ISDIR(mode)) {
 			inode->i_nlink++;
 			/* Some things misbehave if size == 0 on a directory */
@@ -147,6 +170,10 @@ static struct inode *mqueue_get_inode(st
 		}
 	}
 	return inode;
+out_inode:
+	make_bad_inode(inode);
+	iput(inode);
+	return NULL;
 }
 
 static int mqueue_fill_super(struct super_block *sb, void *data, int silent)
@@ -205,6 +232,8 @@ static void mqueue_destroy_inode(struct 
 static void mqueue_delete_inode(struct inode *inode)
 {
 	struct mqueue_inode_info *info;
+	struct user_struct *user;
+	unsigned long mq_bytes;
 	int i;
 
 	if (S_ISDIR(inode->i_mode)) {
@@ -220,10 +249,15 @@ static void mqueue_delete_inode(struct i
 
 	clear_inode(inode);
 
-	if (info->messages) {
+	mq_bytes = (info->attr.mq_maxmsg * sizeof(struct msg_msg *) +
+		   (info->attr.mq_maxmsg * info->attr.mq_msgsize));
+	user = info->user;
+	if (user) {
 		spin_lock(&mq_lock);
+		user->mq_bytes -= mq_bytes;
 		queues_count--;
 		spin_unlock(&mq_lock);
+		free_uid(user);
 	}
 }
 

_
