mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-20 02:34:23 +08:00
4f95dd78a7
Rework the local RxRPC endpoint management. Local endpoint objects are maintained in a flat list as before. This should be okay as there shouldn't be more than one per open AF_RXRPC socket (there can be fewer as local endpoints can be shared if their local service ID is 0 and they share the same local transport parameters). Changes: (1) Local endpoints may now only be shared if they have local service ID 0 (ie. they're not being used for listening). This prevents a scenario where process A is listening of the Cache Manager port and process B contacts a fileserver - which may then attempt to send CM requests back to B. But if A and B are sharing a local endpoint, A will get the CM requests meant for B. (2) We use a mutex to handle lookups and don't provide RCU-only lookups since we only expect to access the list when opening a socket or destroying an endpoint. The local endpoint object is pointed to by the transport socket's sk_user_data for the life of the transport socket - allowing us to refer to it directly from the sk_data_ready and sk_error_report callbacks. (3) atomic_inc_not_zero() now exists and can be used to only share a local endpoint if the last reference hasn't yet gone. (4) We can remove rxrpc_local_lock - a spinlock that had to be taken with BH processing disabled given that we assume sk_user_data won't change under us. (5) The transport socket is shut down before we clear the sk_user_data pointer so that we can be sure that the transport socket's callbacks won't be invoked once the RCU destruction is scheduled. (6) Local endpoints have a work item that handles both destruction and event processing. The means that destruction doesn't then need to wait for event processing. The event queues can then be cleared after the transport socket is shut down. (7) Local endpoints are no longer available for resurrection beyond the life of the sockets that had them open. As soon as their last ref goes, they are scheduled for destruction and may not have their usage count moved from 0. Signed-off-by: David Howells <dhowells@redhat.com>
117 lines
2.7 KiB
C
117 lines
2.7 KiB
C
/* AF_RXRPC local endpoint management
|
|
*
|
|
* Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
|
|
* Written by David Howells (dhowells@redhat.com)
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version
|
|
* 2 of the License, or (at your option) any later version.
|
|
*/
|
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/net.h>
|
|
#include <linux/skbuff.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/udp.h>
|
|
#include <linux/ip.h>
|
|
#include <net/sock.h>
|
|
#include <net/af_rxrpc.h>
|
|
#include <generated/utsrelease.h>
|
|
#include "ar-internal.h"
|
|
|
|
static const char rxrpc_version_string[65] = "linux-" UTS_RELEASE " AF_RXRPC";
|
|
|
|
/*
|
|
* Reply to a version request
|
|
*/
|
|
static void rxrpc_send_version_request(struct rxrpc_local *local,
|
|
struct rxrpc_host_header *hdr,
|
|
struct sk_buff *skb)
|
|
{
|
|
struct rxrpc_wire_header whdr;
|
|
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
|
|
struct sockaddr_in sin;
|
|
struct msghdr msg;
|
|
struct kvec iov[2];
|
|
size_t len;
|
|
int ret;
|
|
|
|
_enter("");
|
|
|
|
sin.sin_family = AF_INET;
|
|
sin.sin_port = udp_hdr(skb)->source;
|
|
sin.sin_addr.s_addr = ip_hdr(skb)->saddr;
|
|
|
|
msg.msg_name = &sin;
|
|
msg.msg_namelen = sizeof(sin);
|
|
msg.msg_control = NULL;
|
|
msg.msg_controllen = 0;
|
|
msg.msg_flags = 0;
|
|
|
|
whdr.epoch = htonl(sp->hdr.epoch);
|
|
whdr.cid = htonl(sp->hdr.cid);
|
|
whdr.callNumber = htonl(sp->hdr.callNumber);
|
|
whdr.seq = 0;
|
|
whdr.serial = 0;
|
|
whdr.type = RXRPC_PACKET_TYPE_VERSION;
|
|
whdr.flags = RXRPC_LAST_PACKET | (~hdr->flags & RXRPC_CLIENT_INITIATED);
|
|
whdr.userStatus = 0;
|
|
whdr.securityIndex = 0;
|
|
whdr._rsvd = 0;
|
|
whdr.serviceId = htons(sp->hdr.serviceId);
|
|
|
|
iov[0].iov_base = &whdr;
|
|
iov[0].iov_len = sizeof(whdr);
|
|
iov[1].iov_base = (char *)rxrpc_version_string;
|
|
iov[1].iov_len = sizeof(rxrpc_version_string);
|
|
|
|
len = iov[0].iov_len + iov[1].iov_len;
|
|
|
|
_proto("Tx VERSION (reply)");
|
|
|
|
ret = kernel_sendmsg(local->socket, &msg, iov, 2, len);
|
|
if (ret < 0)
|
|
_debug("sendmsg failed: %d", ret);
|
|
|
|
_leave("");
|
|
}
|
|
|
|
/*
|
|
* Process event packets targetted at a local endpoint.
|
|
*/
|
|
void rxrpc_process_local_events(struct rxrpc_local *local)
|
|
{
|
|
struct sk_buff *skb;
|
|
char v;
|
|
|
|
_enter("");
|
|
|
|
skb = skb_dequeue(&local->event_queue);
|
|
if (skb) {
|
|
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
|
|
|
|
_debug("{%d},{%u}", local->debug_id, sp->hdr.type);
|
|
|
|
switch (sp->hdr.type) {
|
|
case RXRPC_PACKET_TYPE_VERSION:
|
|
if (skb_copy_bits(skb, 0, &v, 1) < 0)
|
|
return;
|
|
_proto("Rx VERSION { %02x }", v);
|
|
if (v == 0)
|
|
rxrpc_send_version_request(local, &sp->hdr, skb);
|
|
break;
|
|
|
|
default:
|
|
/* Just ignore anything we don't understand */
|
|
break;
|
|
}
|
|
|
|
rxrpc_free_skb(skb);
|
|
}
|
|
|
|
_leave("");
|
|
}
|