Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d001648e authored by David Howells's avatar David Howells Committed by David S. Miller
Browse files

rxrpc: Don't expose skbs to in-kernel users [ver #2]



Don't expose skbs to in-kernel users, such as the AFS filesystem, but
instead provide a notification hook the indicates that a call needs
attention and another that indicates that there's a new call to be
collected.

This makes the following possibilities more achievable:

 (1) Call refcounting can be made simpler if skbs don't hold refs to calls.

 (2) skbs referring to non-data events will be able to be freed much sooner
     rather than being queued for AFS to pick up as rxrpc_kernel_recv_data
     will be able to consult the call state.

 (3) We can shortcut the receive phase when a call is remotely aborted
     because we don't have to go through all the packets to get to the one
     cancelling the operation.

 (4) It makes it easier to do encryption/decryption directly between AFS's
     buffers and sk_buffs.

 (5) Encryption/decryption can more easily be done in the AFS's thread
     contexts - usually that of the userspace process that issued a syscall
     - rather than in one of rxrpc's background threads on a workqueue.

 (6) AFS will be able to wait synchronously on a call inside AF_RXRPC.

To make this work, the following interface function has been added:

     int rxrpc_kernel_recv_data(
		struct socket *sock, struct rxrpc_call *call,
		void *buffer, size_t bufsize, size_t *_offset,
		bool want_more, u32 *_abort_code);

This is the recvmsg equivalent.  It allows the caller to find out about the
state of a specific call and to transfer received data into a buffer
piecemeal.

afs_extract_data() and rxrpc_kernel_recv_data() now do all the extraction
logic between them.  They don't wait synchronously yet because the socket
lock needs to be dealt with.

Five interface functions have been removed:

	rxrpc_kernel_is_data_last()
    	rxrpc_kernel_get_abort_code()
    	rxrpc_kernel_get_error_number()
    	rxrpc_kernel_free_skb()
    	rxrpc_kernel_data_consumed()

As a temporary hack, sk_buffs going to an in-kernel call are queued on the
rxrpc_call struct (->knlrecv_queue) rather than being handed over to the
in-kernel user.  To process the queue internally, a temporary function,
temp_deliver_data() has been added.  This will be replaced with common code
between the rxrpc_recvmsg() path and the kernel_rxrpc_recv_data() path in a
future patch.

Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 95ac3994
Loading
Loading
Loading
Loading
+31 −41
Original line number Diff line number Diff line
@@ -748,6 +748,37 @@ The kernel interface functions are as follows:
     The msg must not specify a destination address, control data or any flags
     other than MSG_MORE.  len is the total amount of data to transmit.

 (*) Receive data from a call.

	int rxrpc_kernel_recv_data(struct socket *sock,
				   struct rxrpc_call *call,
				   void *buf,
				   size_t size,
				   size_t *_offset,
				   bool want_more,
				   u32 *_abort)

      This is used to receive data from either the reply part of a client call
      or the request part of a service call.  buf and size specify how much
      data is desired and where to store it.  *_offset is added on to buf and
      subtracted from size internally; the amount copied into the buffer is
      added to *_offset before returning.

      want_more should be true if further data will be required after this is
      satisfied and false if this is the last item of the receive phase.

      There are three normal returns: 0 if the buffer was filled and want_more
      was true; 1 if the buffer was filled, the last DATA packet has been
      emptied and want_more was false; and -EAGAIN if the function needs to be
      called again.

      If the last DATA packet is processed but the buffer contains less than
      the amount requested, EBADMSG is returned.  If want_more wasn't set, but
      more data was available, EMSGSIZE is returned.

      If a remote ABORT is detected, the abort code received will be stored in
      *_abort and ECONNABORTED will be returned.

 (*) Abort a call.

	void rxrpc_kernel_abort_call(struct socket *sock,
@@ -825,47 +856,6 @@ The kernel interface functions are as follows:
     Other errors may be returned if the call had been aborted (-ECONNABORTED)
     or had timed out (-ETIME).

 (*) Record the delivery of a data message.

	void rxrpc_kernel_data_consumed(struct rxrpc_call *call,
					struct sk_buff *skb);

     This is used to record a data message as having been consumed and to
     update the ACK state for the call.  The message must still be passed to
     rxrpc_kernel_free_skb() for disposal by the caller.

 (*) Free a message.

	void rxrpc_kernel_free_skb(struct sk_buff *skb);

     This is used to free a non-DATA socket buffer intercepted from an AF_RXRPC
     socket.

 (*) Determine if a data message is the last one on a call.

	bool rxrpc_kernel_is_data_last(struct sk_buff *skb);

     This is used to determine if a socket buffer holds the last data message
     to be received for a call (true will be returned if it does, false
     if not).

     The data message will be part of the reply on a client call and the
     request on an incoming call.  In the latter case there will be more
     messages, but in the former case there will not.

 (*) Get the abort code from an abort message.

	u32 rxrpc_kernel_get_abort_code(struct sk_buff *skb);

     This is used to extract the abort code from a remote abort message.

 (*) Get the error number from a local or network error message.

	int rxrpc_kernel_get_error_number(struct sk_buff *skb);

     This is used to extract the error number from a message indicating either
     a local error occurred or a network error occurred.

 (*) Allocate a null key for doing anonymous security.

	struct key *rxrpc_get_null_key(const char *keyname);
+77 −65
Original line number Diff line number Diff line
@@ -17,15 +17,12 @@
#include "internal.h"
#include "afs_cm.h"

static int afs_deliver_cb_init_call_back_state(struct afs_call *,
					       struct sk_buff *, bool);
static int afs_deliver_cb_init_call_back_state3(struct afs_call *,
						struct sk_buff *, bool);
static int afs_deliver_cb_probe(struct afs_call *, struct sk_buff *, bool);
static int afs_deliver_cb_callback(struct afs_call *, struct sk_buff *, bool);
static int afs_deliver_cb_probe_uuid(struct afs_call *, struct sk_buff *, bool);
static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *,
						 struct sk_buff *, bool);
