1 /* AFS fileserver list management.
3 * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
12 #include <linux/kernel.h>
13 #include <linux/slab.h>
16 void afs_put_serverlist(struct afs_net
*net
, struct afs_server_list
*slist
)
20 if (slist
&& refcount_dec_and_test(&slist
->usage
)) {
21 for (i
= 0; i
< slist
->nr_servers
; i
++) {
22 afs_put_cb_interest(net
, slist
->servers
[i
].cb_interest
);
23 afs_put_server(net
, slist
->servers
[i
].server
);
30 * Build a server list from a VLDB record.
32 struct afs_server_list
*afs_alloc_server_list(struct afs_cell
*cell
,
34 struct afs_vldb_entry
*vldb
,
37 struct afs_server_list
*slist
;
38 struct afs_server
*server
;
39 int ret
= -ENOMEM
, nr_servers
= 0, i
, j
;
41 for (i
= 0; i
< vldb
->nr_servers
; i
++)
42 if (vldb
->fs_mask
[i
] & type_mask
)
45 slist
= kzalloc(sizeof(struct afs_server_list
) +
46 sizeof(struct afs_server_entry
) * nr_servers
,
51 refcount_set(&slist
->usage
, 1);
53 /* Make sure a records exists for each server in the list. */
54 for (i
= 0; i
< vldb
->nr_servers
; i
++) {
55 if (!(vldb
->fs_mask
[i
] & type_mask
))
58 server
= afs_lookup_server(cell
, key
, &vldb
->fs_server
[i
]);
60 ret
= PTR_ERR(server
);
67 /* Insertion-sort by server pointer */
68 for (j
= 0; j
< slist
->nr_servers
; j
++)
69 if (slist
->servers
[j
].server
>= server
)
71 if (j
< slist
->nr_servers
) {
72 if (slist
->servers
[j
].server
== server
) {
73 afs_put_server(cell
->net
, server
);
77 memmove(slist
->servers
+ j
+ 1,
79 (slist
->nr_servers
- j
) * sizeof(struct afs_server_entry
));
82 slist
->servers
[j
].server
= server
;
86 if (slist
->nr_servers
== 0) {
94 afs_put_serverlist(cell
->net
, slist
);
100 * Copy the annotations from an old server list to its potential replacement.
102 bool afs_annotate_server_list(struct afs_server_list
*new,
103 struct afs_server_list
*old
)
105 struct afs_server
*cur
;
108 if (old
->nr_servers
!= new->nr_servers
)
111 for (i
= 0; i
< old
->nr_servers
; i
++)
112 if (old
->servers
[i
].server
!= new->servers
[i
].server
)
118 /* Maintain the same current server as before if possible. */
119 cur
= old
->servers
[old
->index
].server
;
120 for (j
= 0; j
< new->nr_servers
; j
++) {
121 if (new->servers
[j
].server
== cur
) {
127 /* Keep the old callback interest records where possible so that we
128 * maintain callback interception.
132 while (i
< old
->nr_servers
&& j
< new->nr_servers
) {
133 if (new->servers
[j
].server
== old
->servers
[i
].server
) {
134 struct afs_cb_interest
*cbi
= old
->servers
[i
].cb_interest
;
136 new->servers
[j
].cb_interest
= cbi
;
137 refcount_inc(&cbi
->usage
);
144 if (new->servers
[j
].server
< old
->servers
[i
].server
) {