Skip to content

Commit

Permalink
9p/net: make flush asynchronous
Browse files Browse the repository at this point in the history
Make the client flush asynchronous so we don't need to ignore signals in
rpc functions:
 - on signal, send a flush request as we previously did but use the new
asynchronous helper and return immediately
 - when the reply has been received or connection is destroyed, free
both tags in the handler

Link: http://lkml.kernel.org/r/1544532108-21689-3-git-send-email-asmadeus@codewreck.org
Signed-off-by: Dominique Martinet <dominique.martinet@cea.fr>
Reviewed-by: Tomas Bortoli <tomasbortoli@gmail.com>
Cc: Dmitry Vyukov <dvyukov@google.com>
  • Loading branch information
Dominique Martinet committed Jun 25, 2020
1 parent b1d37de commit 62cca28
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 96 deletions.
2 changes: 2 additions & 0 deletions include/net/9p/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ enum p9_req_status_t {
* @rc: the response fcall structure
* @req_list: link for transports to chain requests (used by trans_fd)
* @async_list: link used to check on async requests
* @flushed_req: for flush, points to matching flushed req
* @clunked_fid: for clunk, points to fid
*/
struct p9_req_t {
Expand All @@ -87,6 +88,7 @@ struct p9_req_t {
struct list_head req_list;
struct list_head async_list;
union {
struct p9_req_t *flushed_req;
struct p9_fid *clunked_fid;
};
};
Expand Down
172 changes: 76 additions & 96 deletions net/9p/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -680,50 +680,6 @@ static void p9_fid_destroy(struct p9_fid *fid)
kfree(fid);
}

static struct p9_req_t *
p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...);

/**
* p9_client_flush - flush (cancel) a request
* @c: client state
* @oldreq: request to cancel
*
* This sents a flush for a particular request and links
* the flush request to the original request. The current
* code only supports a single flush request although the protocol
* allows for multiple flush requests to be sent for a single request.
*
*/

static int p9_client_flush(struct p9_client *c, struct p9_req_t *oldreq)
{
struct p9_req_t *req;
int16_t oldtag;
int err;

err = p9_parse_header(&oldreq->tc, NULL, NULL, &oldtag, 1);
if (err)
return err;

p9_debug(P9_DEBUG_9P, ">>> TFLUSH tag %d\n", oldtag);

req = p9_client_rpc(c, P9_TFLUSH, "w", oldtag);
if (IS_ERR(req))
return PTR_ERR(req);

/*
* if we haven't received a response for oldreq,
* remove it from the list
*/
if (oldreq->status == REQ_STATUS_SENT) {
if (c->trans_mod->cancelled)
c->trans_mod->cancelled(c, oldreq);
}

p9_tag_remove(c, req);
return 0;
}

static struct p9_req_t *p9_client_prepare_req(struct p9_client *c,
int8_t type, int req_size,
const char *fmt, va_list ap)
Expand Down Expand Up @@ -786,6 +742,39 @@ p9_client_async_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
return req;
}

/**
* p9_client_flush - flush (cancel) a request
* @c: client state
* @oldreq: request to cancel
*
* This sents a flush for a particular request and links
* the flush request to the original request. The current
* code only supports a single flush request although the protocol
* allows for multiple flush requests to be sent for a single request.
*
*/

static int p9_client_flush(struct p9_client *c, struct p9_req_t *oldreq)
{
struct p9_req_t *req;
int16_t oldtag = oldreq->tc.tag;

p9_debug(P9_DEBUG_9P, ">>> TFLUSH tag %d\n", oldtag);
req = p9_client_async_rpc(c, P9_TFLUSH, "w", oldtag);
if (IS_ERR(req)) {
return PTR_ERR(req);
}

p9_debug(P9_DEBUG_MUX, "sent flush for oldreq %d type %d with flush tag %d\n",
oldtag, oldreq->tc.id, req->tc.tag);
req->flushed_req = oldreq;
spin_lock_irq(&c->lock);
list_add(&req->async_list, &c->async_req_list);
spin_unlock_irq(&c->lock);

return 0;
}

