Esempio n. 1
0
Req*
allocreq(Reqpool *pool, ulong tag)
{
    Req *r;

    r = emalloc9p(sizeof *r);
    r->tag = tag;
    r->pool = pool;

    increqref(r);
    increqref(r);
    if(caninsertkey(pool->map, tag, r) == 0) {
        closereq(r);
        closereq(r);
        return nil;
    }

    return r;
}
Esempio n. 2
0
void
needkeyflush(Req *r)
{
	Req **l;

	for(l=&needwait; *l; l=&(*l)->aux){
		if(*l == r){
			*l = r->aux;
			if(r->aux == nil)
				needlast = l;
			closereq(r);
			break;
		}
	}
	logbufflush(&needkeybuf, r);
}
Esempio n. 3
0
void
confirmflush(Req *r)
{
	Req **l;

	for(l=&cusewait; *l; l=&(*l)->aux){
		if(*l == r){
			*l = r->aux;
			if(r->aux == nil)
				cuselast = l;
			closereq(r);
			break;
		}
	}
	logbufflush(&confbuf, r);
}
Esempio n. 4
0
File: srv.c Progetto: 99years/plan9
static int
rflush(Req *r, char *error)
{
	Req *or;

	assert(error == nil);
	or = r->oldreq;
	if(or){
		qlock(&or->lk);
		if(or->responded == 0){
			or->flush = erealloc9p(or->flush, (or->nflush+1)*sizeof(or->flush[0]));
			or->flush[or->nflush++] = r;
			qunlock(&or->lk);
			return -1;		/* delay response until or is responded */
		}
		qunlock(&or->lk);
		closereq(or);
	}
	r->oldreq = nil;
	return 0;
}
Esempio n. 5
0
File: req.c Progetto: 99years/plan9
void
closereq(Req *r)
{
	int i;

	if(r == nil)
		return;

if(chatty9p > 1)
	fprint(2, "closereq %p %d\n", r, r->ref.ref);

	if(decref(&r->ref) == 0){
		if(r->fid)
			closefid(r->fid);
		if(r->newfid)
			closefid(r->newfid);
		if(r->afid)
			closefid(r->afid);
		if(r->oldreq)
			closereq(r->oldreq);
		for(i=0; i<r->nflush; i++)
			respond(r->flush[i], nil);
		free(r->flush);
		switch(r->ifcall.type){
		case Tstat:
			free(r->ofcall.stat);
			free(r->d.name);
			free(r->d.uid);
			free(r->d.gid);
			free(r->d.muid);
			break;
		}
		if(r->pool->destroy)
			r->pool->destroy(r);
		free(r->buf);
		free(r->rbuf);
		free(r);
	}
}
Esempio n. 6
0
void
closereq(Req *r)
{
    if(r == nil)
        return;

    if(chatty9p > 1)
        fprint(2, "closereq %p %ld\n", r, r->ref.ref);

    if(decref(&r->ref) == 0) {
        if(r->fid)
            closefid(r->fid);
        if(r->newfid)
            closefid(r->newfid);
        if(r->afid)
            closefid(r->afid);
        if(r->oldreq)
            closereq(r->oldreq);
        if(r->nflush)
            fprint(2, "closereq: flushes remaining\n");
        free(r->flush);
        switch(r->ifcall.type) {
        case Tstat:
            free(r->ofcall.stat);
            free(r->d.name);
            free(r->d.uid);
            free(r->d.gid);
            free(r->d.muid);
            break;
        }
        if(r->pool->destroy)
            r->pool->destroy(r);
        free(r->buf);
        free(r->rbuf);
        free(r);
    }
}
Esempio n. 7
0
File: srv.c Progetto: 99years/plan9
void
respond(Req *r, char *error)
{
	int i, m, n;
	char errbuf[ERRMAX];
	Srv *srv;

	srv = r->srv;
	assert(srv != nil);

	if(r->responded){
		assert(r->pool);
		goto free;
	}
		
	assert(r->responded == 0);
	r->error = error;

	switch(r->ifcall.type){
	default:
		assert(0);
	/*
	 * Flush is special.  If the handler says so, we return
	 * without further processing.  Respond will be called
	 * again once it is safe.
	 */
	case Tflush:
		if(rflush(r, error)<0)
			return;
		break;
	case Tversion:	rversion(r, error);	break;
	case Tauth:	rauth(r, error);	break;
	case Tattach:	rattach(r, error);	break;
	case Twalk:	rwalk(r, error);	break;
	case Topen:	ropen(r, error);	break;
	case Tcreate:	rcreate(r, error);	break;
	case Tread:	rread(r, error);	break;
	case Twrite:	rwrite(r, error);	break;
	case Tclunk:	rclunk(r, error);	break;
	case Tremove:	rremove(r, error, errbuf);	break;
	case Tstat:	rstat(r, error);	break;
	case Twstat:	rwstat(r, error);	break;
	}

	r->ofcall.tag = r->ifcall.tag;
	r->ofcall.type = r->ifcall.type+1;
	if(r->error)
		setfcallerror(&r->ofcall, r->error);

if(chatty9p)
	fprint(2, "-%d-> %F\n", srv->outfd, &r->ofcall);

	qlock(&srv->wlock);
	n = convS2M(&r->ofcall, srv->wbuf, srv->msize);
	if(n <= 0){
		fprint(2, "n = %d %F\n", n, &r->ofcall);
		abort();
	}
	assert(n > 2);
	/*
	 * There is a race here - we must remove the entry before
	 * the write, so that if the client is very fast and reuses the
	 * tag, the read loop won't think it is still in use.
	 * 
	 * By removing the entry before the write, we open up a 
	 * race with incoming Tflush messages.  Specifically, an
	 * incoming Tflush might not see r even though it has not
	 * yet been responded to.  It would then send an Rflush
	 * immediately, potentially before we do the write.  This can't
	 * happen because we already old srv->wlock, so nothing
	 * is going out on the wire before this write.
	 */
	if(r->pool)	/* not a fake */
		closereq(removereq(r->pool, r->ifcall.tag));

	qlock(&r->lk);
	r->responded = 1;
	if(r->pool)
	if(r->ref.ref == 1+r->nflush)
	if(r->fid){
		/*
		 * There are no references other than in our r->flush array,
		 * so no one else should be accessing r concurrently.
		 * Close the fid now, before responding to the message.
		 * 
		 * If the client is behaving (there are no outstanding T-messages
		 * that reference r->fid) and the message is a Tclunk or Tremove,
		 * then this closefid will call destroyfid.  
		 * 
		 * This means destroyfid can't piddle around 
		 * indefinitely (we're holding srv->wlock!), but it provides
		 * for tighter semantics as to when destroyfid is called.
		 *
		 * LANL has observed cases where waiting until after the write
		 * can delay a closefid on a Twrite for many 9P transactions,
		 * so that a handful of transactions can happen including a Tclunk
		 * and a Topen, and the original fid will still not be destroyed.
		 */
		closefid(r->fid);
		r->fid = nil;
	}
	qunlock(&r->lk);
	m = write(srv->outfd, srv->wbuf, n);
	if(m != n)
		sysfatal("lib9p srv: write %d returned %d on fd %d: %r", n, m, srv->outfd);
	qunlock(&srv->wlock);

free:
	qlock(&r->lk);	/* no one will add flushes now */

	for(i=0; i<r->nflush; i++){
		r->flush[i]->oldreq = nil;	/* so it doesn't try to lock us! */
		respond(r->flush[i], nil);
	}
	free(r->flush);
	r->flush = nil;
	r->nflush = 0;
	qunlock(&r->lk);

	if(r->pool)
		closereq(r);
	else
		free(r);
}
Esempio n. 8
0
File: srv.c Progetto: npe9/harvey
void
respond(Req *r, char *error)
{
	int i, m, n;
	char errbuf[ERRMAX];
	Srv *srv;

	srv = r->srv;
	assert(srv != nil);

	assert(r->responded == 0);
	r->error = error;

	switch(r->ifcall.type){
	default:
		assert(0);
	/*
	 * Flush is special.  If the handler says so, we return
	 * without further processing.  Respond will be called
	 * again once it is safe.
	 */
	case Tflush:
		if(rflush(r, error)<0)
			return;
		break;
	case Tversion:	rversion(r, error);	break;
	case Tauth:	rauth(r, error);	break;
	case Tattach:	rattach(r, error);	break;
	case Twalk:	rwalk(r, error);	break;
	case Topen:	ropen(r, error);	break;
	case Tcreate:	rcreate(r, error);	break;
	case Tread:	rread(r, error);	break;
	case Twrite:	rwrite(r, error);	break;
	case Tclunk:	rclunk(r, error);	break;
	case Tremove:	rremove(r, error, errbuf);	break;
	case Tstat:	rstat(r, error);	break;
	case Twstat:	rwstat(r, error);	break;
	}

	r->ofcall.tag = r->ifcall.tag;
	r->ofcall.type = r->ifcall.type+1;
	if(r->error)
		setfcallerror(&r->ofcall, r->error);

if(chatty9p)
	fprint(2, "-%d-> %F\n", srv->outfd, &r->ofcall);

	qlock(&srv->wlock);
	n = convS2M(&r->ofcall, srv->wbuf, srv->msize);
	if(n <= 0){
		fprint(2, "n = %d %F\n", n, &r->ofcall);
		abort();
	}
	assert(n > 2);
	if(r->pool)	/* not a fake */
		closereq(removereq(r->pool, r->ifcall.tag));
	m = write(srv->outfd, srv->wbuf, n);
	if(m != n)
		sysfatal("lib9p srv: write %d returned %d on fd %d: %r", n, m, srv->outfd);
	qunlock(&srv->wlock);

	qlock(&r->lk);	/* no one will add flushes now */
	r->responded = 1;
	qunlock(&r->lk);

	for(i=0; i<r->nflush; i++)
		respond(r->flush[i], nil);
	free(r->flush);
	r->flush = nil;
	r->nflush = 0;

	if(r->pool)
		closereq(r);
	else
		free(r);
}