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_unuse_server(net
, slist
->servers
[i
].server
,
19 afs_server_trace_put_slist
);
25 * Build a server list from a VLDB record.
27 struct afs_server_list
*afs_alloc_server_list(struct afs_cell
*cell
,
29 struct afs_vldb_entry
*vldb
,
32 struct afs_server_list
*slist
;
33 struct afs_server
*server
;
34 int ret
= -ENOMEM
, nr_servers
= 0, i
, j
;
36 for (i
= 0; i
< vldb
->nr_servers
; i
++)
37 if (vldb
->fs_mask
[i
] & type_mask
)
40 slist
= kzalloc(struct_size(slist
, servers
, nr_servers
), GFP_KERNEL
);
44 refcount_set(&slist
->usage
, 1);
45 rwlock_init(&slist
->lock
);
47 for (i
= 0; i
< AFS_MAXTYPES
; i
++)
48 slist
->vids
[i
] = vldb
->vid
[i
];
50 /* Make sure a records exists for each server in the list. */
51 for (i
= 0; i
< vldb
->nr_servers
; i
++) {
52 if (!(vldb
->fs_mask
[i
] & type_mask
))
55 server
= afs_lookup_server(cell
, key
, &vldb
->fs_server
[i
],
56 vldb
->addr_version
[i
]);
58 ret
= PTR_ERR(server
);
65 /* Insertion-sort by UUID */
66 for (j
= 0; j
< slist
->nr_servers
; j
++)
67 if (memcmp(&slist
->servers
[j
].server
->uuid
,
69 sizeof(server
->uuid
)) >= 0)
71 if (j
< slist
->nr_servers
) {
72 if (slist
->servers
[j
].server
== server
) {
73 afs_put_server(cell
->net
, server
,
74 afs_server_trace_put_slist_isort
);
78 memmove(slist
->servers
+ j
+ 1,
80 (slist
->nr_servers
- j
) * sizeof(struct afs_server_entry
));
83 slist
->servers
[j
].server
= server
;
87 if (slist
->nr_servers
== 0) {
95 afs_put_serverlist(cell
->net
, slist
);
101 * Copy the annotations from an old server list to its potential replacement.
103 bool afs_annotate_server_list(struct afs_server_list
*new,
104 struct afs_server_list
*old
)
106 struct afs_server
*cur
;
109 if (old
->nr_servers
!= new->nr_servers
)
112 for (i
= 0; i
< old
->nr_servers
; i
++)
113 if (old
->servers
[i
].server
!= new->servers
[i
].server
)
119 /* Maintain the same preferred server as before if possible. */
120 cur
= old
->servers
[old
->preferred
].server
;
121 for (j
= 0; j
< new->nr_servers
; j
++) {
122 if (new->servers
[j
].server
== cur
) {