Re: /selinux/create + X windows = performance limiter

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, 2009-02-25 at 16:34 -0500, Eric Paris wrote:
> On Wed, 2009-02-25 at 16:14 -0500, Stephen Smalley wrote:
> > On Wed, 2009-02-25 at 15:50 -0500, Eric Paris wrote:
> > > So the X people here at Red Hat complained the other day that they have
> > > to do an open, write, read, close very very often on /selinux/create.
> > > They'd like to cut the number of syscalls down.  Even if the open and
> > > close are fast, they are still syscalls that still take time and still
> > > provide maximum limits on the operations per second they can do.  (I
> > > think ajax said he was estimating it at 10000/sec, but I don't remember
> > > the math or even if it was reasonable)
> > > 
> > > We've got 2 choices.  We could reduce the number of syscalls to 3 by
> > > adding another operation, maybe an ioctl, that would reset the
> > > transaction.  X could keep the file open indeffinitely and instead use
> > > an open, write, read, ioctl, write read, ioctl, etc callpath.
> > > 
> > > We could also reduce the number of syscalls needed to 2. We could just
> > > say that after a full read we reset the transaction.  So the process
> > > would look like open, write, read, write, read, write, read, etc....
> > > 
> > > Does anyone see a problem with going to the 2 syscall kernel interface?
> > > Userspace which uses the library shouldn't even notice since the library
> > > (I believe) takes care of the open, write, read, close chain and would
> > > continue to work properly.
> > > 
> > > If the X people can really show that this call chain makes a big
> > > performance difference I'm sure we could come up with other ways to
> > > speed things up (crazy things that sds would hate like exposing internal
> > > sids to userspace and passing those back and forth across a new boundary
> > > for fast in kernel operations.  But for now, just stopping opening and
> > > closing a file 1000s of times a second seems like an easy, obvious, and
> > > reasonable win.
> > 
> > Wouldn't it be simpler and more efficient to just start caching the
> > results of security_compute_create in the AVC so that
> > avc_compute_create() will get most answers from the cache, just like
> > avc_has_perm()?
> 
> I like how you respond to my "future work" part first  :)   I'll take a
> look at caching these results but before I put much into what I can't
> clearly say would be a win, I'm going to have to get some read perf data
> showing where in selinux code we are spending time....

I think you'll get the biggest win from having the userspace AVC cache
the compute_create results.  Shouldn't be hard.

> > BTW, as I recall, the transaction ops don't actually require a separate
> > write() + read() pair; they can be combined into a single call that does
> > both request + response transfer.
> 
> What syscall would we use to send the info pack and forth?  don't say
> ioctl, don't say ioctl, don't say ioctl......

No, just read().  Something along these lines would allow a single
read() call to both submit the request and collect the response, as long
as the buffer is large enough for both.

diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 01ec6d2..9a5d2a8 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -544,9 +544,20 @@ static ssize_t selinux_transaction_write(struct file *file, const char __user *b
 	return rv;
 }
 
+static ssize_t selinux_transaction_read(struct file *file, char __user *buf, size_t size, loff_t *pos)
+{
+	if (!file->private_data) {
+		ssize_t rv = selinux_transaction_write(file, buf, size, pos);
+		if (rv < 0)
+			return rv;
+	}
+	return simple_transaction_read(file, buf, size, pos);
+
+}
+
 static const struct file_operations transaction_ops = {
 	.write		= selinux_transaction_write,
-	.read		= simple_transaction_read,
+	.read		= selinux_transaction_read,
 	.release	= simple_transaction_release,
 };

Some might object to this however on the grounds that read(2) isn't
supposed to do anything with the initial contents of buf.

nfsctl does something similar to allow a read() without a prior write()
to get status information but it only does a 0-byte write so it isn't
actually using the buffer contents.

I'm not sure though that we'd gain much in performance from this.
Eliminating the need for open/close on each transaction is likely to be
more significant as you say.  I'd start with the userspace AVC though
because that offers the best situation - no need for any syscalls when
the result has previously been computed.
 
-- 
Stephen Smalley
National Security Agency


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@xxxxxxxxxxxxx with
the words "unsubscribe selinux" without quotes as the message.

[Index of Archives]     [Selinux Refpolicy]     [Linux SGX]     [Fedora Users]     [Fedora Desktop]     [Yosemite Photos]     [Yosemite Camping]     [Yosemite Campsites]     [KDE Users]     [Gnome Users]

  Powered by Linux