static int afs_deliver_cb_init_call_back_state(struct afs_call *);
static int afs_deliver_cb_init_call_back_state3(struct afs_call *);
static int afs_deliver_cb_probe(struct afs_call *);
static int afs_deliver_cb_callback(struct afs_call *);
static int afs_deliver_cb_probe_uuid(struct afs_call *);
static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *);
static void afs_cm_destructor(struct afs_call *);

/*
@@ -130,7 +127,7 @@ static void afs_cm_destructor(struct afs_call *call)
	 * received.  The step number here must match the final number in
	 * afs_deliver_cb_callback().
	 */
	if (call->unmarshall == 6) {
	if (call->unmarshall == 5) {
		ASSERT(call->server && call->count && call->request);
		afs_break_callbacks(call->server, call->count, call->request);
	}
@@ -164,8 +161,7 @@ static void SRXAFSCB_CallBack(struct work_struct *work)
/*
 * deliver request data to a CB.CallBack call
 */
static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb,
				   bool last)
static int afs_deliver_cb_callback(struct afs_call *call)
{
	struct sockaddr_rxrpc srx;
	struct afs_callback *cb;
@@ -174,7 +170,7 @@ static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb,
	u32 tmp;
	int ret, loop;

	_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
	_enter("{%u}", call->unmarshall);

	switch (call->unmarshall) {
	case 0:
@@ -185,7 +181,7 @@ static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb,
		/* extract the FID array and its count in two steps */
	case 1:
		_debug("extract FID count");
		ret = afs_extract_data(call, skb, last, &call->tmp, 4);
		ret = afs_extract_data(call, &call->tmp, 4, true);
		if (ret < 0)
			return ret;

@@ -202,8 +198,8 @@ static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb,

	case 2:
		_debug("extract FID array");
		ret = afs_extract_data(call, skb, last, call->buffer,
				       call->count * 3 * 4);
		ret = afs_extract_data(call, call->buffer,
				       call->count * 3 * 4, true);
		if (ret < 0)
			return ret;

@@ -229,7 +225,7 @@ static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb,
		/* extract the callback array and its count in two steps */
	case 3:
		_debug("extract CB count");
		ret = afs_extract_data(call, skb, last, &call->tmp, 4);
		ret = afs_extract_data(call, &call->tmp, 4, true);
		if (ret < 0)
			return ret;

@@ -239,13 +235,11 @@ static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb,
			return -EBADMSG;
		call->offset = 0;
		call->unmarshall++;
		if (tmp == 0)
			goto empty_cb_array;

	case 4:
		_debug("extract CB array");
		ret = afs_extract_data(call, skb, last, call->request,
				       call->count * 3 * 4);
		ret = afs_extract_data(call, call->buffer,
				       call->count * 3 * 4, false);
		if (ret < 0)
			return ret;

@@ -258,15 +252,9 @@ static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb,
			cb->type	= ntohl(*bp++);
		}

	empty_cb_array:
		call->offset = 0;
		call->unmarshall++;

	case 5:
		ret = afs_data_complete(call, skb, last);
		if (ret < 0)
			return ret;

		/* Record that the message was unmarshalled successfully so
		 * that the call destructor can know do the callback breaking
		 * work, even if the final ACK isn't received.
@@ -275,7 +263,7 @@ static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb,
		 * updated also.
		 */
		call->unmarshall++;
	case 6:
	case 5:
		break;
	}

