2874c5fd28426 (Thomas Gleixner 2019-05-27 08:55:01 +0200 1) // SPDX-License-Identifier: GPL-2.0-or-later
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 2) /* AFS fileserver list management.
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 3) *
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 4) * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 5) * Written by David Howells (dhowells@redhat.com)
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 6) */
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 7)
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 8) #include <linux/kernel.h>
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 9) #include <linux/slab.h>
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 10) #include "internal.h"
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 11)
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 12) void afs_put_serverlist(struct afs_net *net, struct afs_server_list *slist)
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 13) {
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 14) int i;
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 15)
0fafdc9f888b4 (David Howells 2017-11-13 16:59:50 +0000 16) if (slist && refcount_dec_and_test(&slist->usage)) {
20325960f8750 (David Howells 2020-04-30 01:03:49 +0100 17) for (i = 0; i < slist->nr_servers; i++)
977e5f8ed0ab2 (David Howells 2020-04-17 17:31:26 +0100 18) afs_unuse_server(net, slist->servers[i].server,
977e5f8ed0ab2 (David Howells 2020-04-17 17:31:26 +0100 19) afs_server_trace_put_slist);
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 20) kfree(slist);
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 21) }
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 22) }
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 23)
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 24) /*
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 25) * Build a server list from a VLDB record.
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 26) */
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 27) struct afs_server_list *afs_alloc_server_list(struct afs_cell *cell,
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 28) struct key *key,
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 29) struct afs_vldb_entry *vldb,
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 30) u8 type_mask)
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 31) {
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 32) struct afs_server_list *slist;
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 33) struct afs_server *server;
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 34) int ret = -ENOMEM, nr_servers = 0, i, j;
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 35)
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 36) for (i = 0; i < vldb->nr_servers; i++)
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 37) if (vldb->fs_mask[i] & type_mask)
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 38) nr_servers++;
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 39)
c2b8bd49d35a7 (Gustavo A. R. Silva 2019-01-09 17:23:54 +0000 40) slist = kzalloc(struct_size(slist, servers, nr_servers), GFP_KERNEL);
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 41) if (!slist)
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 42) goto error;
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 43)
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 44) refcount_set(&slist->usage, 1);
d4a96bec7a736 (David Howells 2018-05-10 08:43:04 +0100 45) rwlock_init(&slist->lock);
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 46)
194d28cf197ca (David Howells 2020-04-27 13:42:53 +0100 47) for (i = 0; i < AFS_MAXTYPES; i++)
194d28cf197ca (David Howells 2020-04-27 13:42:53 +0100 48) slist->vids[i] = vldb->vid[i];
194d28cf197ca (David Howells 2020-04-27 13:42:53 +0100 49)
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 50) /* Make sure a records exists for each server in the list. */
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 51) for (i = 0; i < vldb->nr_servers; i++) {
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 52) if (!(vldb->fs_mask[i] & type_mask))
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 53) continue;
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 54)
8100680592345 (David Howells 2020-04-16 17:05:28 +0100 55) server = afs_lookup_server(cell, key, &vldb->fs_server[i],
8100680592345 (David Howells 2020-04-16 17:05:28 +0100 56) vldb->addr_version[i]);
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 57) if (IS_ERR(server)) {
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 58) ret = PTR_ERR(server);
45df8462730d2 (David Howells 2018-02-06 14:12:32 +0000 59) if (ret == -ENOENT ||
45df8462730d2 (David Howells 2018-02-06 14:12:32 +0000 60) ret == -ENOMEDIUM)
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 61) continue;
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 62) goto error_2;
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 63) }
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 64)
d4a96bec7a736 (David Howells 2018-05-10 08:43:04 +0100 65) /* Insertion-sort by UUID */
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 66) for (j = 0; j < slist->nr_servers; j++)
d4a96bec7a736 (David Howells 2018-05-10 08:43:04 +0100 67) if (memcmp(&slist->servers[j].server->uuid,
d4a96bec7a736 (David Howells 2018-05-10 08:43:04 +0100 68) &server->uuid,
d4a96bec7a736 (David Howells 2018-05-10 08:43:04 +0100 69) sizeof(server->uuid)) >= 0)
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 70) break;
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 71) if (j < slist->nr_servers) {
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 72) if (slist->servers[j].server == server) {
452181936931f (David Howells 2019-06-20 18:12:17 +0100 73) afs_put_server(cell->net, server,
452181936931f (David Howells 2019-06-20 18:12:17 +0100 74) afs_server_trace_put_slist_isort);
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 75) continue;
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 76) }
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 77)
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 78) memmove(slist->servers + j + 1,
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 79) slist->servers + j,
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 80) (slist->nr_servers - j) * sizeof(struct afs_server_entry));
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 81) }
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 82)
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 83) slist->servers[j].server = server;
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 84) slist->nr_servers++;
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 85) }
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 86)
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 87) if (slist->nr_servers == 0) {
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 88) ret = -EDESTADDRREQ;
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 89) goto error_2;
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 90) }
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 91)
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 92) return slist;
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 93)
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 94) error_2:
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 95) afs_put_serverlist(cell->net, slist);
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 96) error:
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 97) return ERR_PTR(ret);
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 98) }
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 99)
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 100) /*
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 101) * Copy the annotations from an old server list to its potential replacement.
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 102) */
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 103) bool afs_annotate_server_list(struct afs_server_list *new,
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 104) struct afs_server_list *old)
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 105) {
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 106) struct afs_server *cur;
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 107) int i, j;
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 108)
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 109) if (old->nr_servers != new->nr_servers)
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 110) goto changed;
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 111)
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 112) for (i = 0; i < old->nr_servers; i++)
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 113) if (old->servers[i].server != new->servers[i].server)
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 114) goto changed;
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 115)
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 116) return false;
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 117)
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 118) changed:
3bf0fb6f33dd5 (David Howells 2018-10-20 00:57:59 +0100 119) /* Maintain the same preferred server as before if possible. */
3bf0fb6f33dd5 (David Howells 2018-10-20 00:57:59 +0100 120) cur = old->servers[old->preferred].server;
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 121) for (j = 0; j < new->nr_servers; j++) {
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 122) if (new->servers[j].server == cur) {
3bf0fb6f33dd5 (David Howells 2018-10-20 00:57:59 +0100 123) new->preferred = j;
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 124) break;
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 125) }
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 126) }
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 127)
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 128) return true;
d2ddc776a4581 (David Howells 2017-11-02 15:27:50 +0000 129) }