Skip to content

Commit

Permalink
rxrpc, afs: Allow afs to pin rxrpc_peer objects
Browse files Browse the repository at this point in the history
Change rxrpc's API such that:

 (1) A new function, rxrpc_kernel_lookup_peer(), is provided to look up an
     rxrpc_peer record for a remote address and a corresponding function,
     rxrpc_kernel_put_peer(), is provided to dispose of it again.

 (2) When setting up a call, the rxrpc_peer object used during a call is
     now passed in rather than being set up by rxrpc_connect_call().  For
     afs, this meenat passing it to rxrpc_kernel_begin_call() rather than
     the full address (the service ID then has to be passed in as a
     separate parameter).

 (3) A new function, rxrpc_kernel_remote_addr(), is added so that afs can
     get a pointer to the transport address for display purposed, and
     another, rxrpc_kernel_remote_srx(), to gain a pointer to the full
     rxrpc address.

 (4) The function to retrieve the RTT from a call, rxrpc_kernel_get_srtt(),
     is then altered to take a peer.  This now returns the RTT or -1 if
     there are insufficient samples.

 (5) Rename rxrpc_kernel_get_peer() to rxrpc_kernel_call_get_peer().

 (6) Provide a new function, rxrpc_kernel_get_peer(), to get a ref on a
     peer the caller already has.

This allows the afs filesystem to pin the rxrpc_peer records that it is
using, allowing faster lookups and pointer comparisons rather than
comparing sockaddr_rxrpc contents.  It also makes it easier to get hold of
the RTT.  The following changes are made to afs:

 (1) The addr_list struct's addrs[] elements now hold a peer struct pointer
     and a service ID rather than a sockaddr_rxrpc.

 (2) When displaying the transport address, rxrpc_kernel_remote_addr() is
     used.

 (3) The port arg is removed from afs_alloc_addrlist() since it's always
     overridden.

 (4) afs_merge_fs_addr4() and afs_merge_fs_addr6() do peer lookup and may
     now return an error that must be handled.

 (5) afs_find_server() now takes a peer pointer to specify the address.

 (6) afs_find_server(), afs_compare_fs_alists() and afs_merge_fs_addr[46]{}
     now do peer pointer comparison rather than address comparison.

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: linux-afs@lists.infradead.org
  • Loading branch information
David Howells committed Dec 24, 2023
1 parent 07f3502 commit 72904d7
Show file tree
Hide file tree
Showing 20 changed files with 273 additions and 238 deletions.
125 changes: 66 additions & 59 deletions fs/afs/addr_list.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,33 @@
#include "internal.h"
#include "afs_fs.h"

static void afs_free_addrlist(struct rcu_head *rcu)
{
struct afs_addr_list *alist = container_of(rcu, struct afs_addr_list, rcu);
unsigned int i;

for (i = 0; i < alist->nr_addrs; i++)
rxrpc_kernel_put_peer(alist->addrs[i].peer);
}

/*
* Release an address list.
*/
void afs_put_addrlist(struct afs_addr_list *alist)
{
if (alist && refcount_dec_and_test(&alist->usage))
kfree_rcu(alist, rcu);
call_rcu(&alist->rcu, afs_free_addrlist);
}

