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

Commit 9854d758 authored by David S. Miller's avatar David S. Miller
Browse files


David Howells says:

====================
rxrpc: Add bits for kernel services

Here are some patches that add a few things for kernel services to use:

 (1) Allow service upgrade to be requested and allow the resultant actual
     service ID to be obtained.

 (2) Allow the RTT time of a call to be obtained.

 (3) Allow a kernel service to find out if a call is still alive on a
     server between transmitting a request and getting the reply.

 (4) Allow data transmission to ignore signals if transmission progress is
     being made in reasonable time.  This is also usable by userspace by
     passing MSG_WAITALL to sendmsg()[*].

[*] I'm not sure this is the right interface for this or whether a sockopt
    should be used instead.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 37320537 bc5e3a54
Loading
Loading
Loading
Loading
+51 −2
Original line number Diff line number Diff line
@@ -280,6 +280,18 @@ Interaction with the user of the RxRPC socket:
     nominated by a socket option.


Notes on sendmsg:

 (*) MSG_WAITALL can be set to tell sendmsg to ignore signals if the peer is
     making progress at accepting packets within a reasonable time such that we
     manage to queue up all the data for transmission.  This requires the
     client to accept at least one packet per 2*RTT time period.

     If this isn't set, sendmsg() will return immediately, either returning
     EINTR/ERESTARTSYS if nothing was consumed or returning the amount of data
     consumed.


Notes on recvmsg:

 (*) If there's a sequence of data messages belonging to a particular call on
@@ -782,7 +794,9 @@ The kernel interface functions are as follows:
				struct key *key,
				unsigned long user_call_ID,
				s64 tx_total_len,
				gfp_t gfp);
				gfp_t gfp,
				rxrpc_notify_rx_t notify_rx,
				bool upgrade);

     This allocates the infrastructure to make a new RxRPC call and assigns
     call and connection numbers.  The call will be made on the UDP port that
@@ -803,6 +817,13 @@ The kernel interface functions are as follows:
     allows the kernel to encrypt directly to the packet buffers, thereby
     saving a copy.  The value may not be less than -1.

     notify_rx is a pointer to a function to be called when events such as
     incoming data packets or remote aborts happen.

     upgrade should be set to true if a client operation should request that
     the server upgrade the service to a better one.  The resultant service ID
     is returned by rxrpc_kernel_recv_data().

     If this function is successful, an opaque reference to the RxRPC call is
     returned.  The caller now holds a reference on this and it must be
     properly ended.
@@ -850,7 +871,8 @@ The kernel interface functions are as follows:
				   size_t size,
				   size_t *_offset,
				   bool want_more,
				   u32 *_abort)
				   u32 *_abort,
				   u16 *_service)

      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
