summaryrefslogtreecommitdiff
path: root/fs/afs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/afs')
-rw-r--r--fs/afs/addr_prefs.c82
-rw-r--r--fs/afs/internal.h4
-rw-r--r--fs/afs/proc.c9
3 files changed, 91 insertions, 4 deletions
diff --git a/fs/afs/addr_prefs.c b/fs/afs/addr_prefs.c
index c6dcff4f8aa1..a189ff8a5034 100644
--- a/fs/afs/addr_prefs.c
+++ b/fs/afs/addr_prefs.c
@@ -447,3 +447,85 @@ inval:
ret = -EINVAL;
goto done;
}
+
+/*
+ * Mark the priorities on an address list if the address preferences table has
+ * changed. The caller must hold the RCU read lock.
+ */
+void afs_get_address_preferences_rcu(struct afs_net *net, struct afs_addr_list *alist)
+{
+ const struct afs_addr_preference_list *preflist =
+ rcu_dereference(net->address_prefs);
+ const struct sockaddr_in6 *sin6;
+ const struct sockaddr_in *sin;
+ const struct sockaddr *sa;
+ struct afs_addr_preference test;
+ enum cmp_ret cmp;
+ int i, j;
+
+ if (!preflist || !preflist->nr || !alist->nr_addrs ||
+ smp_load_acquire(&alist->addr_pref_version) == preflist->version)
+ return;
+
+ test.family = AF_INET;
+ test.subnet_mask = 32;
+ test.prio = 0;
+ for (i = 0; i < alist->nr_ipv4; i++) {
+ sa = rxrpc_kernel_remote_addr(alist->addrs[i].peer);
+ sin = (const struct sockaddr_in *)sa;
+ test.ipv4_addr = sin->sin_addr;
+ for (j = 0; j < preflist->ipv6_off; j++) {
+ cmp = afs_cmp_address_pref(&test, &preflist->prefs[j]);
+ switch (cmp) {
+ case CONTINUE_SEARCH:
+ continue;
+ case INSERT_HERE:
+ break;
+ case EXACT_MATCH:
+ case SUBNET_MATCH:
+ WRITE_ONCE(alist->addrs[i].prio, preflist->prefs[j].prio);
+ break;
+ }
+ }
+ }
+
+ test.family = AF_INET6;
+ test.subnet_mask = 128;
+ test.prio = 0;
+ for (; i < alist->nr_addrs; i++) {
+ sa = rxrpc_kernel_remote_addr(alist->addrs[i].peer);
+ sin6 = (const struct sockaddr_in6 *)sa;
+ test.ipv6_addr = sin6->sin6_addr;
+ for (j = preflist->ipv6_off; j < preflist->nr; j++) {
+ cmp = afs_cmp_address_pref(&test, &preflist->prefs[j]);
+ switch (cmp) {
+ case CONTINUE_SEARCH:
+ continue;
+ case INSERT_HERE:
+ break;
+ case EXACT_MATCH:
+ case SUBNET_MATCH:
+ WRITE_ONCE(alist->addrs[i].prio, preflist->prefs[j].prio);
+ break;
+ }
+ }
+ }
+
+ smp_store_release(&alist->addr_pref_version, preflist->version);
+}
+
+/*
+ * Mark the priorities on an address list if the address preferences table has
+ * changed. Avoid taking the RCU read lock if we can.
+ */
+void afs_get_address_preferences(struct afs_net *net, struct afs_addr_list *alist)
+{
+ if (!net->address_prefs ||
+ /* Load version before prefs */
+ smp_load_acquire(&net->address_pref_version) == alist->addr_pref_version)
+ return;
+
+ rcu_read_lock();
+ afs_get_address_preferences_rcu(net, alist);
+ rcu_read_unlock();
+}
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 4445c734cdcd..9a1e151e77e7 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -97,6 +97,7 @@ struct afs_addr_preference_list {
struct afs_address {
struct rxrpc_peer *peer;
short last_error; /* Last error from this address */
+ u16 prio; /* Address priority */
};
/*
@@ -107,6 +108,7 @@ struct afs_addr_list {
refcount_t usage;
u32 version; /* Version */
unsigned int debug_id;
+ unsigned int addr_pref_version; /* Version of address preference list */
unsigned char max_addrs;
unsigned char nr_addrs;
unsigned char preferred; /* Preferred address */
@@ -1010,6 +1012,8 @@ extern int afs_merge_fs_addr6(struct afs_net *net, struct afs_addr_list *addr,
* addr_prefs.c
*/
int afs_proc_addr_prefs_write(struct file *file, char *buf, size_t size);
+void afs_get_address_preferences_rcu(struct afs_net *net, struct afs_addr_list *alist);
+void afs_get_address_preferences(struct afs_net *net, struct afs_addr_list *alist);
/*
* callback.c
diff --git a/fs/afs/proc.c b/fs/afs/proc.c
index 2e63c99a4f1e..944eb51e75a1 100644
--- a/fs/afs/proc.c
+++ b/fs/afs/proc.c
@@ -447,17 +447,18 @@ static int afs_proc_servers_show(struct seq_file *m, void *v)
(int)(jiffies - server->probed_at) / HZ,
atomic_read(&server->probe_outstanding));
failed = alist->probe_failed;
- seq_printf(m, " - ALIST v=%u rsp=%lx f=%lx\n",
- alist->version, alist->responded, alist->probe_failed);
+ seq_printf(m, " - ALIST v=%u rsp=%lx f=%lx ap=%u\n",
+ alist->version, alist->responded, alist->probe_failed,
+ alist->addr_pref_version);
for (i = 0; i < alist->nr_addrs; i++) {
const struct afs_address *addr = &alist->addrs[i];
- seq_printf(m, " [%x] %pISpc%s rtt=%d err=%d\n",
+ seq_printf(m, " [%x] %pISpc%s rtt=%d err=%d p=%u\n",
i, rxrpc_kernel_remote_addr(addr->peer),
alist->preferred == i ? "*" :
test_bit(i, &failed) ? "!" : "",
rxrpc_kernel_get_srtt(addr->peer),
- addr->last_error);
+ addr->last_error, addr->prio);
}
return 0;
}