1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* AFS fileserver list management.
4 * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
5 * Written by David Howells (dhowells@redhat.com)
8 #include <linux/kernel.h>
9 #include <linux/slab.h>
12 void afs_put_serverlist(struct afs_net
*net
, struct afs_server_list
*slist
)
16 if (slist
&& refcount_dec_and_test(&slist
->usage
)) {
17 for (i
= 0; i
< slist
->nr_servers
; i
++) {
18 afs_put_cb_interest(net
, slist
->servers
[i
].cb_interest
);
19 afs_put_server(net
, slist
->servers
[i
].server
,
20 afs_server_trace_put_slist
);
27 * Build a server list from a VLDB record.
29 struct afs_server_list
*afs_alloc_server_list(struct afs_cell
*cell
,
31 struct afs_vldb_entry
*vldb
,
34 struct afs_server_list
*slist
;
35 struct afs_server
*server
;
36 int ret
= -ENOMEM
, nr_servers
= 0, i
, j
;
38 for (i
= 0; i
< vldb
->nr_servers
; i
++)
39 if (vldb
->fs_mask
[i
] & type_mask
)
42 slist
= kzalloc(struct_size(slist
, servers
, nr_servers
), GFP_KERNEL
);
46 refcount_set(&slist
->usage
, 1);
47 rwlock_init(&slist
->lock
);
49 /* Make sure a records exists for each server in the list. */
50 for (i
= 0; i
< vldb
->nr_servers
; i
++) {
51 if (!(vldb
->fs_mask
[i
] & type_mask
))
54 server
= afs_lookup_server(cell
, key
, &vldb
->fs_server
[i
]);
56 ret
= PTR_ERR(server
);
63 /* Insertion-sort by UUID */
64 for (j
= 0; j
< slist
->nr_servers
; j
++)
65 if (memcmp(&slist
->servers
[j
].server
->uuid
,
67 sizeof(server
->uuid
)) >= 0)
69 if (j
< slist
->nr_servers
) {
70 if (slist
->servers
[j
].server
== server
) {
71 afs_put_server(cell
->net
, server
,
72 afs_server_trace_put_slist_isort
);
76 memmove(slist
->servers
+ j
+ 1,
78 (slist
->nr_servers
- j
) * sizeof(struct afs_server_entry
));
81 slist
->servers
[j
].server
= server
;
85 if (slist
->nr_servers
== 0) {
93 afs_put_serverlist(cell
->net
, slist
);
99 * Copy the annotations from an old server list to its potential replacement.
101 bool afs_annotate_server_list(struct afs_server_list
*new,
102 struct afs_server_list
*old
)
104 struct afs_server
*cur
;
107 if (old
->nr_servers
!= new->nr_servers
)
110 for (i
= 0; i
< old
->nr_servers
; i
++)
111 if (old
->servers
[i
].server
!= new->servers
[i
].server
)
117 /* Maintain the same preferred server as before if possible. */
118 cur
= old
->servers
[old
->preferred
].server
;
119 for (j
= 0; j
< new->nr_servers
; j
++) {
120 if (new->servers
[j
].server
== cur
) {
126 /* Keep the old callback interest records where possible so that we
127 * maintain callback interception.
131 while (i
< old
->nr_servers
&& j
< new->nr_servers
) {
132 if (new->servers
[j
].server
== old
->servers
[i
].server
) {
133 struct afs_cb_interest
*cbi
= old
->servers
[i
].cb_interest
;
135 new->servers
[j
].cb_interest
= cbi
;
136 refcount_inc(&cbi
->usage
);
143 if (new->servers
[j
].server
< old
->servers
[i
].server
) {