@@ -873,6 +895,9 @@ The kernel interface functions are as follows:
      If a remote ABORT is detected, the abort code received will be stored in
      *_abort and ECONNABORTED will be returned.

      The service ID that the call ended up with is returned into *_service.
      This can be used to see if a call got a service upgrade.

 (*) Abort a call.

	void rxrpc_kernel_abort_call(struct socket *sock,
@@ -1020,6 +1045,30 @@ The kernel interface functions are as follows:

     It returns 0 if the call was requeued and an error otherwise.

 (*) Get call RTT.

	u64 rxrpc_kernel_get_rtt(struct socket *sock, struct rxrpc_call *call);

     Get the RTT time to the peer in use by a call.  The value returned is in
     nanoseconds.

 (*) Check call still alive.

	u32 rxrpc_kernel_check_life(struct socket *sock,
				    struct rxrpc_call *call);

     This returns a number that is updated when ACKs are received from the peer
     (notably including PING RESPONSE ACKs which we can elicit by sending PING
     ACKs to see if the call still exists on the server).  The caller should
     compare the numbers of two calls to see if the call is still alive after
     waiting for a suitable interval.

     This allows the caller to work out if the server is still contactable and
     if the call is still alive on the server whilst waiting for the server to
     process a client operation.

     This function may transmit a PING ACK.


=======================
CONFIGURABLE PARAMETERS
+1 −0
Original line number Diff line number Diff line
@@ -100,6 +100,7 @@ struct afs_call {
	bool			send_pages;	/* T if data from mapping should be sent */
	bool			need_attention;	/* T if RxRPC poked us */
	bool			async;		/* T if asynchronous */
	bool			upgrade;	/* T to request service upgrade */
	u16			service_id;	/* RxRPC service ID to call */
	__be16			port;		/* target UDP port */
	u32			operation_ID;	/* operation ID for an incoming call */
+33 −9
Original line number Diff line number Diff line
@@ -387,7 +387,8 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp,
					 tx_total_len, gfp,
					 (async ?
					  afs_wake_up_async_call :
					  afs_wake_up_call_waiter));
					  afs_wake_up_call_waiter),
					 call->upgrade);
	call->key = NULL;
	if (IS_ERR(rxcall)) {
		ret = PTR_ERR(rxcall);
@@ -406,7 +407,7 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp,
		      call->request_size);
	msg.msg_control		= NULL;
	msg.msg_controllen	= 0;
	msg.msg_flags		= (call->send_pages ? MSG_MORE : 0);
	msg.msg_flags		= MSG_WAITALL | (call->send_pages ? MSG_MORE : 0);

	/* We have to change the state *before* sending the last packet as
	 * rxrpc might give us the reply before it returns from sending the
@@ -443,7 +444,7 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp,
		abort_code = 0;
		offset = 0;
		rxrpc_kernel_recv_data(afs_socket, rxcall, NULL, 0, &offset,
				       false, &abort_code);
				       false, &abort_code, &call->service_id);
		ret = call->type->abort_to_error(abort_code);
	}
error_kill_call:
@@ -471,7 +472,8 @@ static void afs_deliver_to_call(struct afs_call *call)
			size_t offset = 0;
			ret = rxrpc_kernel_recv_data(afs_socket, call->rxcall,
						     NULL, 0, &offset, false,
						     &call->abort_code);
						     &call->abort_code,
						     &call->service_id);
			trace_afs_recv_data(call, 0, offset, false, ret);

			if (ret == -EINPROGRESS || ret == -EAGAIN)
@@ -536,15 +538,26 @@ static void afs_deliver_to_call(struct afs_call *call)
 */
static int afs_wait_for_call_to_complete(struct afs_call *call)
{
	signed long rtt2, timeout;
	int ret;
	u64 rtt;
	u32 life, last_life;

	DECLARE_WAITQUEUE(myself, current);

	_enter("");

	rtt = rxrpc_kernel_get_rtt(afs_socket, call->rxcall);
	rtt2 = nsecs_to_jiffies64(rtt) * 2;
	if (rtt2 < 2)
		rtt2 = 2;

	timeout = rtt2;
	last_life = rxrpc_kernel_check_life(afs_socket, call->rxcall);

	add_wait_queue(&call->waitq, &myself);
	for (;;) {
		set_current_state(TASK_INTERRUPTIBLE);
		set_current_state(TASK_UNINTERRUPTIBLE);

		/* deliver any messages that are in the queue */
		if (call->state < AFS_CALL_COMPLETE && call->need_attention) {
@@ -554,10 +567,20 @@ static int afs_wait_for_call_to_complete(struct afs_call *call)
			continue;
		}

		if (call->state == AFS_CALL_COMPLETE ||
		    signal_pending(current))
		if (call->state == AFS_CALL_COMPLETE)
			break;
		schedule();

		life = rxrpc_kernel_check_life(afs_socket, call->rxcall);
		if (timeout == 0 &&
		    life == last_life && signal_pending(current))
				break;

		if (life != last_life) {
			timeout = rtt2;
			last_life = life;
		}

		timeout = schedule_timeout(timeout);
	}

	remove_wait_queue(&call->waitq, &myself);
@@ -851,7 +874,8 @@ int afs_extract_data(struct afs_call *call, void *buf, size_t count,

	ret = rxrpc_kernel_recv_data(afs_socket, call->rxcall,
				     buf, count, &call->offset,
				     want_more, &call->abort_code);
				     want_more, &call->abort_code,
				     &call->service_id);
	trace_afs_recv_data(call, count, call->offset, want_more, ret);
	if (ret == 0 || ret == -EAGAIN)
		return ret;
+5 −2
Original line number Diff line number Diff line
@@ -49,17 +49,19 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *,
					   unsigned long,
					   s64,
					   gfp_t,
					   rxrpc_notify_rx_t);
					   rxrpc_notify_rx_t,
					   bool);