static void p9_client_handle_async(struct p9_client *c, bool free_all)
{
struct p9_req_t *req, *nreq;
Expand All @@ -809,6 +798,24 @@ static void p9_client_handle_async(struct p9_client *c, bool free_all)
}
if (free_all || req->status >= REQ_STATUS_RCVD) {
/* Put old refs whatever reqs actually returned */
if (req->tc.id == P9_TFLUSH) {
p9_debug(P9_DEBUG_MUX,
"flushing oldreq tag %d status %d, flush_req tag %d\n",
req->flushed_req->tc.tag,
req->flushed_req->status,
req->tc.tag);
if (req->flushed_req->status < REQ_STATUS_RCVD) {
/* won't receive reply now */
if (c->trans_mod->cancelled)
c->trans_mod->cancelled(c, req);
p9_req_put(req->flushed_req);
}
if (!p9_tag_remove(c, req->flushed_req))
p9_debug(P9_DEBUG_ERROR,
"oldreq tag %d status %d still has ref\n",
req->flushed_req->tc.tag,
req->flushed_req->status);
}
if (req->tc.id == P9_TCLUNK) {
p9_fid_destroy(req->clunked_fid);
}
Expand All @@ -832,8 +839,8 @@ static struct p9_req_t *
p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
{
va_list ap;
int sigpending, err;
unsigned long flags;
int err;
int flushing = 0;
struct p9_req_t *req;

p9_client_handle_async(c, 0);
Expand All @@ -845,20 +852,21 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
return req;

if (signal_pending(current)) {
sigpending = 1;
clear_thread_flag(TIF_SIGPENDING);
} else
sigpending = 0;
err = -ERESTARTSYS;
/* write won't happen */
p9_req_put(req);
goto reterr;
}

err = c->trans_mod->request(c, req);
if (err < 0) {
/* write won't happen */
p9_req_put(req);
if (err != -ERESTARTSYS && err != -EFAULT)
c->status = Disconnected;
goto recalc_sigpending;
goto reterr;
}
again:

/* Wait for the response */
err = wait_event_killable(req->wq, req->status >= REQ_STATUS_RCVD);

Expand All @@ -868,34 +876,15 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
*/
smp_rmb();

if ((err == -ERESTARTSYS) && (c->status == Connected)
&& (type == P9_TFLUSH)) {
sigpending = 1;
clear_thread_flag(TIF_SIGPENDING);
goto again;
}

if (req->status == REQ_STATUS_ERROR) {
p9_debug(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err);
err = req->t_err;
}
if ((err == -ERESTARTSYS) && (c->status == Connected)) {
p9_debug(P9_DEBUG_MUX, "flushing\n");
sigpending = 1;
clear_thread_flag(TIF_SIGPENDING);

if (c->trans_mod->cancel(c, req))
p9_client_flush(c, req);

/* if we received the response anyway, don't signal error */
if (req->status == REQ_STATUS_RCVD)
err = 0;
}
recalc_sigpending:
if (sigpending) {
spin_lock_irqsave(&current->sighand->siglock, flags);
recalc_sigpending();
spin_unlock_irqrestore(&current->sighand->siglock, flags);
if (c->trans_mod->cancel(c, req) && !p9_client_flush(c, req))
flushing = 1;
}
if (err < 0)
goto reterr;
Expand All @@ -905,7 +894,8 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
if (!err)
return req;
reterr:
p9_tag_remove(c, req);
if (!flushing)
p9_tag_remove(c, req);
return ERR_PTR(safe_errno(err));
}

Expand All @@ -929,8 +919,8 @@ static struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type,
const char *fmt, ...)
{
va_list ap;
int sigpending, err;
unsigned long flags;
int err;
int flushing = 0;
struct p9_req_t *req;

p9_client_handle_async(c, 0);
Expand All @@ -946,40 +936,29 @@ static struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type,
return req;

if (signal_pending(current)) {
sigpending = 1;
clear_thread_flag(TIF_SIGPENDING);
} else
sigpending = 0;
err = -ERESTARTSYS;
/* write won't happen */
p9_req_put(req);
goto reterr;
}

err = c->trans_mod->zc_request(c, req, uidata, uodata,
inlen, olen, in_hdrlen);
if (err < 0) {
if (err == -EIO)
c->status = Disconnected;
if (err != -ERESTARTSYS)
goto recalc_sigpending;
goto reterr;
}
if (req->status == REQ_STATUS_ERROR) {
p9_debug(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err);
err = req->t_err;
}
if ((err == -ERESTARTSYS) && (c->status == Connected)) {
p9_debug(P9_DEBUG_MUX, "flushing\n");
sigpending = 1;
clear_thread_flag(TIF_SIGPENDING);

if (c->trans_mod->cancel(c, req))
p9_client_flush(c, req);

/* if we received the response anyway, don't signal error */
if (req->status == REQ_STATUS_RCVD)
err = 0;
}
recalc_sigpending:
if (sigpending) {
spin_lock_irqsave(&current->sighand->siglock, flags);
recalc_sigpending();
spin_unlock_irqrestore(&current->sighand->siglock, flags);
if (c->trans_mod->cancel(c, req) && !p9_client_flush(c, req))
flushing = 1;
}
if (err < 0)
goto reterr;
Expand All @@ -989,7 +968,8 @@ static struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type,
if (!err)
return req;
reterr:
p9_tag_remove(c, req);
if (!flushing)
p9_tag_remove(c, req);
return ERR_PTR(safe_errno(err));
}

Expand Down

0 comments on commit 62cca28

Please sign in to comment.