/*
* Allocate an address list.
*/
struct afs_addr_list *afs_alloc_addrlist(unsigned int nr,
unsigned short service,
unsigned short port)
struct afs_addr_list *afs_alloc_addrlist(unsigned int nr, u16 service_id)
{
struct afs_addr_list *alist;
unsigned int i;

_enter("%u,%u,%u", nr, service, port);
_enter("%u,%u", nr, service_id);

if (nr > AFS_MAX_ADDRESSES)
nr = AFS_MAX_ADDRESSES;
Expand All @@ -44,16 +51,8 @@ struct afs_addr_list *afs_alloc_addrlist(unsigned int nr,
refcount_set(&alist->usage, 1);
alist->max_addrs = nr;

for (i = 0; i < nr; i++) {
struct sockaddr_rxrpc *srx = &alist->addrs[i].srx;
srx->srx_family = AF_RXRPC;
srx->srx_service = service;
srx->transport_type = SOCK_DGRAM;
srx->transport_len = sizeof(srx->transport.sin6);
srx->transport.sin6.sin6_family = AF_INET6;
srx->transport.sin6.sin6_port = htons(port);
}

for (i = 0; i < nr; i++)
alist->addrs[i].service_id = service_id;
return alist;
}

Expand Down Expand Up @@ -126,7 +125,7 @@ struct afs_vlserver_list *afs_parse_text_addrs(struct afs_net *net,
if (!vllist->servers[0].server)
goto error_vl;

alist = afs_alloc_addrlist(nr, service, AFS_VL_PORT);
alist = afs_alloc_addrlist(nr, service);
if (!alist)
goto error;

Expand Down Expand Up @@ -197,9 +196,11 @@ struct afs_vlserver_list *afs_parse_text_addrs(struct afs_net *net,
}

if (family == AF_INET)
afs_merge_fs_addr4(alist, x[0], xport);
ret = afs_merge_fs_addr4(net, alist, x[0], xport);
else
afs_merge_fs_addr6(alist, x, xport);
ret = afs_merge_fs_addr6(net, alist, x, xport);
if (ret < 0)
goto error;

} while (p < end);

Expand Down Expand Up @@ -271,25 +272,33 @@ struct afs_vlserver_list *afs_dns_query(struct afs_cell *cell, time64_t *_expiry
/*
* Merge an IPv4 entry into a fileserver address list.
*/
void afs_merge_fs_addr4(struct afs_addr_list *alist, __be32 xdr, u16 port)
int afs_merge_fs_addr4(struct afs_net *net, struct afs_addr_list *alist,
__be32 xdr, u16 port)
{
struct sockaddr_rxrpc *srx;
u32 addr = ntohl(xdr);
struct sockaddr_rxrpc srx;
struct rxrpc_peer *peer;
int i;

if (alist->nr_addrs >= alist->max_addrs)
return;
return 0;

for (i = 0; i < alist->nr_ipv4; i++) {
struct sockaddr_in *a = &alist->addrs[i].srx.transport.sin;
u32 a_addr = ntohl(a->sin_addr.s_addr);
u16 a_port = ntohs(a->sin_port);
srx.srx_family = AF_RXRPC;
srx.transport_type = SOCK_DGRAM;
srx.transport_len = sizeof(srx.transport.sin);
srx.transport.sin.sin_family = AF_INET;
srx.transport.sin.sin_port = htons(port);
srx.transport.sin.sin_addr.s_addr = xdr;

if (addr == a_addr && port == a_port)
return;
if (addr == a_addr && port < a_port)
break;
if (addr < a_addr)
peer = rxrpc_kernel_lookup_peer(net->socket, &srx, GFP_KERNEL);
if (!peer)
return -ENOMEM;

for (i = 0; i < alist->nr_ipv4; i++) {
if (peer == alist->addrs[i].peer) {
rxrpc_kernel_put_peer(peer);
return 0;
}
if (peer <= alist->addrs[i].peer)
break;
}

Expand All @@ -298,54 +307,52 @@ void afs_merge_fs_addr4(struct afs_addr_list *alist, __be32 xdr, u16 port)
alist->addrs + i,
sizeof(alist->addrs[0]) * (alist->nr_addrs - i));

srx = &alist->addrs[i].srx;
srx->srx_family = AF_RXRPC;
srx->transport_type = SOCK_DGRAM;
srx->transport_len = sizeof(srx->transport.sin);
srx->transport.sin.sin_family = AF_INET;
srx->transport.sin.sin_port = htons(port);
srx->transport.sin.sin_addr.s_addr = xdr;
alist->addrs[i].peer = peer;
alist->nr_ipv4++;
alist->nr_addrs++;
return 0;
}

/*
* Merge an IPv6 entry into a fileserver address list.
*/
void afs_merge_fs_addr6(struct afs_addr_list *alist, __be32 *xdr, u16 port)
int afs_merge_fs_addr6(struct afs_net *net, struct afs_addr_list *alist,
__be32 *xdr, u16 port)
{
struct sockaddr_rxrpc *srx;
int i, diff;
struct sockaddr_rxrpc srx;
struct rxrpc_peer *peer;
int i;

if (alist->nr_addrs >= alist->max_addrs)
return;
return 0;

for (i = alist->nr_ipv4; i < alist->nr_addrs; i++) {
struct sockaddr_in6 *a = &alist->addrs[i].srx.transport.sin6;
u16 a_port = ntohs(a->sin6_port);
srx.srx_family = AF_RXRPC;
srx.transport_type = SOCK_DGRAM;
srx.transport_len = sizeof(srx.transport.sin6);
srx.transport.sin6.sin6_family = AF_INET6;
srx.transport.sin6.sin6_port = htons(port);
memcpy(&srx.transport.sin6.sin6_addr, xdr, 16);

diff = memcmp(xdr, &a->sin6_addr, 16);
if (diff == 0 && port == a_port)
return;
if (diff == 0 && port < a_port)
break;
if (diff < 0)
peer = rxrpc_kernel_lookup_peer(net->socket, &srx, GFP_KERNEL);
if (!peer)
return -ENOMEM;

for (i = alist->nr_ipv4; i < alist->nr_addrs; i++) {
if (peer == alist->addrs[i].peer) {
rxrpc_kernel_put_peer(peer);
return 0;
}
if (peer <= alist->addrs[i].peer)
break;
}

if (i < alist->nr_addrs)
memmove(alist->addrs + i + 1,
alist->addrs + i,
sizeof(alist->addrs[0]) * (alist->nr_addrs - i));

srx = &alist->addrs[i].srx;
srx->srx_family = AF_RXRPC;
srx->transport_type = SOCK_DGRAM;
srx->transport_len = sizeof(srx->transport.sin6);
srx->transport.sin6.sin6_family = AF_INET6;
srx->transport.sin6.sin6_port = htons(port);
memcpy(&srx->transport.sin6.sin6_addr, xdr, 16);
alist->addrs[i].peer = peer;
alist->nr_addrs++;
return 0;
}

/*
Expand Down
5 changes: 3 additions & 2 deletions fs/afs/cmservice.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,11 @@ static int afs_find_cm_server_by_peer(struct afs_call *call)
{
struct sockaddr_rxrpc srx;
struct afs_server *server;
struct rxrpc_peer *peer;

rxrpc_kernel_get_peer(call->net->socket, call->rxcall, &srx);
peer = rxrpc_kernel_get_call_peer(call->net->socket, call->rxcall);

server = afs_find_server(call->net, &srx);
server = afs_find_server(call->net, peer);
if (!server) {
trace_afs_cm_no_server(call, &srx);
return 0;
Expand Down
11 changes: 6 additions & 5 deletions fs/afs/fs_probe.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ static void afs_fs_probe_not_done(struct afs_net *net,
void afs_fileserver_probe_result(struct afs_call *call)
{
struct afs_addr_list *alist = call->alist;
struct afs_address *addr = &alist->addrs[call->addr_ix];
struct afs_server *server = call->server;
unsigned int index = call->addr_ix;
unsigned int rtt_us = 0, cap0;
Expand Down Expand Up @@ -153,12 +154,12 @@ void afs_fileserver_probe_result(struct afs_call *call)
if (call->service_id == YFS_FS_SERVICE) {
server->probe.is_yfs = true;
set_bit(AFS_SERVER_FL_IS_YFS, &server->flags);
alist->addrs[index].srx.srx_service = call->service_id;
addr->service_id = call->service_id;
} else {
server->probe.not_yfs = true;
if (!server->probe.is_yfs) {
clear_bit(AFS_SERVER_FL_IS_YFS, &server->flags);
alist->addrs[index].srx.srx_service = call->service_id;
addr->service_id = call->service_id;
}
cap0 = ntohl(call->tmp);
if (cap0 & AFS3_VICED_CAPABILITY_64BITFILES)
Expand All @@ -167,7 +168,7 @@ void afs_fileserver_probe_result(struct afs_call *call)
clear_bit(AFS_SERVER_FL_HAS_FS64, &server->flags);
}

rxrpc_kernel_get_srtt(call->net->socket, call->rxcall, &rtt_us);
rtt_us = rxrpc_kernel_get_srtt(addr->peer);
if (rtt_us < server->probe.rtt) {
server->probe.rtt = rtt_us;
server->rtt = rtt_us;
Expand All @@ -181,8 +182,8 @@ void afs_fileserver_probe_result(struct afs_call *call)
out:
spin_unlock(&server->probe_lock);

_debug("probe %pU [%u] %pISpc rtt=%u ret=%d",
&server->uuid, index, &alist->addrs[index].srx.transport,
_debug("probe %pU [%u] %pISpc rtt=%d ret=%d",
&server->uuid, index, rxrpc_kernel_remote_addr(alist->addrs[index].peer),
rtt_us, ret);

return afs_done_one_fs_probe(call->net, server);
Expand Down
26 changes: 14 additions & 12 deletions fs/afs/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ enum afs_call_state {
AFS_CALL_COMPLETE, /* Completed or failed */
};

struct afs_address {
struct rxrpc_peer *peer;
u16 service_id;
};

/*
* List of server addresses.
*/
Expand All @@ -87,9 +92,7 @@ struct afs_addr_list {
enum dns_lookup_status status:8;
unsigned long failed; /* Mask of addrs that failed locally/ICMP */
unsigned long responded; /* Mask of addrs that responded */
struct {
struct sockaddr_rxrpc srx;
} addrs[] __counted_by(max_addrs);
struct afs_address addrs[] __counted_by(max_addrs);
#define AFS_MAX_ADDRESSES ((unsigned int)(sizeof(unsigned long) * 8))
};

Expand Down Expand Up @@ -420,7 +423,7 @@ struct afs_vlserver {
atomic_t probe_outstanding;
spinlock_t probe_lock;
struct {
unsigned int rtt; /* RTT in uS */
unsigned int rtt; /* Best RTT in uS (or UINT_MAX) */
u32 abort_code;
short error;
unsigned short flags;
Expand Down Expand Up @@ -537,7 +540,7 @@ struct afs_server {
atomic_t probe_outstanding;
spinlock_t probe_lock;
struct {
unsigned int rtt; /* RTT in uS */
unsigned int rtt; /* Best RTT in uS (or UINT_MAX) */
u32 abort_code;
short error;
bool responded:1;
Expand Down Expand Up @@ -964,9 +967,7 @@ static inline struct afs_addr_list *afs_get_addrlist(struct afs_addr_list *alist
refcount_inc(&alist->usage);
return alist;
}
extern struct afs_addr_list *afs_alloc_addrlist(unsigned int,
unsigned short,
unsigned short);
extern struct afs_addr_list *afs_alloc_addrlist(unsigned int nr, u16 service_id);
extern void afs_put_addrlist(struct afs_addr_list *);
extern struct afs_vlserver_list *afs_parse_text_addrs(struct afs_net *,
const char *, size_t, char,
Expand All @@ -977,8 +978,10 @@ extern struct afs_vlserver_list *afs_dns_query(struct afs_cell *, time64_t *);
extern bool afs_iterate_addresses(struct afs_addr_cursor *);
extern int afs_end_cursor(struct afs_addr_cursor *);

extern void afs_merge_fs_addr4(struct afs_addr_list *, __be32, u16);
extern void afs_merge_fs_addr6(struct afs_addr_list *, __be32 *, u16);
extern int afs_merge_fs_addr4(struct afs_net *net, struct afs_addr_list *addr,
__be32 xdr, u16 port);
extern int afs_merge_fs_addr6(struct afs_net *net, struct afs_addr_list *addr,
__be32 *xdr, u16 port);

/*
* callback.c
Expand Down Expand Up @@ -1405,8 +1408,7 @@ extern void __exit afs_clean_up_permit_cache(void);
*/
extern spinlock_t afs_server_peer_lock;

extern struct afs_server *afs_find_server(struct afs_net *,
const struct sockaddr_rxrpc *);
extern struct afs_server *afs_find_server(struct afs_net *, const struct rxrpc_peer *);
extern struct afs_server *afs_find_server_by_uuid(struct afs_net *, const uuid_t *);
extern struct afs_server *afs_lookup_server(struct afs_cell *, struct key *, const uuid_t *, u32);
extern struct afs_server *afs_get_server(struct afs_server *, enum afs_server_trace);
Expand Down
9 changes: 5 additions & 4 deletions fs/afs/proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v)
for (i = 0; i < alist->nr_addrs; i++)
seq_printf(m, " %c %pISpc\n",
alist->preferred == i ? '>' : '-',
&alist->addrs[i].srx.transport);
rxrpc_kernel_remote_addr(alist->addrs[i].peer));
}
seq_printf(m, " info: fl=%lx rtt=%d\n", vlserver->flags, vlserver->rtt);
seq_printf(m, " probe: fl=%x e=%d ac=%d out=%d\n",
Expand Down Expand Up @@ -398,9 +398,10 @@ static int afs_proc_servers_show(struct seq_file *m, void *v)
seq_printf(m, " - ALIST v=%u rsp=%lx f=%lx\n",
alist->version, alist->responded, alist->failed);
for (i = 0; i < alist->nr_addrs; i++)
seq_printf(m, " [%x] %pISpc%s\n",
i, &alist->addrs[i].srx.transport,
alist->preferred == i ? "*" : "");
seq_printf(m, " [%x] %pISpc%s rtt=%d\n",
i, rxrpc_kernel_remote_addr(alist->addrs[i].peer),
alist->preferred == i ? "*" : "",
rxrpc_kernel_get_srtt(alist->addrs[i].peer));
return 0;
}

Expand Down
6 changes: 3 additions & 3 deletions fs/afs/rotate.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ bool afs_select_fileserver(struct afs_operation *op)
struct afs_server *server;
struct afs_vnode *vnode = op->file[0].vnode;
struct afs_error e;
u32 rtt;
unsigned int rtt;
int error = op->ac.error, i;

_enter("%lx[%d],%lx[%d],%d,%d",
Expand Down Expand Up @@ -420,7 +420,7 @@ bool afs_select_fileserver(struct afs_operation *op)
}

op->index = -1;
rtt = U32_MAX;
rtt = UINT_MAX;
for (i = 0; i < op->server_list->nr_servers; i++) {
struct afs_server *s = op->server_list->servers[i].server;

Expand Down Expand Up @@ -488,7 +488,7 @@ bool afs_select_fileserver(struct afs_operation *op)

_debug("address [%u] %u/%u %pISp",
op->index, op->ac.index, op->ac.alist->nr_addrs,
&op->ac.alist->addrs[op->ac.index].srx.transport);
rxrpc_kernel_remote_addr(op->ac.alist->addrs[op->ac.index].peer));

_leave(" = t");
return true;
Expand Down
Loading

0 comments on commit 72904d7

Please sign in to comment.