#define CTL_MSGSIZEMAX 4
/* default values */
-#define DFLT_QUEUESMAX 64 /* max number of message queues */
-#define DFLT_MSGMAX 40 /* max number of messages in each queue */
+#define DFLT_QUEUESMAX 256 /* max number of message queues */
+#define DFLT_MSGMAX 10 /* max number of messages in each queue */
#define HARD_MSGMAX (131072/sizeof(void*))
-#define DFLT_MSGSIZEMAX 16384 /* max message size */
+#define DFLT_MSGSIZEMAX 8192 /* max message size */
#define NOTIFY_COOKIE_LEN 32
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;
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;
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;
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 */
}
}
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)
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)) {
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);
}
}
info->notify_owner = 0;
}
+static int mq_attr_ok(struct mq_attr *attr)
+{
+ if (attr->mq_maxmsg <= 0 || attr->mq_msgsize <= 0)
+ return 0;
+ if (capable(CAP_SYS_RESOURCE)) {
+ if (attr->mq_maxmsg > HARD_MSGMAX)
+ return 0;
+ } else {
+ if (attr->mq_maxmsg > msg_max ||
+ attr->mq_msgsize > msgsize_max)
+ return 0;
+ }
+ /* check for overflow */
+ if (attr->mq_msgsize > ULONG_MAX/attr->mq_maxmsg)
+ return 0;
+ if ((unsigned long)(attr->mq_maxmsg * attr->mq_msgsize) +
+ (attr->mq_maxmsg * sizeof (struct msg_msg *)) <
+ (unsigned long)(attr->mq_maxmsg * attr->mq_msgsize))
+ return 0;
+ return 1;
+}
+
/*
* Invoked when creating a new queue via sys_mq_open
*/
if (u_attr != NULL) {
if (copy_from_user(&attr, u_attr, sizeof(attr)))
return ERR_PTR(-EFAULT);
-
- if (attr.mq_maxmsg <= 0 || attr.mq_msgsize <= 0)
+ if (!mq_attr_ok(&attr))
return ERR_PTR(-EINVAL);
- if (capable(CAP_SYS_RESOURCE)) {
- if (attr.mq_maxmsg > HARD_MSGMAX)
- return ERR_PTR(-EINVAL);
- } else {
- if (attr.mq_maxmsg > msg_max ||
- attr.mq_msgsize > msgsize_max)
- return ERR_PTR(-EINVAL);
- }
/* store for use during create */
dentry->d_fsdata = &attr;
}