[PATCH 1/1] ipc/mqueue.c: Drag unneeded code out of locks

From: Steven Stewart-Gallus
Date: Fri Nov 07 2014 - 01:40:56 EST


This shouldn't be too controversial. I simply looked for where there
was a tiny bit of waste in the message queue code.

Signed-off-by: Steven Stewart-Gallus <sstewartgallus00@xxxxxxxxxxxxxxx>
---
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 4fcf39a..aa3f903 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -278,16 +278,29 @@ static struct inode *mqueue_get_inode(struct super_block *sb,
mq_bytes = mq_treesize + (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 > rlimit(RLIMIT_MSGQUEUE)) {
+ {
+ bool too_many_open_files;
+ long msgqueue_lim;
+ unsigned long u_bytes;
+
+ msgqueue_lim = rlimit(RLIMIT_MSGQUEUE);
+
+ spin_lock(&mq_lock);
+
+ u_bytes = u->mq_bytes;
+ too_many_open_files = u_bytes + mq_bytes < u_bytes ||
+ u_bytes + mq_bytes > msgqueue_lim;
+ if (!too_many_open_files)
+ u->mq_bytes += mq_bytes;
+
spin_unlock(&mq_lock);
+
/* mqueue_evict_inode() releases info->messages */
- ret = -EMFILE;
- goto out_inode;
+ if (too_many_open_files) {
+ ret = -EMFILE;
+ goto out_inode;
+ }
}
- u->mq_bytes += mq_bytes;
- spin_unlock(&mq_lock);

/* all is ok */
info->user = get_uid(u);
@@ -423,44 +436,60 @@ static int mqueue_create(struct inode *dir, struct dentry
*dentry,
umode_t mode, bool excl)
{
struct inode *inode;
- struct mq_attr *attr = dentry->d_fsdata;
- int error;
+ struct mq_attr *attr;
struct ipc_namespace *ipc_ns;
+ int error = 0;
+
+ if (!capable(CAP_SYS_RESOURCE)) {
+ error = -ENOSPC;
+ goto finish;
+ }
+
+ attr = dentry->d_fsdata;

spin_lock(&mq_lock);
ipc_ns = __get_ns_from_inode(dir);
if (!ipc_ns) {
error = -EACCES;
- goto out_unlock;
+ goto unlock_mq;
}

- if (ipc_ns->mq_queues_count >= ipc_ns->mq_queues_max &&
- !capable(CAP_SYS_RESOURCE)) {
+ if (ipc_ns->mq_queues_count >= ipc_ns->mq_queues_max) {
error = -ENOSPC;
- goto out_unlock;
+ goto unlock_mq;
}
ipc_ns->mq_queues_count++;
+unlock_mq:
spin_unlock(&mq_lock);

+ if (error != 0)
+ goto put_ipc_ns;
+
inode = mqueue_get_inode(dir->i_sb, ipc_ns, mode, attr);
if (IS_ERR(inode)) {
error = PTR_ERR(inode);
+
spin_lock(&mq_lock);
ipc_ns->mq_queues_count--;
- goto out_unlock;
+ spin_unlock(&mq_lock);
+
+ goto put_ipc_ns;
}

- put_ipc_ns(ipc_ns);
+put_ipc_ns:
+ if (ipc_ns)
+ put_ipc_ns(ipc_ns);
+
+ if (error != 0)
+ goto finish;
+
dir->i_size += DIRENT_SIZE;
dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME;

d_instantiate(dentry, inode);
dget(dentry);
- return 0;
-out_unlock:
- spin_unlock(&mq_lock);
- if (ipc_ns)
- put_ipc_ns(ipc_ns);
+
+finish:
return error;
}

@@ -485,26 +514,39 @@ static int mqueue_unlink(struct inode *dir, struct dentry
*dentry)
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(file_inode(filp));
- char buffer[FILENT_SIZE];
ssize_t ret;
+ pid_t notify_owner;
+ unsigned long qsize;
+ struct sigevent notify;

- 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 : 0,
- (info->notify_owner &&
- info->notify.sigev_notify == SIGEV_SIGNAL) ?
- info->notify.sigev_signo : 0,
- pid_vnr(info->notify_owner));
- spin_unlock(&info->lock);
- buffer[sizeof(buffer)-1] = '\0';
+ {
+ struct mqueue_inode_info *info = MQUEUE_I(file_inode(filp));

- ret = simple_read_from_buffer(u_data, count, off, buffer,
- strlen(buffer));
- if (ret <= 0)
- return ret;
+ spin_lock(&info->lock);
+ notify_owner = pid_vnr(info->notify_owner);
+ notify = info->notify;
+ qsize = info->qsize;
+ spin_unlock(&info->lock);
+ }
+
+ {
+ char buffer[FILENT_SIZE];
+
+ snprintf(buffer, sizeof(buffer),
+ "QSIZE:%-10lu NOTIFY:%-5d SIGNO:%-5d NOTIFY_PID:%-6d\n",
+ qsize,
+ notify_owner ? notify.sigev_notify : 0,
+ (notify_owner &&
+ notify.sigev_notify == SIGEV_SIGNAL) ?
+ notify.sigev_signo : 0,
+ notify_owner);
+ buffer[sizeof(buffer)-1] = '\0';
+
+ ret = simple_read_from_buffer(u_data, count, off, buffer,
+ strlen(buffer));
+ if (ret <= 0)
+ return ret;
+ }

file_inode(filp)->i_atime = file_inode(filp)->i_ctime = CURRENT_TIME;
return ret;
@@ -524,18 +566,26 @@ static int mqueue_flush_file(struct file *filp, fl_owner_t id)

static unsigned int mqueue_poll_file(struct file *filp, struct
poll_table_struct *poll_tab)
{
- struct mqueue_inode_info *info = MQUEUE_I(file_inode(filp));
int retval = 0;
+ unsigned long curmsgs;
+ unsigned long maxmsg;

- poll_wait(filp, &info->wait_q, poll_tab);
+ {
+ struct mqueue_inode_info *info = MQUEUE_I(file_inode(filp));

- spin_lock(&info->lock);
- if (info->attr.mq_curmsgs)
+ poll_wait(filp, &info->wait_q, poll_tab);
+
+ spin_lock(&info->lock);
+ curmsgs = info->attr.mq_curmsgs;
+ maxmsg = info->attr.mq_maxmsg;
+ spin_unlock(&info->lock);
+ }
+
+ if (curmsgs)
retval = POLLIN | POLLRDNORM;

- if (info->attr.mq_curmsgs < info->attr.mq_maxmsg)
+ if (curmsgs < maxmsg)
retval |= POLLOUT | POLLWRNORM;
- spin_unlock(&info->lock);

return retval;
}

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/