afs: Set up the iov_iter before calling afs_extract_data()

afs_extract_data sets up a temporary iov_iter and passes it to AF_RXRPC
each time it is called to describe the remaining buffer to be filled.

Instead:

 (1) Put an iterator in the afs_call struct.

 (2) Set the iterator for each marshalling stage to load data into the
     appropriate places.  A number of convenience functions are provided to
     this end (eg. afs_extract_to_buf()).

     This iterator is then passed to afs_extract_data().

 (3) Use the new ITER_DISCARD iterator to discard any excess data provided
     by FetchData.

Signed-off-by: David Howells <dhowells@redhat.com>
This commit is contained in:
David Howells
2018-10-20 00:57:56 +01:00
parent 160cb9574b
commit 12bdcf333f
6 changed files with 235 additions and 308 deletions

View File

@@ -143,6 +143,7 @@ static struct afs_call *afs_alloc_call(struct afs_net *net,
INIT_WORK(&call->async_work, afs_process_async_call);
init_waitqueue_head(&call->waitq);
spin_lock_init(&call->state_lock);
call->_iter = &call->iter;
o = atomic_inc_return(&net->nr_outstanding_calls);
trace_afs_call(call, afs_call_trace_alloc, 1, o,
@@ -233,6 +234,7 @@ struct afs_call *afs_alloc_flat_call(struct afs_net *net,
goto nomem_free;
}
afs_extract_to_buf(call, call->reply_max);
call->operation_ID = type->op;
init_waitqueue_head(&call->waitq);
return call;
@@ -465,14 +467,12 @@ static void afs_deliver_to_call(struct afs_call *call)
state == AFS_CALL_SV_AWAIT_ACK
) {
if (state == AFS_CALL_SV_AWAIT_ACK) {
struct iov_iter iter;
iov_iter_kvec(&iter, READ, NULL, 0, 0);
iov_iter_kvec(&call->iter, READ, NULL, 0, 0);
ret = rxrpc_kernel_recv_data(call->net->socket,
call->rxcall, &iter, false,
&remote_abort,
call->rxcall, &call->iter,
false, &remote_abort,
&call->service_id);
trace_afs_recv_data(call, 0, 0, false, ret);
trace_afs_receive_data(call, &call->iter, false, ret);
if (ret == -EINPROGRESS || ret == -EAGAIN)
return;
@@ -516,7 +516,7 @@ static void afs_deliver_to_call(struct afs_call *call)
if (state != AFS_CALL_CL_AWAIT_REPLY)
abort_code = RXGEN_SS_UNMARSHAL;
rxrpc_kernel_abort_call(call->net->socket, call->rxcall,
abort_code, -EBADMSG, "KUM");
abort_code, ret, "KUM");
goto local_abort;
}
}
@@ -727,6 +727,7 @@ void afs_charge_preallocation(struct work_struct *work)
call->async = true;
call->state = AFS_CALL_SV_AWAIT_OP_ID;
init_waitqueue_head(&call->waitq);
afs_extract_to_tmp(call);
}
if (rxrpc_kernel_charge_accept(net->socket,
@@ -772,18 +773,15 @@ static int afs_deliver_cm_op_id(struct afs_call *call)
{
int ret;
_enter("{%zu}", call->offset);
ASSERTCMP(call->offset, <, 4);
_enter("{%zu}", iov_iter_count(call->_iter));
/* the operation ID forms the first four bytes of the request data */
ret = afs_extract_data(call, &call->tmp, 4, true);
ret = afs_extract_data(call, true);
if (ret < 0)
return ret;
call->operation_ID = ntohl(call->tmp);
afs_set_call_state(call, AFS_CALL_SV_AWAIT_OP_ID, AFS_CALL_SV_AWAIT_REQUEST);
call->offset = 0;
/* ask the cache manager to route the call (it'll change the call type
* if successful) */
@@ -887,30 +885,19 @@ void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len)
/*
* Extract a piece of data from the received data socket buffers.
*/
int afs_extract_data(struct afs_call *call, void *buf, size_t count,
bool want_more)
int afs_extract_data(struct afs_call *call, bool want_more)
{
struct afs_net *net = call->net;
struct iov_iter iter;
struct kvec iov;
struct iov_iter *iter = call->_iter;
enum afs_call_state state;
u32 remote_abort = 0;
int ret;
_enter("{%s,%zu},,%zu,%d",
call->type->name, call->offset, count, want_more);
_enter("{%s,%zu},%d", call->type->name, iov_iter_count(iter), want_more);
ASSERTCMP(call->offset, <=, count);
iov.iov_base = buf + call->offset;
iov.iov_len = count - call->offset;
iov_iter_kvec(&iter, READ, &iov, 1, count - call->offset);
ret = rxrpc_kernel_recv_data(net->socket, call->rxcall, &iter,
ret = rxrpc_kernel_recv_data(net->socket, call->rxcall, iter,
want_more, &remote_abort,
&call->service_id);
call->offset += (count - call->offset) - iov_iter_count(&iter);
trace_afs_recv_data(call, count, call->offset, want_more, ret);
if (ret == 0 || ret == -EAGAIN)
return ret;