Allow Qlistens to be partially opened with O_PATH
authorBarret Rhoden <brho@cs.berkeley.edu>
Fri, 11 Sep 2015 16:01:16 +0000 (12:01 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 28 Sep 2015 19:14:00 +0000 (15:14 -0400)
This gives us an FD that actually points to Qlisten.  Otherwise, when
you do a full open of Qlisten, you get a chan that points to a new
conversation that you listened for.  With this FD, we'll be able to tap
Qlisten to find out about new conversations (epoll).

There's a few things I don't understand about how #I interacts with 9ns
and what the rules are.  For instance, you can namec to get a chan that
points to an object.  Now your chan has a QID and a device, uniquely
identifying the object.  Once you have that, are you supposed to have a
reference to the object that does not disappear until the chan is
released?  That would make sense.  Note that 9ns will call the device's
close() method on the chan, including chans that were not actually
opened.  #I deals with this by checking c->flags for COPEN so that it
only calls closeconv on chans that called ipopen().

That's also not what seems to happen with #I; there's no permanence
between gen and open.  ipgen will create conversation directories up to
"ac", which is the number of active conversations.  That seems to be the
only check in ipgen, and there's nothing that keeps those conversations
alive.  That's probably why we have a high water mark of conversations
in #I: once created, they are around forever.  Their status might just
change.

I think it is possible to namec/ipgen a chan for something like ctl,
data, or now listen and get the "wrong" conversation.  Say we gen a chan
for "data" for a conversation, but do not open it.  Then that
conversation closes (or it can even be closed already), and then a new
thread opens "clone" and gets a new conversation that has the same QID
as the genned chan.  (Here, Fsprotoclone checks inuse, but inuse is 0
still).  Then the genned chan is opened, and we now have an FD pointing
to a chan that is pointing to a conversation that wasn't the
conversation we originally asked for.

One way to think about this is "you asked for tcp/1/data, that's what
you get.  There's no guarantee that that conversation is the one you
actually want."

Anyway, you can now do that same thing with "listen".

Oh, and be careful if you try to hang refcnted blobs off c->aux.  I
tried that a while ago with #s and it was a nightmare.  Maybe it can
work, but again, the rules for how everything works are not clear.

kern/src/net/devip.c

index eabfe7f..c1b7278 100644 (file)
@@ -462,6 +462,22 @@ static struct chan *ipopen(struct chan *c, int omode)
                        break;
                case Qlisten:
                        cv = f->p[PROTO(c->qid)]->conv[CONV(c->qid)];
+                       /* No permissions or Announce checks required.  We'll see if that's
+                        * a good idea or not. (the perm check would do nothing, as is,
+                        * since an O_PATH perm is 0).
+                        *
+                        * But we probably want to incref to keep the conversation around
+                        * until this FD/chan is closed.  #I is a little weird in that
+                        * objects never really go away (high water mark for convs, you can
+                        * always find them in the ns).  I think it is possible to
+                        * namec/ipgen a chan, then have that conv close, then have that
+                        * chan be opened.  You can probably do this with a data file. */
+                       if (omode & O_PATH) {
+                               qlock(&cv->qlock);
+                               cv->inuse++;
+                               qunlock(&cv->qlock);
+                               break;
+                       }
                        if ((perm & (cv->perm >> 6)) != perm) {
                                if (strcmp(ATTACHER(c), cv->owner) != 0)
                                        error(Eperm);