patch: remove some lock contention in sys_readv, sys_writev

Gideon Glass (gid@wombat.sbt.net)
Thu, 21 Oct 1999 17:08:53 -0500 (CDT)


Here's a patch against 2.3.19 that removes lock_kernel()/unlock_kernel()
in sys_readv/sys_writev for the case where socket I/O is occurring and where
the IOV array fits on the stack. I'm pretty sure this is OK to do
because sock_read and sock_write (which are called without kernel_flag) are so
similar to sock_readv_writev.

Background: I'm working with some web proxy cache software that ends up
doing a lot of writev's to sockets. We're using the lockstat/lockmeter
patch that was recently posted to linux-kernel to measure lock contention.
On a dual processor machine running 2 independent proxy processes, kernel_flag
contention was taking up about 30% of time before this patch. After the
patch it's closer to 10-15%. kernel_flag contention, which is the bulk of
all contention we see, still occurs in sock_alloc, do_close, sock_poll, and
a few other places.

One bit of paranoia.. in the case where kmalloc needs to be called, I
go back and call lock_kernel, since I'm not positive that kmalloc can
be called without the kernel being locked. This might be too
conservative.

gid

--- linux-2.3.19.orig/fs/read_write.c Tue Sep 7 12:22:12 1999
+++ linux-2.3.19.gid/fs/read_write.c Wed Oct 20 16:57:43 1999
@@ -173,6 +173,7 @@
ssize_t ret, i;
io_fn_t fn;
struct inode *inode;
+ int locked;

/*
* First get the "struct iovec" from user memory and
@@ -186,10 +187,22 @@
goto out_nofree;
if (count > UIO_FASTIOV) {
ret = -ENOMEM;
+ lock_kernel();
iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
- if (!iov)
+ if (!iov) {
+ unlock_kernel();
goto out_nofree;
+ }
+ locked = 1;
+ } else {
+ locked = 0;
}
+
+ /*
+ * after this point, if the kernel lock is held, then locked === 1;
+ * also, after this point, you can't jump to out_nofree.
+ */
+
ret = -EFAULT;
if (copy_from_user(iov, vector, count*sizeof(*vector)))
goto out;
@@ -214,6 +227,11 @@
ret = sock_readv_writev(type,inode,file,iov,count,tot_len);
goto out;
}
+
+ if (!locked) {
+ locked = 1;
+ lock_kernel();
+ }

ret = -EINVAL;
if (!file->f_op)
@@ -248,6 +266,8 @@
}

out:
+ if (locked)
+ unlock_kernel();
if (iov != iovstack)
kfree(iov);
out_nofree:
@@ -260,7 +280,7 @@
struct file * file;
ssize_t ret;

- lock_kernel();
+ /* lock_kernel(); */

ret = -EBADF;
file = fget(fd);
@@ -271,7 +291,7 @@
fput(file);

bad_file:
- unlock_kernel();
+ /* unlock_kernel(); */
return ret;
}

@@ -281,7 +301,7 @@
struct file * file;
ssize_t ret;

- lock_kernel();
+ /* lock_kernel(); */

ret = -EBADF;
file = fget(fd);
@@ -293,7 +313,7 @@
fput(file);

bad_file:
- unlock_kernel();
+ /* unlock_kernel(); */
return ret;
}

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