int rxrpc_kernel_send_data(struct socket *, struct rxrpc_call *,
			   struct msghdr *, size_t,
			   rxrpc_notify_end_tx_t);
int rxrpc_kernel_recv_data(struct socket *, struct rxrpc_call *,
			   void *, size_t, size_t *, bool, u32 *);
			   void *, size_t, size_t *, bool, u32 *, u16 *);
bool rxrpc_kernel_abort_call(struct socket *, struct rxrpc_call *,
			     u32, int, const char *);
void rxrpc_kernel_end_call(struct socket *, struct rxrpc_call *);
void rxrpc_kernel_get_peer(struct socket *, struct rxrpc_call *,
			   struct sockaddr_rxrpc *);
u64 rxrpc_kernel_get_rtt(struct socket *, struct rxrpc_call *);
int rxrpc_kernel_charge_accept(struct socket *, rxrpc_notify_rx_t,
			       rxrpc_user_attach_call_t, unsigned long, gfp_t);
void rxrpc_kernel_set_tx_length(struct socket *, struct rxrpc_call *, s64);
@@ -67,5 +69,6 @@ int rxrpc_kernel_retry_call(struct socket *, struct rxrpc_call *,
			    struct sockaddr_rxrpc *, struct key *);
int rxrpc_kernel_check_call(struct socket *, struct rxrpc_call *,
			    enum rxrpc_call_completion *, u32 *);
u32 rxrpc_kernel_check_life(struct socket *, struct rxrpc_call *);

#endif /* _NET_RXRPC_H */
+23 −1
Original line number Diff line number Diff line
@@ -265,6 +265,7 @@ static int rxrpc_listen(struct socket *sock, int backlog)
 * @tx_total_len: Total length of data to transmit during the call (or -1)
 * @gfp: The allocation constraints
 * @notify_rx: Where to send notifications instead of socket queue
 * @upgrade: Request service upgrade for call
 *
 * Allow a kernel service to begin a call on the nominated socket.  This just
 * sets up all the internal tracking structures and allocates connection and
@@ -279,7 +280,8 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
					   unsigned long user_call_ID,
					   s64 tx_total_len,
					   gfp_t gfp,
					   rxrpc_notify_rx_t notify_rx)
					   rxrpc_notify_rx_t notify_rx,
					   bool upgrade)
{
	struct rxrpc_conn_parameters cp;
	struct rxrpc_call *call;
@@ -304,6 +306,7 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
	cp.key			= key;
	cp.security_level	= 0;
	cp.exclusive		= false;
	cp.upgrade		= upgrade;
	cp.service_id		= srx->srx_service;
	call = rxrpc_new_client_call(rx, &cp, srx, user_call_ID, tx_total_len,
				     gfp);
@@ -336,6 +339,25 @@ void rxrpc_kernel_end_call(struct socket *sock, struct rxrpc_call *call)
}
EXPORT_SYMBOL(rxrpc_kernel_end_call);

/**
 * rxrpc_kernel_check_life - Check to see whether a call is still alive
 * @sock: The socket the call is on
 * @call: The call to check
 *
 * Allow a kernel service to find out whether a call is still alive - ie. we're
 * getting ACKs from the server.  Returns a number representing the life state
 * which can be compared to that returned by a previous call.
 *
 * If this is a client call, ping ACKs will be sent to the server to find out
 * whether it's still responsive and whether the call is still alive on the
 * server.
 */
u32 rxrpc_kernel_check_life(struct socket *sock, struct rxrpc_call *call)
{
	return call->acks_latest;
}
EXPORT_SYMBOL(rxrpc_kernel_check_life);

/**
 * rxrpc_kernel_check_call - Check a call's state
 * @sock: The socket the call is on
Loading