Message ID | 20231109154004.3317227-11-dhowells@redhat.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | afs: Fix probe handling, server rotation and RO volume callback handling | expand |
On Thu, Nov 9, 2023 at 11:40 AM David Howells <dhowells@redhat.com> wrote: > > 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 > --- > fs/afs/addr_list.c | 125 ++++++++++++++++++----------------- > fs/afs/cmservice.c | 5 +- > fs/afs/fs_probe.c | 11 +-- > fs/afs/internal.h | 26 ++++---- > fs/afs/proc.c | 9 +-- > fs/afs/rotate.c | 6 +- > fs/afs/rxrpc.c | 10 +-- > fs/afs/server.c | 41 ++---------- > fs/afs/vl_alias.c | 55 +-------------- > fs/afs/vl_list.c | 15 +++-- > fs/afs/vl_probe.c | 12 ++-- > fs/afs/vl_rotate.c | 6 +- > fs/afs/vlclient.c | 22 ++++-- > include/net/af_rxrpc.h | 15 +++-- > include/trace/events/rxrpc.h | 3 + > net/rxrpc/af_rxrpc.c | 62 ++++++++++++++--- > net/rxrpc/ar-internal.h | 2 +- > net/rxrpc/call_object.c | 17 ++--- > net/rxrpc/peer_object.c | 56 ++++++++++------ > net/rxrpc/sendmsg.c | 11 ++- > 20 files changed, 271 insertions(+), 238 deletions(-) > > diff --git a/fs/afs/addr_list.c b/fs/afs/addr_list.c > index ac05a59e9d46..519821f5aedc 100644 > --- a/fs/afs/addr_list.c > +++ b/fs/afs/addr_list.c > @@ -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; > @@ -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; > } > > @@ -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; > > @@ -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); > > @@ -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; > } > > @@ -298,38 +307,42 @@ 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; > } > > @@ -337,15 +350,9 @@ void afs_merge_fs_addr6(struct afs_addr_list *alist, __be32 *xdr, u16 port) > 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; > } > > /* > diff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c > index d4ddb20d6732..99a3f20bc786 100644 > --- a/fs/afs/cmservice.c > +++ b/fs/afs/cmservice.c > @@ -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; > diff --git a/fs/afs/fs_probe.c b/fs/afs/fs_probe.c > index 3dd24842f277..58d28b82571e 100644 > --- a/fs/afs/fs_probe.c > +++ b/fs/afs/fs_probe.c > @@ -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; > @@ -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) > @@ -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; > @@ -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); > diff --git a/fs/afs/internal.h b/fs/afs/internal.h > index ae874baee249..caf89edc0644 100644 > --- a/fs/afs/internal.h > +++ b/fs/afs/internal.h > @@ -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. > */ > @@ -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)) > }; > > @@ -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; > @@ -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; > @@ -963,9 +966,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, > @@ -976,8 +977,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 > @@ -1404,8 +1407,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); > diff --git a/fs/afs/proc.c b/fs/afs/proc.c > index ab9cd986cfd9..8a65a06908d2 100644 > --- a/fs/afs/proc.c > +++ b/fs/afs/proc.c > @@ -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", > @@ -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; > } > > diff --git a/fs/afs/rotate.c b/fs/afs/rotate.c > index 993e20d752d9..1c8f26a7f128 100644 > --- a/fs/afs/rotate.c > +++ b/fs/afs/rotate.c > @@ -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", > @@ -419,7 +419,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; > > @@ -487,7 +487,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; > diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c > index 2b1a31b4249c..1a18fcbdec80 100644 > --- a/fs/afs/rxrpc.c > +++ b/fs/afs/rxrpc.c > @@ -296,7 +296,8 @@ static void afs_notify_end_request_tx(struct sock *sock, > */ > void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp) > { > - struct sockaddr_rxrpc *srx = &ac->alist->addrs[ac->index].srx; > + struct afs_address *addr = &ac->alist->addrs[ac->index]; > + struct rxrpc_peer *peer = addr->peer; > struct rxrpc_call *rxcall; > struct msghdr msg; > struct kvec iov[1]; > @@ -304,7 +305,7 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp) > s64 tx_total_len; > int ret; > > - _enter(",{%pISp},", &srx->transport); > + _enter(",{%pISp},", rxrpc_kernel_remote_addr(addr->peer)); > > ASSERT(call->type != NULL); > ASSERT(call->type->name != NULL); > @@ -333,7 +334,7 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp) > } > > /* create a call */ > - rxcall = rxrpc_kernel_begin_call(call->net->socket, srx, call->key, > + rxcall = rxrpc_kernel_begin_call(call->net->socket, peer, call->key, > (unsigned long)call, > tx_total_len, > call->max_lifespan, > @@ -341,6 +342,7 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp) > (call->async ? > afs_wake_up_async_call : > afs_wake_up_call_waiter), > + addr->service_id, > call->upgrade, > (call->intr ? RXRPC_PREINTERRUPTIBLE : > RXRPC_UNINTERRUPTIBLE), > @@ -461,7 +463,7 @@ static void afs_log_error(struct afs_call *call, s32 remote_abort) > max = m + 1; > pr_notice("kAFS: Peer reported %s failure on %s [%pISp]\n", > msg, call->type->name, > - &call->alist->addrs[call->addr_ix].srx.transport); > + rxrpc_kernel_remote_addr(call->alist->addrs[call->addr_ix].peer)); > } > } > > diff --git a/fs/afs/server.c b/fs/afs/server.c > index 4b98788c7b12..831254d8ef9c 100644 > --- a/fs/afs/server.c > +++ b/fs/afs/server.c > @@ -21,13 +21,12 @@ static void __afs_put_server(struct afs_net *, struct afs_server *); > /* > * Find a server by one of its addresses. > */ > -struct afs_server *afs_find_server(struct afs_net *net, > - const struct sockaddr_rxrpc *srx) > +struct afs_server *afs_find_server(struct afs_net *net, const struct rxrpc_peer *peer) > { > const struct afs_addr_list *alist; > struct afs_server *server = NULL; > unsigned int i; > - int seq = 0, diff; > + int seq = 0; > > rcu_read_lock(); > > @@ -37,37 +36,11 @@ struct afs_server *afs_find_server(struct afs_net *net, > server = NULL; > read_seqbegin_or_lock(&net->fs_addr_lock, &seq); > > - if (srx->transport.family == AF_INET6) { > - const struct sockaddr_in6 *a = &srx->transport.sin6, *b; > - hlist_for_each_entry_rcu(server, &net->fs_addresses6, addr6_link) { > - alist = rcu_dereference(server->addresses); > - for (i = alist->nr_ipv4; i < alist->nr_addrs; i++) { > - b = &alist->addrs[i].srx.transport.sin6; > - diff = ((u16 __force)a->sin6_port - > - (u16 __force)b->sin6_port); > - if (diff == 0) > - diff = memcmp(&a->sin6_addr, > - &b->sin6_addr, > - sizeof(struct in6_addr)); > - if (diff == 0) > - goto found; > - } > - } > - } else { > - const struct sockaddr_in *a = &srx->transport.sin, *b; > - hlist_for_each_entry_rcu(server, &net->fs_addresses4, addr4_link) { > - alist = rcu_dereference(server->addresses); > - for (i = 0; i < alist->nr_ipv4; i++) { > - b = &alist->addrs[i].srx.transport.sin; > - diff = ((u16 __force)a->sin_port - > - (u16 __force)b->sin_port); > - if (diff == 0) > - diff = ((u32 __force)a->sin_addr.s_addr - > - (u32 __force)b->sin_addr.s_addr); > - if (diff == 0) > - goto found; > - } > - } > + hlist_for_each_entry_rcu(server, &net->fs_addresses6, addr6_link) { > + alist = rcu_dereference(server->addresses); > + for (i = 0; i < alist->nr_addrs; i++) > + if (alist->addrs[i].peer == peer) > + goto found; > } > > server = NULL; > diff --git a/fs/afs/vl_alias.c b/fs/afs/vl_alias.c > index d3c0df70a1a5..6fdf9f1bedc0 100644 > --- a/fs/afs/vl_alias.c > +++ b/fs/afs/vl_alias.c > @@ -32,55 +32,6 @@ static struct afs_volume *afs_sample_volume(struct afs_cell *cell, struct key *k > return volume; > } > > -/* > - * Compare two addresses. > - */ > -static int afs_compare_addrs(const struct sockaddr_rxrpc *srx_a, > - const struct sockaddr_rxrpc *srx_b) > -{ > - short port_a, port_b; > - int addr_a, addr_b, diff; > - > - diff = (short)srx_a->transport_type - (short)srx_b->transport_type; > - if (diff) > - goto out; > - > - switch (srx_a->transport_type) { > - case AF_INET: { > - const struct sockaddr_in *a = &srx_a->transport.sin; > - const struct sockaddr_in *b = &srx_b->transport.sin; > - addr_a = ntohl(a->sin_addr.s_addr); > - addr_b = ntohl(b->sin_addr.s_addr); > - diff = addr_a - addr_b; > - if (diff == 0) { > - port_a = ntohs(a->sin_port); > - port_b = ntohs(b->sin_port); > - diff = port_a - port_b; > - } > - break; > - } > - > - case AF_INET6: { > - const struct sockaddr_in6 *a = &srx_a->transport.sin6; > - const struct sockaddr_in6 *b = &srx_b->transport.sin6; > - diff = memcmp(&a->sin6_addr, &b->sin6_addr, 16); > - if (diff == 0) { > - port_a = ntohs(a->sin6_port); > - port_b = ntohs(b->sin6_port); > - diff = port_a - port_b; > - } > - break; > - } > - > - default: > - WARN_ON(1); > - diff = 1; > - } > - > -out: > - return diff; > -} > - > /* > * Compare the address lists of a pair of fileservers. > */ > @@ -94,9 +45,9 @@ static int afs_compare_fs_alists(const struct afs_server *server_a, > lb = rcu_dereference(server_b->addresses); > > while (a < la->nr_addrs && b < lb->nr_addrs) { > - const struct sockaddr_rxrpc *srx_a = &la->addrs[a].srx; > - const struct sockaddr_rxrpc *srx_b = &lb->addrs[b].srx; > - int diff = afs_compare_addrs(srx_a, srx_b); > + unsigned long pa = (unsigned long)la->addrs[a].peer; > + unsigned long pb = (unsigned long)lb->addrs[b].peer; > + long diff = pa - pb; > > if (diff < 0) { > a++; > diff --git a/fs/afs/vl_list.c b/fs/afs/vl_list.c > index acc48216136a..ba89140eee9e 100644 > --- a/fs/afs/vl_list.c > +++ b/fs/afs/vl_list.c > @@ -83,14 +83,15 @@ static u16 afs_extract_le16(const u8 **_b) > /* > * Build a VL server address list from a DNS queried server list. > */ > -static struct afs_addr_list *afs_extract_vl_addrs(const u8 **_b, const u8 *end, > +static struct afs_addr_list *afs_extract_vl_addrs(struct afs_net *net, > + const u8 **_b, const u8 *end, > u8 nr_addrs, u16 port) > { > struct afs_addr_list *alist; > const u8 *b = *_b; > int ret = -EINVAL; > > - alist = afs_alloc_addrlist(nr_addrs, VL_SERVICE, port); > + alist = afs_alloc_addrlist(nr_addrs, VL_SERVICE); > if (!alist) > return ERR_PTR(-ENOMEM); > if (nr_addrs == 0) > @@ -109,7 +110,9 @@ static struct afs_addr_list *afs_extract_vl_addrs(const u8 **_b, const u8 *end, > goto error; > } > memcpy(x, b, 4); > - afs_merge_fs_addr4(alist, x[0], port); > + ret = afs_merge_fs_addr4(net, alist, x[0], port); > + if (ret < 0) > + goto error; > b += 4; > break; > > @@ -119,7 +122,9 @@ static struct afs_addr_list *afs_extract_vl_addrs(const u8 **_b, const u8 *end, > goto error; > } > memcpy(x, b, 16); > - afs_merge_fs_addr6(alist, x, port); > + ret = afs_merge_fs_addr6(net, alist, x, port); > + if (ret < 0) > + goto error; > b += 16; > break; > > @@ -247,7 +252,7 @@ struct afs_vlserver_list *afs_extract_vlserver_list(struct afs_cell *cell, > /* Extract the addresses - note that we can't skip this as we > * have to advance the payload pointer. > */ > - addrs = afs_extract_vl_addrs(&b, end, bs.nr_addrs, bs.port); > + addrs = afs_extract_vl_addrs(cell->net, &b, end, bs.nr_addrs, bs.port); > if (IS_ERR(addrs)) { > ret = PTR_ERR(addrs); > goto error_2; > diff --git a/fs/afs/vl_probe.c b/fs/afs/vl_probe.c > index bdd9372e3fb2..9551aef07cee 100644 > --- a/fs/afs/vl_probe.c > +++ b/fs/afs/vl_probe.c > @@ -48,6 +48,7 @@ void afs_vlserver_probe_result(struct afs_call *call) > { > struct afs_addr_list *alist = call->alist; > struct afs_vlserver *server = call->vlserver; > + struct afs_address *addr = &alist->addrs[call->addr_ix]; > unsigned int server_index = call->server_index; > unsigned int rtt_us = 0; > unsigned int index = call->addr_ix; > @@ -106,16 +107,16 @@ void afs_vlserver_probe_result(struct afs_call *call) > if (call->service_id == YFS_VL_SERVICE) { > server->probe.flags |= AFS_VLSERVER_PROBE_IS_YFS; > set_bit(AFS_VLSERVER_FL_IS_YFS, &server->flags); > - alist->addrs[index].srx.srx_service = call->service_id; > + addr->service_id = call->service_id; > } else { > server->probe.flags |= AFS_VLSERVER_PROBE_NOT_YFS; > if (!(server->probe.flags & AFS_VLSERVER_PROBE_IS_YFS)) { > clear_bit(AFS_VLSERVER_FL_IS_YFS, &server->flags); > - alist->addrs[index].srx.srx_service = call->service_id; > + addr->service_id = call->service_id; > } > } > > - 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; > @@ -130,8 +131,9 @@ void afs_vlserver_probe_result(struct afs_call *call) > out: > spin_unlock(&server->probe_lock); > > - _debug("probe [%u][%u] %pISpc rtt=%u ret=%d", > - server_index, index, &alist->addrs[index].srx.transport, rtt_us, ret); > + _debug("probe [%u][%u] %pISpc rtt=%d ret=%d", > + server_index, index, rxrpc_kernel_remote_addr(addr->peer), > + rtt_us, ret); > > afs_done_one_vl_probe(server, have_result); > } > diff --git a/fs/afs/vl_rotate.c b/fs/afs/vl_rotate.c > index 0d0b54819128..af445e7d3a12 100644 > --- a/fs/afs/vl_rotate.c > +++ b/fs/afs/vl_rotate.c > @@ -86,7 +86,7 @@ bool afs_select_vlserver(struct afs_vl_cursor *vc) > struct afs_addr_list *alist; > struct afs_vlserver *vlserver; > struct afs_error e; > - u32 rtt; > + unsigned int rtt; > int error = vc->ac.error, i; > > _enter("%lx[%d],%lx[%d],%d,%d", > @@ -188,7 +188,7 @@ bool afs_select_vlserver(struct afs_vl_cursor *vc) > goto selected_server; > > vc->index = -1; > - rtt = U32_MAX; > + rtt = UINT_MAX; > for (i = 0; i < vc->server_list->nr_servers; i++) { > struct afs_vlserver *s = vc->server_list->servers[i].server; > > @@ -243,7 +243,7 @@ bool afs_select_vlserver(struct afs_vl_cursor *vc) > > _debug("VL address %d/%d", vc->ac.index, vc->ac.alist->nr_addrs); > > - _leave(" = t %pISpc", &vc->ac.alist->addrs[vc->ac.index].srx.transport); > + _leave(" = t %pISpc", rxrpc_kernel_remote_addr(vc->ac.alist->addrs[vc->ac.index].peer)); > return true; > > next_server: > diff --git a/fs/afs/vlclient.c b/fs/afs/vlclient.c > index 00fca3c66ba6..41e7932d75c6 100644 > --- a/fs/afs/vlclient.c > +++ b/fs/afs/vlclient.c > @@ -208,7 +208,7 @@ static int afs_deliver_vl_get_addrs_u(struct afs_call *call) > count = ntohl(*bp); > > nentries = min(nentries, count); > - alist = afs_alloc_addrlist(nentries, FS_SERVICE, AFS_FS_PORT); > + alist = afs_alloc_addrlist(nentries, FS_SERVICE); > if (!alist) > return -ENOMEM; > alist->version = uniquifier; > @@ -230,9 +230,13 @@ static int afs_deliver_vl_get_addrs_u(struct afs_call *call) > alist = call->ret_alist; > bp = call->buffer; > count = min(call->count, 4U); > - for (i = 0; i < count; i++) > - if (alist->nr_addrs < call->count2) > - afs_merge_fs_addr4(alist, *bp++, AFS_FS_PORT); > + for (i = 0; i < count; i++) { > + if (alist->nr_addrs < call->count2) { > + ret = afs_merge_fs_addr4(call->net, alist, *bp++, AFS_FS_PORT); > + if (ret < 0) > + return ret; > + } > + } > > call->count -= count; > if (call->count > 0) > @@ -450,7 +454,7 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call) > if (call->count > YFS_MAXENDPOINTS) > return afs_protocol_error(call, afs_eproto_yvl_fsendpt_num); > > - alist = afs_alloc_addrlist(call->count, FS_SERVICE, AFS_FS_PORT); > + alist = afs_alloc_addrlist(call->count, FS_SERVICE); > if (!alist) > return -ENOMEM; > alist->version = uniquifier; > @@ -488,14 +492,18 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call) > if (ntohl(bp[0]) != sizeof(__be32) * 2) > return afs_protocol_error( > call, afs_eproto_yvl_fsendpt4_len); > - afs_merge_fs_addr4(alist, bp[1], ntohl(bp[2])); > + ret = afs_merge_fs_addr4(call->net, alist, bp[1], ntohl(bp[2])); > + if (ret < 0) > + return ret; > bp += 3; > break; > case YFS_ENDPOINT_IPV6: > if (ntohl(bp[0]) != sizeof(__be32) * 5) > return afs_protocol_error( > call, afs_eproto_yvl_fsendpt6_len); > - afs_merge_fs_addr6(alist, bp + 1, ntohl(bp[5])); > + ret = afs_merge_fs_addr6(call->net, alist, bp + 1, ntohl(bp[5])); > + if (ret < 0) > + return ret; > bp += 6; > break; > default: > diff --git a/include/net/af_rxrpc.h b/include/net/af_rxrpc.h > index 5531dd08061e..0754c463224a 100644 > --- a/include/net/af_rxrpc.h > +++ b/include/net/af_rxrpc.h > @@ -15,6 +15,7 @@ struct key; > struct sock; > struct socket; > struct rxrpc_call; > +struct rxrpc_peer; > enum rxrpc_abort_reason; > > enum rxrpc_interruptibility { > @@ -41,13 +42,14 @@ void rxrpc_kernel_new_call_notification(struct socket *, > rxrpc_notify_new_call_t, > rxrpc_discard_new_call_t); > struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock, > - struct sockaddr_rxrpc *srx, > + struct rxrpc_peer *peer, > struct key *key, > unsigned long user_call_ID, > s64 tx_total_len, > u32 hard_timeout, > gfp_t gfp, > rxrpc_notify_rx_t notify_rx, > + u16 service_id, > bool upgrade, > enum rxrpc_interruptibility interruptibility, > unsigned int debug_id); > @@ -60,9 +62,14 @@ bool rxrpc_kernel_abort_call(struct socket *, struct rxrpc_call *, > u32, int, enum rxrpc_abort_reason); > void rxrpc_kernel_shutdown_call(struct socket *sock, struct rxrpc_call *call); > void rxrpc_kernel_put_call(struct socket *sock, struct rxrpc_call *call); > -void rxrpc_kernel_get_peer(struct socket *, struct rxrpc_call *, > - struct sockaddr_rxrpc *); > -bool rxrpc_kernel_get_srtt(struct socket *, struct rxrpc_call *, u32 *); > +struct rxrpc_peer *rxrpc_kernel_lookup_peer(struct socket *sock, > + struct sockaddr_rxrpc *srx, gfp_t gfp); > +void rxrpc_kernel_put_peer(struct rxrpc_peer *peer); > +struct rxrpc_peer *rxrpc_kernel_get_peer(struct rxrpc_peer *peer); > +struct rxrpc_peer *rxrpc_kernel_get_call_peer(struct socket *sock, struct rxrpc_call *call); > +const struct sockaddr_rxrpc *rxrpc_kernel_remote_srx(const struct rxrpc_peer *peer); > +const struct sockaddr *rxrpc_kernel_remote_addr(const struct rxrpc_peer *peer); > +unsigned int rxrpc_kernel_get_srtt(const struct rxrpc_peer *); > int rxrpc_kernel_charge_accept(struct socket *, rxrpc_notify_rx_t, > rxrpc_user_attach_call_t, unsigned long, gfp_t, > unsigned int); > diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h > index 4c53a5ef6257..90a1e39d620e 100644 > --- a/include/trace/events/rxrpc.h > +++ b/include/trace/events/rxrpc.h > @@ -178,7 +178,9 @@ > #define rxrpc_peer_traces \ > EM(rxrpc_peer_free, "FREE ") \ > EM(rxrpc_peer_get_accept, "GET accept ") \ > + EM(rxrpc_peer_get_application, "GET app ") \ > EM(rxrpc_peer_get_bundle, "GET bundle ") \ > + EM(rxrpc_peer_get_call, "GET call ") \ > EM(rxrpc_peer_get_client_conn, "GET cln-conn") \ > EM(rxrpc_peer_get_input, "GET input ") \ > EM(rxrpc_peer_get_input_error, "GET inpt-err") \ > @@ -187,6 +189,7 @@ > EM(rxrpc_peer_get_service_conn, "GET srv-conn") \ > EM(rxrpc_peer_new_client, "NEW client ") \ > EM(rxrpc_peer_new_prealloc, "NEW prealloc") \ > + EM(rxrpc_peer_put_application, "PUT app ") \ > EM(rxrpc_peer_put_bundle, "PUT bundle ") \ > EM(rxrpc_peer_put_call, "PUT call ") \ > EM(rxrpc_peer_put_conn, "PUT conn ") \ > diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c > index fa8aec78f63d..465bfe5eb061 100644 > --- a/net/rxrpc/af_rxrpc.c > +++ b/net/rxrpc/af_rxrpc.c > @@ -258,16 +258,62 @@ static int rxrpc_listen(struct socket *sock, int backlog) > return ret; > } > > +/** > + * rxrpc_kernel_lookup_peer - Obtain remote transport endpoint for an address > + * @sock: The socket through which it will be accessed > + * @srx: The network address > + * @gfp: Allocation flags > + * > + * Lookup or create a remote transport endpoint record for the specified > + * address and return it with a ref held. > + */ > +struct rxrpc_peer *rxrpc_kernel_lookup_peer(struct socket *sock, > + struct sockaddr_rxrpc *srx, gfp_t gfp) > +{ > + struct rxrpc_sock *rx = rxrpc_sk(sock->sk); > + int ret; > + > + ret = rxrpc_validate_address(rx, srx, sizeof(*srx)); > + if (ret < 0) > + return ERR_PTR(ret); > + > + return rxrpc_lookup_peer(rx->local, srx, gfp); > +} > +EXPORT_SYMBOL(rxrpc_kernel_lookup_peer); > + > +/** > + * rxrpc_kernel_get_peer - Get a reference on a peer > + * @peer: The peer to get a reference on. > + * > + * Get a record for the remote peer in a call. > + */ > +struct rxrpc_peer *rxrpc_kernel_get_peer(struct rxrpc_peer *peer) > +{ > + return peer ? rxrpc_get_peer(peer, rxrpc_peer_get_application) : NULL; > +} > +EXPORT_SYMBOL(rxrpc_kernel_get_peer); > + > +/** > + * rxrpc_kernel_put_peer - Allow a kernel app to drop a peer reference > + * @peer: The peer to drop a ref on > + */ > +void rxrpc_kernel_put_peer(struct rxrpc_peer *peer) > +{ > + rxrpc_put_peer(peer, rxrpc_peer_put_application); > +} > +EXPORT_SYMBOL(rxrpc_kernel_put_peer); > + > /** > * rxrpc_kernel_begin_call - Allow a kernel service to begin a call > * @sock: The socket on which to make the call > - * @srx: The address of the peer to contact > + * @peer: The peer to contact > * @key: The security context to use (defaults to socket setting) > * @user_call_ID: The ID to use > * @tx_total_len: Total length of data to transmit during the call (or -1) > * @hard_timeout: The maximum lifespan of the call in sec > * @gfp: The allocation constraints > * @notify_rx: Where to send notifications instead of socket queue > + * @service_id: The ID of the service to contact > * @upgrade: Request service upgrade for call > * @interruptibility: The call is interruptible, or can be canceled. > * @debug_id: The debug ID for tracing to be assigned to the call > @@ -280,13 +326,14 @@ static int rxrpc_listen(struct socket *sock, int backlog) > * supplying @srx and @key. > */ > struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock, > - struct sockaddr_rxrpc *srx, > + struct rxrpc_peer *peer, > struct key *key, > unsigned long user_call_ID, > s64 tx_total_len, > u32 hard_timeout, > gfp_t gfp, > rxrpc_notify_rx_t notify_rx, > + u16 service_id, > bool upgrade, > enum rxrpc_interruptibility interruptibility, > unsigned int debug_id) > @@ -295,13 +342,11 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock, > struct rxrpc_call_params p; > struct rxrpc_call *call; > struct rxrpc_sock *rx = rxrpc_sk(sock->sk); > - int ret; > > _enter(",,%x,%lx", key_serial(key), user_call_ID); > > - ret = rxrpc_validate_address(rx, srx, sizeof(*srx)); > - if (ret < 0) > - return ERR_PTR(ret); > + if (WARN_ON_ONCE(peer->local != rx->local)) > + return ERR_PTR(-EIO); > > lock_sock(&rx->sk); > > @@ -319,12 +364,13 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock, > > memset(&cp, 0, sizeof(cp)); > cp.local = rx->local; > + cp.peer = peer; > cp.key = key; > cp.security_level = rx->min_sec_level; > cp.exclusive = false; > cp.upgrade = upgrade; > - cp.service_id = srx->srx_service; > - call = rxrpc_new_client_call(rx, &cp, srx, &p, gfp, debug_id); > + cp.service_id = service_id; > + call = rxrpc_new_client_call(rx, &cp, &p, gfp, debug_id); > /* The socket has been unlocked. */ > if (!IS_ERR(call)) { > call->notify_rx = notify_rx; > diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h > index e8e14c6f904d..8eea7a487380 100644 > --- a/net/rxrpc/ar-internal.h > +++ b/net/rxrpc/ar-internal.h > @@ -364,6 +364,7 @@ struct rxrpc_conn_proto { > > struct rxrpc_conn_parameters { > struct rxrpc_local *local; /* Representation of local endpoint */ > + struct rxrpc_peer *peer; /* Representation of remote endpoint */ > struct key *key; /* Security details */ > bool exclusive; /* T if conn is exclusive */ > bool upgrade; /* T if service ID can be upgraded */ > @@ -867,7 +868,6 @@ struct rxrpc_call *rxrpc_find_call_by_user_ID(struct rxrpc_sock *, unsigned long > struct rxrpc_call *rxrpc_alloc_call(struct rxrpc_sock *, gfp_t, unsigned int); > struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *, > struct rxrpc_conn_parameters *, > - struct sockaddr_rxrpc *, > struct rxrpc_call_params *, gfp_t, > unsigned int); > void rxrpc_start_call_timer(struct rxrpc_call *call); > diff --git a/net/rxrpc/call_object.c b/net/rxrpc/call_object.c > index 773eecd1e979..beea25ac88f5 100644 > --- a/net/rxrpc/call_object.c > +++ b/net/rxrpc/call_object.c > @@ -193,7 +193,6 @@ struct rxrpc_call *rxrpc_alloc_call(struct rxrpc_sock *rx, gfp_t gfp, > * Allocate a new client call. > */ > static struct rxrpc_call *rxrpc_alloc_client_call(struct rxrpc_sock *rx, > - struct sockaddr_rxrpc *srx, > struct rxrpc_conn_parameters *cp, > struct rxrpc_call_params *p, > gfp_t gfp, > @@ -211,10 +210,12 @@ static struct rxrpc_call *rxrpc_alloc_client_call(struct rxrpc_sock *rx, > now = ktime_get_real(); > call->acks_latest_ts = now; > call->cong_tstamp = now; > - call->dest_srx = *srx; > + call->dest_srx = cp->peer->srx; > + call->dest_srx.srx_service = cp->service_id; > call->interruptibility = p->interruptibility; > call->tx_total_len = p->tx_total_len; > call->key = key_get(cp->key); > + call->peer = rxrpc_get_peer(cp->peer, rxrpc_peer_get_call); > call->local = rxrpc_get_local(cp->local, rxrpc_local_get_call); > call->security_level = cp->security_level; > if (p->kernel) > @@ -306,10 +307,6 @@ static int rxrpc_connect_call(struct rxrpc_call *call, gfp_t gfp) > > _enter("{%d,%lx},", call->debug_id, call->user_call_ID); > > - call->peer = rxrpc_lookup_peer(local, &call->dest_srx, gfp); > - if (!call->peer) > - goto error; > - > ret = rxrpc_look_up_bundle(call, gfp); > if (ret < 0) > goto error; > @@ -334,7 +331,6 @@ static int rxrpc_connect_call(struct rxrpc_call *call, gfp_t gfp) > */ > struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx, > struct rxrpc_conn_parameters *cp, > - struct sockaddr_rxrpc *srx, > struct rxrpc_call_params *p, > gfp_t gfp, > unsigned int debug_id) > @@ -349,13 +345,18 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx, > > _enter("%p,%lx", rx, p->user_call_ID); > > + if (WARN_ON_ONCE(!cp->peer)) { > + release_sock(&rx->sk); > + return ERR_PTR(-EIO); > + } > + > limiter = rxrpc_get_call_slot(p, gfp); > if (!limiter) { > release_sock(&rx->sk); > return ERR_PTR(-ERESTARTSYS); > } > > - call = rxrpc_alloc_client_call(rx, srx, cp, p, gfp, debug_id); > + call = rxrpc_alloc_client_call(rx, cp, p, gfp, debug_id); > if (IS_ERR(call)) { > release_sock(&rx->sk); > up(limiter); > diff --git a/net/rxrpc/peer_object.c b/net/rxrpc/peer_object.c > index 8d7a715a0bb1..65ea57b427a1 100644 > --- a/net/rxrpc/peer_object.c > +++ b/net/rxrpc/peer_object.c > @@ -22,6 +22,8 @@ > #include <net/ip6_route.h> > #include "ar-internal.h" > > +static const struct sockaddr_rxrpc rxrpc_null_addr; > + > /* > * Hash a peer key. > */ > @@ -457,39 +459,51 @@ void rxrpc_destroy_all_peers(struct rxrpc_net *rxnet) > } > > /** > - * rxrpc_kernel_get_peer - Get the peer address of a call > + * rxrpc_kernel_get_call_peer - Get the peer address of a call > * @sock: The socket on which the call is in progress. > * @call: The call to query > - * @_srx: Where to place the result > * > - * Get the address of the remote peer in a call. > + * Get a record for the remote peer in a call. > */ > -void rxrpc_kernel_get_peer(struct socket *sock, struct rxrpc_call *call, > - struct sockaddr_rxrpc *_srx) > +struct rxrpc_peer *rxrpc_kernel_get_call_peer(struct socket *sock, struct rxrpc_call *call) > { > - *_srx = call->peer->srx; > + return call->peer; > } > -EXPORT_SYMBOL(rxrpc_kernel_get_peer); > +EXPORT_SYMBOL(rxrpc_kernel_get_call_peer); > > /** > * rxrpc_kernel_get_srtt - Get a call's peer smoothed RTT > - * @sock: The socket on which the call is in progress. > - * @call: The call to query > - * @_srtt: Where to store the SRTT value. > + * @peer: The peer to query > * > - * Get the call's peer smoothed RTT in uS. > + * Get the call's peer smoothed RTT in uS or UINT_MAX if we have no samples. > */ > -bool rxrpc_kernel_get_srtt(struct socket *sock, struct rxrpc_call *call, > - u32 *_srtt) > +unsigned int rxrpc_kernel_get_srtt(const struct rxrpc_peer *peer) > { > - struct rxrpc_peer *peer = call->peer; > + return peer->rtt_count > 0 ? peer->srtt_us >> 3 : UINT_MAX; > +} > +EXPORT_SYMBOL(rxrpc_kernel_get_srtt); > > - if (peer->rtt_count == 0) { > - *_srtt = 1000000; /* 1S */ > - return false; > - } > +/** > + * rxrpc_kernel_remote_srx - Get the address of a peer > + * @peer: The peer to query > + * > + * Get a pointer to the address from a peer record. The caller is responsible > + * for making sure that the address is not deallocated. > + */ > +const struct sockaddr_rxrpc *rxrpc_kernel_remote_srx(const struct rxrpc_peer *peer) > +{ > + return peer ? &peer->srx : &rxrpc_null_addr; > +} > > - *_srtt = call->peer->srtt_us >> 3; > - return true; > +/** > + * rxrpc_kernel_remote_addr - Get the peer transport address of a call > + * @peer: The peer to query > + * > + * Get a pointer to the transport address from a peer record. The caller is > + * responsible for making sure that the address is not deallocated. > + */ > +const struct sockaddr *rxrpc_kernel_remote_addr(const struct rxrpc_peer *peer) > +{ > + return (const struct sockaddr *) > + (peer ? &peer->srx.transport : &rxrpc_null_addr.transport); > } > -EXPORT_SYMBOL(rxrpc_kernel_get_srtt); > diff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c > index 8e0b94714e84..5677d5690a02 100644 > --- a/net/rxrpc/sendmsg.c > +++ b/net/rxrpc/sendmsg.c > @@ -572,6 +572,7 @@ rxrpc_new_client_call_for_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, > __acquires(&call->user_mutex) > { > struct rxrpc_conn_parameters cp; > + struct rxrpc_peer *peer; > struct rxrpc_call *call; > struct key *key; > > @@ -584,21 +585,29 @@ rxrpc_new_client_call_for_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, > return ERR_PTR(-EDESTADDRREQ); > } > > + peer = rxrpc_lookup_peer(rx->local, srx, GFP_KERNEL); > + if (!peer) { > + release_sock(&rx->sk); > + return ERR_PTR(-ENOMEM); > + } > + > key = rx->key; > if (key && !rx->key->payload.data[0]) > key = NULL; > > memset(&cp, 0, sizeof(cp)); > cp.local = rx->local; > + cp.peer = peer; > cp.key = rx->key; > cp.security_level = rx->min_sec_level; > cp.exclusive = rx->exclusive | p->exclusive; > cp.upgrade = p->upgrade; > cp.service_id = srx->srx_service; > - call = rxrpc_new_client_call(rx, &cp, srx, &p->call, GFP_KERNEL, > + call = rxrpc_new_client_call(rx, &cp, &p->call, GFP_KERNEL, > atomic_inc_return(&rxrpc_debug_id)); > /* The socket is now unlocked */ > > + rxrpc_put_peer(peer, rxrpc_peer_put_application); > _leave(" = %p\n", call); > return call; > } rxrpc_kernel_remote_srx and rxrpc_kernel_remote_addr need an EXPORT_SYMBOL to be available to fs/afs when built as a module. Marc
diff --git a/fs/afs/addr_list.c b/fs/afs/addr_list.c index ac05a59e9d46..519821f5aedc 100644 --- a/fs/afs/addr_list.c +++ b/fs/afs/addr_list.c @@ -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; @@ -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; } @@ -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; @@ -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); @@ -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; } @@ -298,38 +307,42 @@ 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; } @@ -337,15 +350,9 @@ void afs_merge_fs_addr6(struct afs_addr_list *alist, __be32 *xdr, u16 port) 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; } /* diff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c index d4ddb20d6732..99a3f20bc786 100644 --- a/fs/afs/cmservice.c +++ b/fs/afs/cmservice.c @@ -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; diff --git a/fs/afs/fs_probe.c b/fs/afs/fs_probe.c index 3dd24842f277..58d28b82571e 100644 --- a/fs/afs/fs_probe.c +++ b/fs/afs/fs_probe.c @@ -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; @@ -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) @@ -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; @@ -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); diff --git a/fs/afs/internal.h b/fs/afs/internal.h index ae874baee249..caf89edc0644 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -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. */ @@ -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)) }; @@ -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; @@ -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; @@ -963,9 +966,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, @@ -976,8 +977,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 @@ -1404,8 +1407,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); diff --git a/fs/afs/proc.c b/fs/afs/proc.c index ab9cd986cfd9..8a65a06908d2 100644 --- a/fs/afs/proc.c +++ b/fs/afs/proc.c @@ -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", @@ -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; } diff --git a/fs/afs/rotate.c b/fs/afs/rotate.c index 993e20d752d9..1c8f26a7f128 100644 --- a/fs/afs/rotate.c +++ b/fs/afs/rotate.c @@ -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", @@ -419,7 +419,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; @@ -487,7 +487,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; diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c index 2b1a31b4249c..1a18fcbdec80 100644 --- a/fs/afs/rxrpc.c +++ b/fs/afs/rxrpc.c @@ -296,7 +296,8 @@ static void afs_notify_end_request_tx(struct sock *sock, */ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp) { - struct sockaddr_rxrpc *srx = &ac->alist->addrs[ac->index].srx; + struct afs_address *addr = &ac->alist->addrs[ac->index]; + struct rxrpc_peer *peer = addr->peer; struct rxrpc_call *rxcall; struct msghdr msg; struct kvec iov[1]; @@ -304,7 +305,7 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp) s64 tx_total_len; int ret; - _enter(",{%pISp},", &srx->transport); + _enter(",{%pISp},", rxrpc_kernel_remote_addr(addr->peer)); ASSERT(call->type != NULL); ASSERT(call->type->name != NULL); @@ -333,7 +334,7 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp) } /* create a call */ - rxcall = rxrpc_kernel_begin_call(call->net->socket, srx, call->key, + rxcall = rxrpc_kernel_begin_call(call->net->socket, peer, call->key, (unsigned long)call, tx_total_len, call->max_lifespan, @@ -341,6 +342,7 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp) (call->async ? afs_wake_up_async_call : afs_wake_up_call_waiter), + addr->service_id, call->upgrade, (call->intr ? RXRPC_PREINTERRUPTIBLE : RXRPC_UNINTERRUPTIBLE), @@ -461,7 +463,7 @@ static void afs_log_error(struct afs_call *call, s32 remote_abort) max = m + 1; pr_notice("kAFS: Peer reported %s failure on %s [%pISp]\n", msg, call->type->name, - &call->alist->addrs[call->addr_ix].srx.transport); + rxrpc_kernel_remote_addr(call->alist->addrs[call->addr_ix].peer)); } } diff --git a/fs/afs/server.c b/fs/afs/server.c index 4b98788c7b12..831254d8ef9c 100644 --- a/fs/afs/server.c +++ b/fs/afs/server.c @@ -21,13 +21,12 @@ static void __afs_put_server(struct afs_net *, struct afs_server *); /* * Find a server by one of its addresses. */ -struct afs_server *afs_find_server(struct afs_net *net, - const struct sockaddr_rxrpc *srx) +struct afs_server *afs_find_server(struct afs_net *net, const struct rxrpc_peer *peer) { const struct afs_addr_list *alist; struct afs_server *server = NULL; unsigned int i; - int seq = 0, diff; + int seq = 0; rcu_read_lock(); @@ -37,37 +36,11 @@ struct afs_server *afs_find_server(struct afs_net *net, server = NULL; read_seqbegin_or_lock(&net->fs_addr_lock, &seq); - if (srx->transport.family == AF_INET6) { - const struct sockaddr_in6 *a = &srx->transport.sin6, *b; - hlist_for_each_entry_rcu(server, &net->fs_addresses6, addr6_link) { - alist = rcu_dereference(server->addresses); - for (i = alist->nr_ipv4; i < alist->nr_addrs; i++) { - b = &alist->addrs[i].srx.transport.sin6; - diff = ((u16 __force)a->sin6_port - - (u16 __force)b->sin6_port); - if (diff == 0) - diff = memcmp(&a->sin6_addr, - &b->sin6_addr, - sizeof(struct in6_addr)); - if (diff == 0) - goto found; - } - } - } else { - const struct sockaddr_in *a = &srx->transport.sin, *b; - hlist_for_each_entry_rcu(server, &net->fs_addresses4, addr4_link) { - alist = rcu_dereference(server->addresses); - for (i = 0; i < alist->nr_ipv4; i++) { - b = &alist->addrs[i].srx.transport.sin; - diff = ((u16 __force)a->sin_port - - (u16 __force)b->sin_port); - if (diff == 0) - diff = ((u32 __force)a->sin_addr.s_addr - - (u32 __force)b->sin_addr.s_addr); - if (diff == 0) - goto found; - } - } + hlist_for_each_entry_rcu(server, &net->fs_addresses6, addr6_link) { + alist = rcu_dereference(server->addresses); + for (i = 0; i < alist->nr_addrs; i++) + if (alist->addrs[i].peer == peer) + goto found; } server = NULL; diff --git a/fs/afs/vl_alias.c b/fs/afs/vl_alias.c index d3c0df70a1a5..6fdf9f1bedc0 100644 --- a/fs/afs/vl_alias.c +++ b/fs/afs/vl_alias.c @@ -32,55 +32,6 @@ static struct afs_volume *afs_sample_volume(struct afs_cell *cell, struct key *k return volume; } -/* - * Compare two addresses. - */ -static int afs_compare_addrs(const struct sockaddr_rxrpc *srx_a, - const struct sockaddr_rxrpc *srx_b) -{ - short port_a, port_b; - int addr_a, addr_b, diff; - - diff = (short)srx_a->transport_type - (short)srx_b->transport_type; - if (diff) - goto out; - - switch (srx_a->transport_type) { - case AF_INET: { - const struct sockaddr_in *a = &srx_a->transport.sin; - const struct sockaddr_in *b = &srx_b->transport.sin; - addr_a = ntohl(a->sin_addr.s_addr); - addr_b = ntohl(b->sin_addr.s_addr); - diff = addr_a - addr_b; - if (diff == 0) { - port_a = ntohs(a->sin_port); - port_b = ntohs(b->sin_port); - diff = port_a - port_b; - } - break; - } - - case AF_INET6: { - const struct sockaddr_in6 *a = &srx_a->transport.sin6; - const struct sockaddr_in6 *b = &srx_b->transport.sin6; - diff = memcmp(&a->sin6_addr, &b->sin6_addr, 16); - if (diff == 0) { - port_a = ntohs(a->sin6_port); - port_b = ntohs(b->sin6_port); - diff = port_a - port_b; - } - break; - } - - default: - WARN_ON(1); - diff = 1; - } - -out: - return diff; -} - /* * Compare the address lists of a pair of fileservers. */ @@ -94,9 +45,9 @@ static int afs_compare_fs_alists(const struct afs_server *server_a, lb = rcu_dereference(server_b->addresses); while (a < la->nr_addrs && b < lb->nr_addrs) { - const struct sockaddr_rxrpc *srx_a = &la->addrs[a].srx; - const struct sockaddr_rxrpc *srx_b = &lb->addrs[b].srx; - int diff = afs_compare_addrs(srx_a, srx_b); + unsigned long pa = (unsigned long)la->addrs[a].peer; + unsigned long pb = (unsigned long)lb->addrs[b].peer; + long diff = pa - pb; if (diff < 0) { a++; diff --git a/fs/afs/vl_list.c b/fs/afs/vl_list.c index acc48216136a..ba89140eee9e 100644 --- a/fs/afs/vl_list.c +++ b/fs/afs/vl_list.c @@ -83,14 +83,15 @@ static u16 afs_extract_le16(const u8 **_b) /* * Build a VL server address list from a DNS queried server list. */ -static struct afs_addr_list *afs_extract_vl_addrs(const u8 **_b, const u8 *end, +static struct afs_addr_list *afs_extract_vl_addrs(struct afs_net *net, + const u8 **_b, const u8 *end, u8 nr_addrs, u16 port) { struct afs_addr_list *alist; const u8 *b = *_b; int ret = -EINVAL; - alist = afs_alloc_addrlist(nr_addrs, VL_SERVICE, port); + alist = afs_alloc_addrlist(nr_addrs, VL_SERVICE); if (!alist) return ERR_PTR(-ENOMEM); if (nr_addrs == 0) @@ -109,7 +110,9 @@ static struct afs_addr_list *afs_extract_vl_addrs(const u8 **_b, const u8 *end, goto error; } memcpy(x, b, 4); - afs_merge_fs_addr4(alist, x[0], port); + ret = afs_merge_fs_addr4(net, alist, x[0], port); + if (ret < 0) + goto error; b += 4; break; @@ -119,7 +122,9 @@ static struct afs_addr_list *afs_extract_vl_addrs(const u8 **_b, const u8 *end, goto error; } memcpy(x, b, 16); - afs_merge_fs_addr6(alist, x, port); + ret = afs_merge_fs_addr6(net, alist, x, port); + if (ret < 0) + goto error; b += 16; break; @@ -247,7 +252,7 @@ struct afs_vlserver_list *afs_extract_vlserver_list(struct afs_cell *cell, /* Extract the addresses - note that we can't skip this as we * have to advance the payload pointer. */ - addrs = afs_extract_vl_addrs(&b, end, bs.nr_addrs, bs.port); + addrs = afs_extract_vl_addrs(cell->net, &b, end, bs.nr_addrs, bs.port); if (IS_ERR(addrs)) { ret = PTR_ERR(addrs); goto error_2; diff --git a/fs/afs/vl_probe.c b/fs/afs/vl_probe.c index bdd9372e3fb2..9551aef07cee 100644 --- a/fs/afs/vl_probe.c +++ b/fs/afs/vl_probe.c @@ -48,6 +48,7 @@ void afs_vlserver_probe_result(struct afs_call *call) { struct afs_addr_list *alist = call->alist; struct afs_vlserver *server = call->vlserver; + struct afs_address *addr = &alist->addrs[call->addr_ix]; unsigned int server_index = call->server_index; unsigned int rtt_us = 0; unsigned int index = call->addr_ix; @@ -106,16 +107,16 @@ void afs_vlserver_probe_result(struct afs_call *call) if (call->service_id == YFS_VL_SERVICE) { server->probe.flags |= AFS_VLSERVER_PROBE_IS_YFS; set_bit(AFS_VLSERVER_FL_IS_YFS, &server->flags); - alist->addrs[index].srx.srx_service = call->service_id; + addr->service_id = call->service_id; } else { server->probe.flags |= AFS_VLSERVER_PROBE_NOT_YFS; if (!(server->probe.flags & AFS_VLSERVER_PROBE_IS_YFS)) { clear_bit(AFS_VLSERVER_FL_IS_YFS, &server->flags); - alist->addrs[index].srx.srx_service = call->service_id; + addr->service_id = call->service_id; } } - 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; @@ -130,8 +131,9 @@ void afs_vlserver_probe_result(struct afs_call *call) out: spin_unlock(&server->probe_lock); - _debug("probe [%u][%u] %pISpc rtt=%u ret=%d", - server_index, index, &alist->addrs[index].srx.transport, rtt_us, ret); + _debug("probe [%u][%u] %pISpc rtt=%d ret=%d", + server_index, index, rxrpc_kernel_remote_addr(addr->peer), + rtt_us, ret); afs_done_one_vl_probe(server, have_result); } diff --git a/fs/afs/vl_rotate.c b/fs/afs/vl_rotate.c index 0d0b54819128..af445e7d3a12 100644 --- a/fs/afs/vl_rotate.c +++ b/fs/afs/vl_rotate.c @@ -86,7 +86,7 @@ bool afs_select_vlserver(struct afs_vl_cursor *vc) struct afs_addr_list *alist; struct afs_vlserver *vlserver; struct afs_error e; - u32 rtt; + unsigned int rtt; int error = vc->ac.error, i; _enter("%lx[%d],%lx[%d],%d,%d", @@ -188,7 +188,7 @@ bool afs_select_vlserver(struct afs_vl_cursor *vc) goto selected_server; vc->index = -1; - rtt = U32_MAX; + rtt = UINT_MAX; for (i = 0; i < vc->server_list->nr_servers; i++) { struct afs_vlserver *s = vc->server_list->servers[i].server; @@ -243,7 +243,7 @@ bool afs_select_vlserver(struct afs_vl_cursor *vc) _debug("VL address %d/%d", vc->ac.index, vc->ac.alist->nr_addrs); - _leave(" = t %pISpc", &vc->ac.alist->addrs[vc->ac.index].srx.transport); + _leave(" = t %pISpc", rxrpc_kernel_remote_addr(vc->ac.alist->addrs[vc->ac.index].peer)); return true; next_server: diff --git a/fs/afs/vlclient.c b/fs/afs/vlclient.c index 00fca3c66ba6..41e7932d75c6 100644 --- a/fs/afs/vlclient.c +++ b/fs/afs/vlclient.c @@ -208,7 +208,7 @@ static int afs_deliver_vl_get_addrs_u(struct afs_call *call) count = ntohl(*bp); nentries = min(nentries, count); - alist = afs_alloc_addrlist(nentries, FS_SERVICE, AFS_FS_PORT); + alist = afs_alloc_addrlist(nentries, FS_SERVICE); if (!alist) return -ENOMEM; alist->version = uniquifier; @@ -230,9 +230,13 @@ static int afs_deliver_vl_get_addrs_u(struct afs_call *call) alist = call->ret_alist; bp = call->buffer; count = min(call->count, 4U); - for (i = 0; i < count; i++) - if (alist->nr_addrs < call->count2) - afs_merge_fs_addr4(alist, *bp++, AFS_FS_PORT); + for (i = 0; i < count; i++) { + if (alist->nr_addrs < call->count2) { + ret = afs_merge_fs_addr4(call->net, alist, *bp++, AFS_FS_PORT); + if (ret < 0) + return ret; + } + } call->count -= count; if (call->count > 0) @@ -450,7 +454,7 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call) if (call->count > YFS_MAXENDPOINTS) return afs_protocol_error(call, afs_eproto_yvl_fsendpt_num); - alist = afs_alloc_addrlist(call->count, FS_SERVICE, AFS_FS_PORT); + alist = afs_alloc_addrlist(call->count, FS_SERVICE); if (!alist) return -ENOMEM; alist->version = uniquifier; @@ -488,14 +492,18 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call) if (ntohl(bp[0]) != sizeof(__be32) * 2) return afs_protocol_error( call, afs_eproto_yvl_fsendpt4_len); - afs_merge_fs_addr4(alist, bp[1], ntohl(bp[2])); + ret = afs_merge_fs_addr4(call->net, alist, bp[1], ntohl(bp[2])); + if (ret < 0) + return ret; bp += 3; break; case YFS_ENDPOINT_IPV6: if (ntohl(bp[0]) != sizeof(__be32) * 5) return afs_protocol_error( call, afs_eproto_yvl_fsendpt6_len); - afs_merge_fs_addr6(alist, bp + 1, ntohl(bp[5])); + ret = afs_merge_fs_addr6(call->net, alist, bp + 1, ntohl(bp[5])); + if (ret < 0) + return ret; bp += 6; break; default: diff --git a/include/net/af_rxrpc.h b/include/net/af_rxrpc.h index 5531dd08061e..0754c463224a 100644 --- a/include/net/af_rxrpc.h +++ b/include/net/af_rxrpc.h @@ -15,6 +15,7 @@ struct key; struct sock; struct socket; struct rxrpc_call; +struct rxrpc_peer; enum rxrpc_abort_reason; enum rxrpc_interruptibility { @@ -41,13 +42,14 @@ void rxrpc_kernel_new_call_notification(struct socket *, rxrpc_notify_new_call_t, rxrpc_discard_new_call_t); struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock, - struct sockaddr_rxrpc *srx, + struct rxrpc_peer *peer, struct key *key, unsigned long user_call_ID, s64 tx_total_len, u32 hard_timeout, gfp_t gfp, rxrpc_notify_rx_t notify_rx, + u16 service_id, bool upgrade, enum rxrpc_interruptibility interruptibility, unsigned int debug_id); @@ -60,9 +62,14 @@ bool rxrpc_kernel_abort_call(struct socket *, struct rxrpc_call *, u32, int, enum rxrpc_abort_reason); void rxrpc_kernel_shutdown_call(struct socket *sock, struct rxrpc_call *call); void rxrpc_kernel_put_call(struct socket *sock, struct rxrpc_call *call); -void rxrpc_kernel_get_peer(struct socket *, struct rxrpc_call *, - struct sockaddr_rxrpc *); -bool rxrpc_kernel_get_srtt(struct socket *, struct rxrpc_call *, u32 *); +struct rxrpc_peer *rxrpc_kernel_lookup_peer(struct socket *sock, + struct sockaddr_rxrpc *srx, gfp_t gfp); +void rxrpc_kernel_put_peer(struct rxrpc_peer *peer); +struct rxrpc_peer *rxrpc_kernel_get_peer(struct rxrpc_peer *peer); +struct rxrpc_peer *rxrpc_kernel_get_call_peer(struct socket *sock, struct rxrpc_call *call); +const struct sockaddr_rxrpc *rxrpc_kernel_remote_srx(const struct rxrpc_peer *peer); +const struct sockaddr *rxrpc_kernel_remote_addr(const struct rxrpc_peer *peer); +unsigned int rxrpc_kernel_get_srtt(const struct rxrpc_peer *); int rxrpc_kernel_charge_accept(struct socket *, rxrpc_notify_rx_t, rxrpc_user_attach_call_t, unsigned long, gfp_t, unsigned int); diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h index 4c53a5ef6257..90a1e39d620e 100644 --- a/include/trace/events/rxrpc.h +++ b/include/trace/events/rxrpc.h @@ -178,7 +178,9 @@ #define rxrpc_peer_traces \ EM(rxrpc_peer_free, "FREE ") \ EM(rxrpc_peer_get_accept, "GET accept ") \ + EM(rxrpc_peer_get_application, "GET app ") \ EM(rxrpc_peer_get_bundle, "GET bundle ") \ + EM(rxrpc_peer_get_call, "GET call ") \ EM(rxrpc_peer_get_client_conn, "GET cln-conn") \ EM(rxrpc_peer_get_input, "GET input ") \ EM(rxrpc_peer_get_input_error, "GET inpt-err") \ @@ -187,6 +189,7 @@ EM(rxrpc_peer_get_service_conn, "GET srv-conn") \ EM(rxrpc_peer_new_client, "NEW client ") \ EM(rxrpc_peer_new_prealloc, "NEW prealloc") \ + EM(rxrpc_peer_put_application, "PUT app ") \ EM(rxrpc_peer_put_bundle, "PUT bundle ") \ EM(rxrpc_peer_put_call, "PUT call ") \ EM(rxrpc_peer_put_conn, "PUT conn ") \ diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c index fa8aec78f63d..465bfe5eb061 100644 --- a/net/rxrpc/af_rxrpc.c +++ b/net/rxrpc/af_rxrpc.c @@ -258,16 +258,62 @@ static int rxrpc_listen(struct socket *sock, int backlog) return ret; } +/** + * rxrpc_kernel_lookup_peer - Obtain remote transport endpoint for an address + * @sock: The socket through which it will be accessed + * @srx: The network address + * @gfp: Allocation flags + * + * Lookup or create a remote transport endpoint record for the specified + * address and return it with a ref held. + */ +struct rxrpc_peer *rxrpc_kernel_lookup_peer(struct socket *sock, + struct sockaddr_rxrpc *srx, gfp_t gfp) +{ + struct rxrpc_sock *rx = rxrpc_sk(sock->sk); + int ret; + + ret = rxrpc_validate_address(rx, srx, sizeof(*srx)); + if (ret < 0) + return ERR_PTR(ret); + + return rxrpc_lookup_peer(rx->local, srx, gfp); +} +EXPORT_SYMBOL(rxrpc_kernel_lookup_peer); + +/** + * rxrpc_kernel_get_peer - Get a reference on a peer + * @peer: The peer to get a reference on. + * + * Get a record for the remote peer in a call. + */ +struct rxrpc_peer *rxrpc_kernel_get_peer(struct rxrpc_peer *peer) +{ + return peer ? rxrpc_get_peer(peer, rxrpc_peer_get_application) : NULL; +} +EXPORT_SYMBOL(rxrpc_kernel_get_peer); + +/** + * rxrpc_kernel_put_peer - Allow a kernel app to drop a peer reference + * @peer: The peer to drop a ref on + */ +void rxrpc_kernel_put_peer(struct rxrpc_peer *peer) +{ + rxrpc_put_peer(peer, rxrpc_peer_put_application); +} +EXPORT_SYMBOL(rxrpc_kernel_put_peer); + /** * rxrpc_kernel_begin_call - Allow a kernel service to begin a call * @sock: The socket on which to make the call - * @srx: The address of the peer to contact + * @peer: The peer to contact * @key: The security context to use (defaults to socket setting) * @user_call_ID: The ID to use * @tx_total_len: Total length of data to transmit during the call (or -1) * @hard_timeout: The maximum lifespan of the call in sec * @gfp: The allocation constraints * @notify_rx: Where to send notifications instead of socket queue + * @service_id: The ID of the service to contact * @upgrade: Request service upgrade for call * @interruptibility: The call is interruptible, or can be canceled. * @debug_id: The debug ID for tracing to be assigned to the call @@ -280,13 +326,14 @@ static int rxrpc_listen(struct socket *sock, int backlog) * supplying @srx and @key. */ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock, - struct sockaddr_rxrpc *srx, + struct rxrpc_peer *peer, struct key *key, unsigned long user_call_ID, s64 tx_total_len, u32 hard_timeout, gfp_t gfp, rxrpc_notify_rx_t notify_rx, + u16 service_id, bool upgrade, enum rxrpc_interruptibility interruptibility, unsigned int debug_id) @@ -295,13 +342,11 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock, struct rxrpc_call_params p; struct rxrpc_call *call; struct rxrpc_sock *rx = rxrpc_sk(sock->sk); - int ret; _enter(",,%x,%lx", key_serial(key), user_call_ID); - ret = rxrpc_validate_address(rx, srx, sizeof(*srx)); - if (ret < 0) - return ERR_PTR(ret); + if (WARN_ON_ONCE(peer->local != rx->local)) + return ERR_PTR(-EIO); lock_sock(&rx->sk); @@ -319,12 +364,13 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock, memset(&cp, 0, sizeof(cp)); cp.local = rx->local; + cp.peer = peer; cp.key = key; cp.security_level = rx->min_sec_level; cp.exclusive = false; cp.upgrade = upgrade; - cp.service_id = srx->srx_service; - call = rxrpc_new_client_call(rx, &cp, srx, &p, gfp, debug_id); + cp.service_id = service_id; + call = rxrpc_new_client_call(rx, &cp, &p, gfp, debug_id); /* The socket has been unlocked. */ if (!IS_ERR(call)) { call->notify_rx = notify_rx; diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index e8e14c6f904d..8eea7a487380 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -364,6 +364,7 @@ struct rxrpc_conn_proto { struct rxrpc_conn_parameters { struct rxrpc_local *local; /* Representation of local endpoint */ + struct rxrpc_peer *peer; /* Representation of remote endpoint */ struct key *key; /* Security details */ bool exclusive; /* T if conn is exclusive */ bool upgrade; /* T if service ID can be upgraded */ @@ -867,7 +868,6 @@ struct rxrpc_call *rxrpc_find_call_by_user_ID(struct rxrpc_sock *, unsigned long struct rxrpc_call *rxrpc_alloc_call(struct rxrpc_sock *, gfp_t, unsigned int); struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *, struct rxrpc_conn_parameters *, - struct sockaddr_rxrpc *, struct rxrpc_call_params *, gfp_t, unsigned int); void rxrpc_start_call_timer(struct rxrpc_call *call); diff --git a/net/rxrpc/call_object.c b/net/rxrpc/call_object.c index 773eecd1e979..beea25ac88f5 100644 --- a/net/rxrpc/call_object.c +++ b/net/rxrpc/call_object.c @@ -193,7 +193,6 @@ struct rxrpc_call *rxrpc_alloc_call(struct rxrpc_sock *rx, gfp_t gfp, * Allocate a new client call. */ static struct rxrpc_call *rxrpc_alloc_client_call(struct rxrpc_sock *rx, - struct sockaddr_rxrpc *srx, struct rxrpc_conn_parameters *cp, struct rxrpc_call_params *p, gfp_t gfp, @@ -211,10 +210,12 @@ static struct rxrpc_call *rxrpc_alloc_client_call(struct rxrpc_sock *rx, now = ktime_get_real(); call->acks_latest_ts = now; call->cong_tstamp = now; - call->dest_srx = *srx; + call->dest_srx = cp->peer->srx; + call->dest_srx.srx_service = cp->service_id; call->interruptibility = p->interruptibility; call->tx_total_len = p->tx_total_len; call->key = key_get(cp->key); + call->peer = rxrpc_get_peer(cp->peer, rxrpc_peer_get_call); call->local = rxrpc_get_local(cp->local, rxrpc_local_get_call); call->security_level = cp->security_level; if (p->kernel) @@ -306,10 +307,6 @@ static int rxrpc_connect_call(struct rxrpc_call *call, gfp_t gfp) _enter("{%d,%lx},", call->debug_id, call->user_call_ID); - call->peer = rxrpc_lookup_peer(local, &call->dest_srx, gfp); - if (!call->peer) - goto error; - ret = rxrpc_look_up_bundle(call, gfp); if (ret < 0) goto error; @@ -334,7 +331,6 @@ static int rxrpc_connect_call(struct rxrpc_call *call, gfp_t gfp) */ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx, struct rxrpc_conn_parameters *cp, - struct sockaddr_rxrpc *srx, struct rxrpc_call_params *p, gfp_t gfp, unsigned int debug_id) @@ -349,13 +345,18 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx, _enter("%p,%lx", rx, p->user_call_ID); + if (WARN_ON_ONCE(!cp->peer)) { + release_sock(&rx->sk); + return ERR_PTR(-EIO); + } + limiter = rxrpc_get_call_slot(p, gfp); if (!limiter) { release_sock(&rx->sk); return ERR_PTR(-ERESTARTSYS); } - call = rxrpc_alloc_client_call(rx, srx, cp, p, gfp, debug_id); + call = rxrpc_alloc_client_call(rx, cp, p, gfp, debug_id); if (IS_ERR(call)) { release_sock(&rx->sk); up(limiter); diff --git a/net/rxrpc/peer_object.c b/net/rxrpc/peer_object.c index 8d7a715a0bb1..65ea57b427a1 100644 --- a/net/rxrpc/peer_object.c +++ b/net/rxrpc/peer_object.c @@ -22,6 +22,8 @@ #include <net/ip6_route.h> #include "ar-internal.h" +static const struct sockaddr_rxrpc rxrpc_null_addr; + /* * Hash a peer key. */ @@ -457,39 +459,51 @@ void rxrpc_destroy_all_peers(struct rxrpc_net *rxnet) } /** - * rxrpc_kernel_get_peer - Get the peer address of a call + * rxrpc_kernel_get_call_peer - Get the peer address of a call * @sock: The socket on which the call is in progress. * @call: The call to query - * @_srx: Where to place the result * - * Get the address of the remote peer in a call. + * Get a record for the remote peer in a call. */ -void rxrpc_kernel_get_peer(struct socket *sock, struct rxrpc_call *call, - struct sockaddr_rxrpc *_srx) +struct rxrpc_peer *rxrpc_kernel_get_call_peer(struct socket *sock, struct rxrpc_call *call) { - *_srx = call->peer->srx; + return call->peer; } -EXPORT_SYMBOL(rxrpc_kernel_get_peer); +EXPORT_SYMBOL(rxrpc_kernel_get_call_peer); /** * rxrpc_kernel_get_srtt - Get a call's peer smoothed RTT - * @sock: The socket on which the call is in progress. - * @call: The call to query - * @_srtt: Where to store the SRTT value. + * @peer: The peer to query * - * Get the call's peer smoothed RTT in uS. + * Get the call's peer smoothed RTT in uS or UINT_MAX if we have no samples. */ -bool rxrpc_kernel_get_srtt(struct socket *sock, struct rxrpc_call *call, - u32 *_srtt) +unsigned int rxrpc_kernel_get_srtt(const struct rxrpc_peer *peer) { - struct rxrpc_peer *peer = call->peer; + return peer->rtt_count > 0 ? peer->srtt_us >> 3 : UINT_MAX; +} +EXPORT_SYMBOL(rxrpc_kernel_get_srtt); - if (peer->rtt_count == 0) { - *_srtt = 1000000; /* 1S */ - return false; - } +/** + * rxrpc_kernel_remote_srx - Get the address of a peer + * @peer: The peer to query + * + * Get a pointer to the address from a peer record. The caller is responsible + * for making sure that the address is not deallocated. + */ +const struct sockaddr_rxrpc *rxrpc_kernel_remote_srx(const struct rxrpc_peer *peer) +{ + return peer ? &peer->srx : &rxrpc_null_addr; +} - *_srtt = call->peer->srtt_us >> 3; - return true; +/** + * rxrpc_kernel_remote_addr - Get the peer transport address of a call + * @peer: The peer to query + * + * Get a pointer to the transport address from a peer record. The caller is + * responsible for making sure that the address is not deallocated. + */ +const struct sockaddr *rxrpc_kernel_remote_addr(const struct rxrpc_peer *peer) +{ + return (const struct sockaddr *) + (peer ? &peer->srx.transport : &rxrpc_null_addr.transport); } -EXPORT_SYMBOL(rxrpc_kernel_get_srtt); diff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c index 8e0b94714e84..5677d5690a02 100644 --- a/net/rxrpc/sendmsg.c +++ b/net/rxrpc/sendmsg.c @@ -572,6 +572,7 @@ rxrpc_new_client_call_for_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, __acquires(&call->user_mutex) { struct rxrpc_conn_parameters cp; + struct rxrpc_peer *peer; struct rxrpc_call *call; struct key *key; @@ -584,21 +585,29 @@ rxrpc_new_client_call_for_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, return ERR_PTR(-EDESTADDRREQ); } + peer = rxrpc_lookup_peer(rx->local, srx, GFP_KERNEL); + if (!peer) { + release_sock(&rx->sk); + return ERR_PTR(-ENOMEM); + } + key = rx->key; if (key && !rx->key->payload.data[0]) key = NULL; memset(&cp, 0, sizeof(cp)); cp.local = rx->local; + cp.peer = peer; cp.key = rx->key; cp.security_level = rx->min_sec_level; cp.exclusive = rx->exclusive | p->exclusive; cp.upgrade = p->upgrade; cp.service_id = srx->srx_service; - call = rxrpc_new_client_call(rx, &cp, srx, &p->call, GFP_KERNEL, + call = rxrpc_new_client_call(rx, &cp, &p->call, GFP_KERNEL, atomic_inc_return(&rxrpc_debug_id)); /* The socket is now unlocked */ + rxrpc_put_peer(peer, rxrpc_peer_put_application); _leave(" = %p\n", call); return call; }
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 --- fs/afs/addr_list.c | 125 ++++++++++++++++++----------------- fs/afs/cmservice.c | 5 +- fs/afs/fs_probe.c | 11 +-- fs/afs/internal.h | 26 ++++---- fs/afs/proc.c | 9 +-- fs/afs/rotate.c | 6 +- fs/afs/rxrpc.c | 10 +-- fs/afs/server.c | 41 ++---------- fs/afs/vl_alias.c | 55 +-------------- fs/afs/vl_list.c | 15 +++-- fs/afs/vl_probe.c | 12 ++-- fs/afs/vl_rotate.c | 6 +- fs/afs/vlclient.c | 22 ++++-- include/net/af_rxrpc.h | 15 +++-- include/trace/events/rxrpc.h | 3 + net/rxrpc/af_rxrpc.c | 62 ++++++++++++++--- net/rxrpc/ar-internal.h | 2 +- net/rxrpc/call_object.c | 17 ++--- net/rxrpc/peer_object.c | 56 ++++++++++------ net/rxrpc/sendmsg.c | 11 ++- 20 files changed, 271 insertions(+), 238 deletions(-)