@@ -310,19 +298,17 @@ static void SRXAFSCB_InitCallBackState(struct work_struct *work)
/*
 * deliver request data to a CB.InitCallBackState call
 */
static int afs_deliver_cb_init_call_back_state(struct afs_call *call,
					       struct sk_buff *skb,
					       bool last)
static int afs_deliver_cb_init_call_back_state(struct afs_call *call)
{
	struct sockaddr_rxrpc srx;
	struct afs_server *server;
	int ret;

	_enter(",{%u},%d", skb->len, last);
	_enter("");

	rxrpc_kernel_get_peer(afs_socket, call->rxcall, &srx);

	ret = afs_data_complete(call, skb, last);
	ret = afs_extract_data(call, NULL, 0, false);
	if (ret < 0)
		return ret;

@@ -344,21 +330,61 @@ static int afs_deliver_cb_init_call_back_state(struct afs_call *call,
/*
 * deliver request data to a CB.InitCallBackState3 call
 */
static int afs_deliver_cb_init_call_back_state3(struct afs_call *call,
						struct sk_buff *skb,
						bool last)
static int afs_deliver_cb_init_call_back_state3(struct afs_call *call)
{
	struct sockaddr_rxrpc srx;
	struct afs_server *server;
	struct afs_uuid *r;
	unsigned loop;
	__be32 *b;
	int ret;

	_enter(",{%u},%d", skb->len, last);
	_enter("");

	rxrpc_kernel_get_peer(afs_socket, call->rxcall, &srx);

	/* There are some arguments that we ignore */
	afs_data_consumed(call, skb);
	if (!last)
		return -EAGAIN;
	_enter("{%u}", call->unmarshall);

	switch (call->unmarshall) {
	case 0:
		call->offset = 0;
		call->buffer = kmalloc(11 * sizeof(__be32), GFP_KERNEL);
		if (!call->buffer)
			return -ENOMEM;
		call->unmarshall++;

	case 1:
		_debug("extract UUID");
		ret = afs_extract_data(call, call->buffer,
				       11 * sizeof(__be32), false);
		switch (ret) {
		case 0:		break;
		case -EAGAIN:	return 0;
		default:	return ret;
		}

		_debug("unmarshall UUID");
		call->request = kmalloc(sizeof(struct afs_uuid), GFP_KERNEL);
		if (!call->request)
			return -ENOMEM;

		b = call->buffer;
		r = call->request;
		r->time_low			= ntohl(b[0]);
		r->time_mid			= ntohl(b[1]);
		r->time_hi_and_version		= ntohl(b[2]);
		r->clock_seq_hi_and_reserved 	= ntohl(b[3]);
		r->clock_seq_low		= ntohl(b[4]);

		for (loop = 0; loop < 6; loop++)
			r->node[loop] = ntohl(b[loop + 5]);

		call->offset = 0;
		call->unmarshall++;

	case 2:
		break;
	}

	/* no unmarshalling required */
	call->state = AFS_CALL_REPLYING;
@@ -390,14 +416,13 @@ static void SRXAFSCB_Probe(struct work_struct *work)
/*
 * deliver request data to a CB.Probe call
 */
static int afs_deliver_cb_probe(struct afs_call *call, struct sk_buff *skb,
				bool last)
static int afs_deliver_cb_probe(struct afs_call *call)
{
	int ret;

	_enter(",{%u},%d", skb->len, last);
	_enter("");

	ret = afs_data_complete(call, skb, last);
	ret = afs_extract_data(call, NULL, 0, false);
	if (ret < 0)
		return ret;

@@ -435,19 +460,14 @@ static void SRXAFSCB_ProbeUuid(struct work_struct *work)
/*
 * deliver request data to a CB.ProbeUuid call
 */
static int afs_deliver_cb_probe_uuid(struct afs_call *call, struct sk_buff *skb,
				     bool last)
static int afs_deliver_cb_probe_uuid(struct afs_call *call)
{
	struct afs_uuid *r;
	unsigned loop;
	__be32 *b;
	int ret;

	_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);

	ret = afs_data_complete(call, skb, last);
	if (ret < 0)
		return ret;
	_enter("{%u}", call->unmarshall);

	switch (call->unmarshall) {
	case 0:
@@ -459,8 +479,8 @@ static int afs_deliver_cb_probe_uuid(struct afs_call *call, struct sk_buff *skb,

	case 1:
		_debug("extract UUID");
		ret = afs_extract_data(call, skb, last, call->buffer,
				       11 * sizeof(__be32));
		ret = afs_extract_data(call, call->buffer,
				       11 * sizeof(__be32), false);
		switch (ret) {
		case 0:		break;
		case -EAGAIN:	return 0;
@@ -487,16 +507,9 @@ static int afs_deliver_cb_probe_uuid(struct afs_call *call, struct sk_buff *skb,
		call->unmarshall++;

	case 2:
		_debug("trailer");
		if (skb->len != 0)
			return -EBADMSG;
		break;
	}

	ret = afs_data_complete(call, skb, last);
	if (ret < 0)
		return ret;

	call->state = AFS_CALL_REPLYING;

	INIT_WORK(&call->work, SRXAFSCB_ProbeUuid);
@@ -570,14 +583,13 @@ static void SRXAFSCB_TellMeAboutYourself(struct work_struct *work)
/*
 * deliver request data to a CB.TellMeAboutYourself call
 */
static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *call,
						 struct sk_buff *skb, bool last)
static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *call)
{
	int ret;

	_enter(",{%u},%d", skb->len, last);
	_enter("");

	ret = afs_data_complete(call, skb, last);
	ret = afs_extract_data(call, NULL, 0, false);
	if (ret < 0)
		return ret;

+62 −86
Original line number Diff line number Diff line
@@ -235,16 +235,15 @@ static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp,
/*
 * deliver reply data to an FS.FetchStatus
 */
static int afs_deliver_fs_fetch_status(struct afs_call *call,
				       struct sk_buff *skb, bool last)
static int afs_deliver_fs_fetch_status(struct afs_call *call)
{
	struct afs_vnode *vnode = call->reply;
	const __be32 *bp;
	int ret;

	_enter(",,%u", last);
	_enter("");

	ret = afs_transfer_reply(call, skb, last);
	ret = afs_transfer_reply(call);
	if (ret < 0)
		return ret;

@@ -307,8 +306,7 @@ int afs_fs_fetch_file_status(struct afs_server *server,
/*
 * deliver reply data to an FS.FetchData
 */
static int afs_deliver_fs_fetch_data(struct afs_call *call,
				     struct sk_buff *skb, bool last)
static int afs_deliver_fs_fetch_data(struct afs_call *call)
{
	struct afs_vnode *vnode = call->reply;
	const __be32 *bp;
@@ -316,7 +314,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call,
	void *buffer;
	int ret;

	_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
	_enter("{%u}", call->unmarshall);

	switch (call->unmarshall) {
	case 0:
@@ -332,7 +330,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call,
		 * client) */
	case 1:
		_debug("extract data length (MSW)");
		ret = afs_extract_data(call, skb, last, &call->tmp, 4);
		ret = afs_extract_data(call, &call->tmp, 4, true);
		if (ret < 0)
			return ret;

@@ -347,7 +345,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call,
		/* extract the returned data length */
	case 2:
		_debug("extract data length");
		ret = afs_extract_data(call, skb, last, &call->tmp, 4);
		ret = afs_extract_data(call, &call->tmp, 4, true);
		if (ret < 0)
			return ret;

@@ -363,10 +361,10 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call,
		_debug("extract data");
		if (call->count > 0) {
			page = call->reply3;
			buffer = kmap_atomic(page);
			ret = afs_extract_data(call, skb, last, buffer,
					       call->count);
			kunmap_atomic(buffer);
			buffer = kmap(page);
			ret = afs_extract_data(call, buffer,
					       call->count, true);
			kunmap(buffer);
			if (ret < 0)
				return ret;
		}
@@ -376,8 +374,8 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call,

		/* extract the metadata */
	case 4:
		ret = afs_extract_data(call, skb, last, call->buffer,
				       (21 + 3 + 6) * 4);
		ret = afs_extract_data(call, call->buffer,
				       (21 + 3 + 6) * 4, false);
		if (ret < 0)
			return ret;

@@ -391,18 +389,15 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call,
		call->unmarshall++;

	case 5:
		ret = afs_data_complete(call, skb, last);
		if (ret < 0)
			return ret;
		break;
	}

	if (call->count < PAGE_SIZE) {
		_debug("clear");
		page = call->reply3;
		buffer = kmap_atomic(page);
		buffer = kmap(page);
		memset(buffer + call->count, 0, PAGE_SIZE - call->count);
		kunmap_atomic(buffer);
		kunmap(buffer);
	}

	_leave(" = 0 [done]");
@@ -515,13 +510,12 @@ int afs_fs_fetch_data(struct afs_server *server,
/*
 * deliver reply data to an FS.GiveUpCallBacks
 */
static int afs_deliver_fs_give_up_callbacks(struct afs_call *call,
					    struct sk_buff *skb, bool last)
static int afs_deliver_fs_give_up_callbacks(struct afs_call *call)
{
	_enter(",{%u},%d", skb->len, last);
	_enter("");

	/* shouldn't be any reply data */
	return afs_data_complete(call, skb, last);
	return afs_extract_data(call, NULL, 0, false);
}

/*
@@ -599,16 +593,15 @@ int afs_fs_give_up_callbacks(struct afs_server *server,
/*
 * deliver reply data to an FS.CreateFile or an FS.MakeDir
 */
static int afs_deliver_fs_create_vnode(struct afs_call *call,
				       struct sk_buff *skb, bool last)
static int afs_deliver_fs_create_vnode(struct afs_call *call)
{
	struct afs_vnode *vnode = call->reply;
	const __be32 *bp;
	int ret;

	_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
	_enter("{%u}", call->unmarshall);

	ret = afs_transfer_reply(call, skb, last);
	ret = afs_transfer_reply(call);
	if (ret < 0)
		return ret;

@@ -696,16 +689,15 @@ int afs_fs_create(struct afs_server *server,
/*
 * deliver reply data to an FS.RemoveFile or FS.RemoveDir
 */
static int afs_deliver_fs_remove(struct afs_call *call,
				 struct sk_buff *skb, bool last)
static int afs_deliver_fs_remove(struct afs_call *call)
{
	struct afs_vnode *vnode = call->reply;
	const __be32 *bp;
	int ret;

	_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
	_enter("{%u}", call->unmarshall);

	ret = afs_transfer_reply(call, skb, last);
	ret = afs_transfer_reply(call);
	if (ret < 0)
		return ret;

@@ -777,16 +769,15 @@ int afs_fs_remove(struct afs_server *server,
/*
 * deliver reply data to an FS.Link
 */
static int afs_deliver_fs_link(struct afs_call *call,
			       struct sk_buff *skb, bool last)
static int afs_deliver_fs_link(struct afs_call *call)
{
	struct afs_vnode *dvnode = call->reply, *vnode = call->reply2;
	const __be32 *bp;
	int ret;

	_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
	_enter("{%u}", call->unmarshall);

	ret = afs_transfer_reply(call, skb, last);
	ret = afs_transfer_reply(call);
	if (ret < 0)
		return ret;

@@ -863,16 +854,15 @@ int afs_fs_link(struct afs_server *server,
/*
 * deliver reply data to an FS.Symlink
 */
static int afs_deliver_fs_symlink(struct afs_call *call,
				  struct sk_buff *skb, bool last)
static int afs_deliver_fs_symlink(struct afs_call *call)
{
	struct afs_vnode *vnode = call->reply;
	const __be32 *bp;
	int ret;

	_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
	_enter("{%u}", call->unmarshall);

	ret = afs_transfer_reply(call, skb, last);
	ret = afs_transfer_reply(call);
	if (ret < 0)
		return ret;

@@ -968,16 +958,15 @@ int afs_fs_symlink(struct afs_server *server,
/*
 * deliver reply data to an FS.Rename
 */
static int afs_deliver_fs_rename(struct afs_call *call,
				  struct sk_buff *skb, bool last)
static int afs_deliver_fs_rename(struct afs_call *call)
{
	struct afs_vnode *orig_dvnode = call->reply, *new_dvnode = call->reply2;
	const __be32 *bp;
	int ret;

	_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
	_enter("{%u}", call->unmarshall);

	ret = afs_transfer_reply(call, skb, last);
	ret = afs_transfer_reply(call);
	if (ret < 0)
		return ret;

@@ -1072,16 +1061,15 @@ int afs_fs_rename(struct afs_server *server,
/*
 * deliver reply data to an FS.StoreData
 */
static int afs_deliver_fs_store_data(struct afs_call *call,
				     struct sk_buff *skb, bool last)
static int afs_deliver_fs_store_data(struct afs_call *call)
{
	struct afs_vnode *vnode = call->reply;
	const __be32 *bp;
	int ret;

	_enter(",,%u", last);
	_enter("");

	ret = afs_transfer_reply(call, skb, last);
	ret = afs_transfer_reply(call);
	if (ret < 0)
		return ret;

@@ -1251,17 +1239,16 @@ int afs_fs_store_data(struct afs_server *server, struct afs_writeback *wb,
/*
 * deliver reply data to an FS.StoreStatus
 */
static int afs_deliver_fs_store_status(struct afs_call *call,
				       struct sk_buff *skb, bool last)
static int afs_deliver_fs_store_status(struct afs_call *call)
{
	afs_dataversion_t *store_version;
	struct afs_vnode *vnode = call->reply;
	const __be32 *bp;
	int ret;

	_enter(",,%u", last);
	_enter("");

	ret = afs_transfer_reply(call, skb, last);
	ret = afs_transfer_reply(call);
	if (ret < 0)
		return ret;

@@ -1443,14 +1430,13 @@ int afs_fs_setattr(struct afs_server *server, struct key *key,
/*
 * deliver reply data to an FS.GetVolumeStatus
 */
static int afs_deliver_fs_get_volume_status(struct afs_call *call,
					    struct sk_buff *skb, bool last)
static int afs_deliver_fs_get_volume_status(struct afs_call *call)
{
	const __be32 *bp;
	char *p;
	int ret;

	_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
	_enter("{%u}", call->unmarshall);

	switch (call->unmarshall) {
	case 0:
@@ -1460,8 +1446,8 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call,
		/* extract the returned status record */
	case 1:
		_debug("extract status");
		ret = afs_extract_data(call, skb, last, call->buffer,
				       12 * 4);
		ret = afs_extract_data(call, call->buffer,
				       12 * 4, true);
		if (ret < 0)
			return ret;

@@ -1472,7 +1458,7 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call,

		/* extract the volume name length */
	case 2:
		ret = afs_extract_data(call, skb, last, &call->tmp, 4);
		ret = afs_extract_data(call, &call->tmp, 4, true);
		if (ret < 0)
			return ret;

@@ -1487,8 +1473,8 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call,
	case 3:
		_debug("extract volname");
		if (call->count > 0) {
			ret = afs_extract_data(call, skb, last, call->reply3,
					       call->count);
			ret = afs_extract_data(call, call->reply3,
					       call->count, true);
			if (ret < 0)
				return ret;
		}
@@ -1508,8 +1494,8 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call,
		call->count = 4 - (call->count & 3);

	case 4:
		ret = afs_extract_data(call, skb, last, call->buffer,
				       call->count);
		ret = afs_extract_data(call, call->buffer,
				       call->count, true);
		if (ret < 0)
			return ret;

@@ -1519,7 +1505,7 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call,

		/* extract the offline message length */
	case 5:
		ret = afs_extract_data(call, skb, last, &call->tmp, 4);
		ret = afs_extract_data(call, &call->tmp, 4, true);
		if (ret < 0)
			return ret;

@@ -1534,8 +1520,8 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call,
	case 6:
		_debug("extract offline");
		if (call->count > 0) {
			ret = afs_extract_data(call, skb, last, call->reply3,
					       call->count);
			ret = afs_extract_data(call, call->reply3,
					       call->count, true);
			if (ret < 0)
				return ret;
		}
@@ -1555,8 +1541,8 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call,
		call->count = 4 - (call->count & 3);

	case 7:
		ret = afs_extract_data(call, skb, last, call->buffer,
				       call->count);
		ret = afs_extract_data(call, call->buffer,
				       call->count, true);
		if (ret < 0)
			return ret;

@@ -1566,7 +1552,7 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call,

		/* extract the message of the day length */
	case 8:
		ret = afs_extract_data(call, skb, last, &call->tmp, 4);
		ret = afs_extract_data(call, &call->tmp, 4, true);
		if (ret < 0)
			return ret;

@@ -1581,8 +1567,8 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call,
	case 9:
		_debug("extract motd");
		if (call->count > 0) {
			ret = afs_extract_data(call, skb, last, call->reply3,
					       call->count);
			ret = afs_extract_data(call, call->reply3,
					       call->count, true);
			if (ret < 0)
				return ret;
		}
@@ -1595,26 +1581,17 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call,
		call->unmarshall++;

		/* extract the message of the day padding */
		if ((call->count & 3) == 0) {
			call->unmarshall++;
			goto no_motd_padding;
		}
		call->count = 4 - (call->count & 3);
		call->count = (4 - (call->count & 3)) & 3;

	case 10:
		ret = afs_extract_data(call, skb, last, call->buffer,
				       call->count);
		ret = afs_extract_data(call, call->buffer,
				       call->count, false);
		if (ret < 0)
			return ret;

		call->offset = 0;
		call->unmarshall++;
	no_motd_padding:

	case 11:
		ret = afs_data_complete(call, skb, last);
		if (ret < 0)
			return ret;
		break;
	}

@@ -1685,15 +1662,14 @@ int afs_fs_get_volume_status(struct afs_server *server,
/*
 * deliver reply data to an FS.SetLock, FS.ExtendLock or FS.ReleaseLock
 */
static int afs_deliver_fs_xxxx_lock(struct afs_call *call,
				    struct sk_buff *skb, bool last)
static int afs_deliver_fs_xxxx_lock(struct afs_call *call)
{
	const __be32 *bp;
	int ret;

	_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
	_enter("{%u}", call->unmarshall);

	ret = afs_transfer_reply(call, skb, last);
	ret = afs_transfer_reply(call);
	if (ret < 0)
		return ret;

+9 −24
Original line number Diff line number Diff line
@@ -13,7 +13,6 @@
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/pagemap.h>
#include <linux/skbuff.h>
#include <linux/rxrpc.h>
#include <linux/key.h>
#include <linux/workqueue.h>
@@ -57,7 +56,7 @@ struct afs_mount_params {
 */
struct afs_wait_mode {
	/* RxRPC received message notification */
	void (*rx_wakeup)(struct afs_call *call);
	rxrpc_notify_rx_t notify_rx;

	/* synchronous call waiter and call dispatched notification */
	int (*wait)(struct afs_call *call);
@@ -76,10 +75,8 @@ struct afs_call {
	const struct afs_call_type *type;	/* type of call */
	const struct afs_wait_mode *wait_mode;	/* completion wait mode */
	wait_queue_head_t	waitq;		/* processes awaiting completion */
	void (*async_workfn)(struct afs_call *call); /* asynchronous work function */
	struct work_struct	async_work;	/* asynchronous work processor */
	struct work_struct	work;		/* actual work processor */
	struct sk_buff_head	rx_queue;	/* received packets */
	struct rxrpc_call	*rxcall;	/* RxRPC call handle */
	struct key		*key;		/* security for this call */
	struct afs_server	*server;	/* server affected by incoming CM call */
@@ -93,6 +90,7 @@ struct afs_call {
	void			*reply4;	/* reply buffer (fourth part) */
	pgoff_t			first;		/* first page in mapping to deal with */
	pgoff_t			last;		/* last page in mapping to deal with */
	size_t			offset;		/* offset into received data store */
	enum {					/* call state */
		AFS_CALL_REQUESTING,	/* request is being sent for outgoing call */
		AFS_CALL_AWAIT_REPLY,	/* awaiting reply to outgoing call */
@@ -100,21 +98,18 @@ struct afs_call {
		AFS_CALL_AWAIT_REQUEST,	/* awaiting request data on incoming call */
		AFS_CALL_REPLYING,	/* replying to incoming call */
		AFS_CALL_AWAIT_ACK,	/* awaiting final ACK of incoming call */
		AFS_CALL_COMPLETE,	/* successfully completed */
		AFS_CALL_BUSY,		/* server was busy */
		AFS_CALL_ABORTED,	/* call was aborted */
		AFS_CALL_ERROR,		/* call failed due to error */
		AFS_CALL_COMPLETE,	/* Completed or failed */
	}			state;
	int			error;		/* error code */
	u32			abort_code;	/* Remote abort ID or 0 */
	unsigned		request_size;	/* size of request data */
	unsigned		reply_max;	/* maximum size of reply */
	unsigned		reply_size;	/* current size of reply */
	unsigned		first_offset;	/* offset into mapping[first] */
	unsigned		last_to;	/* amount of mapping[last] */
	unsigned		offset;		/* offset into received data store */
	unsigned char		unmarshall;	/* unmarshalling phase */
	bool			incoming;	/* T if incoming call */
	bool			send_pages;	/* T if data from mapping should be sent */
	bool			need_attention;	/* T if RxRPC poked us */
	u16			service_id;	/* RxRPC service ID to call */
	__be16			port;		/* target UDP port */
	__be32			operation_ID;	/* operation ID for an incoming call */
@@ -129,8 +124,7 @@ struct afs_call_type {
	/* deliver request or reply data to an call
	 * - returning an error will cause the call to be aborted
	 */
	int (*deliver)(struct afs_call *call, struct sk_buff *skb,
		       bool last);
	int (*deliver)(struct afs_call *call);

	/* map an abort code to an error number */
	int (*abort_to_error)(u32 abort_code);
@@ -612,27 +606,18 @@ extern struct socket *afs_socket;

extern int afs_open_socket(void);
extern void afs_close_socket(void);
extern void afs_data_consumed(struct afs_call *, struct sk_buff *);
extern int afs_make_call(struct in_addr *, struct afs_call *, gfp_t,
			 const struct afs_wait_mode *);
extern struct afs_call *afs_alloc_flat_call(const struct afs_call_type *,
					    size_t, size_t);
extern void afs_flat_call_destructor(struct afs_call *);
extern int afs_transfer_reply(struct afs_call *, struct sk_buff *, bool);
extern void afs_send_empty_reply(struct afs_call *);
extern void afs_send_simple_reply(struct afs_call *, const void *, size_t);
extern int afs_extract_data(struct afs_call *, struct sk_buff *, bool, void *,
			    size_t);
extern int afs_extract_data(struct afs_call *, void *, size_t, bool);

static inline int afs_data_complete(struct afs_call *call, struct sk_buff *skb,
				    bool last)
static inline int afs_transfer_reply(struct afs_call *call)
{
	if (skb->len > 0)
		return -EBADMSG;
	afs_data_consumed(call, skb);
	if (!last)
		return -EAGAIN;
	return 0;
	return afs_extract_data(call, call->buffer, call->reply_max, false);
}

/*
+158 −281

File changed.

Preview size limit exceeded, changes collapsed.

Loading