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);
52 rwlock_init(&slist
->lock
);
54 /* Make sure a records exists for each server in the list. */
55 for (i
= 0; i
< vldb
->nr_servers
; i
++) {
56 if (!(vldb
->fs_mask
[i
] & type_mask
))
59 server
= afs_lookup_server(cell
, key
, &vldb
->fs_server
[i
]);
61 ret
= PTR_ERR(server
);
68 /* Insertion-sort by UUID */
69 for (j
= 0; j
< slist
->nr_servers
; j
++)
70 if (memcmp(&slist
->servers
[j
].server
->uuid
,
72 sizeof(server
->uuid
)) >= 0)
74 if (j
< slist
->nr_servers
) {
75 if (slist
->servers
[j
].server
== server
) {
76 afs_put_server(cell
->net
, server
);
80 memmove(slist
->servers
+ j
+ 1,
82 (slist
->nr_servers
- j
) * sizeof(struct afs_server_entry
));
85 slist
->servers
[j
].server
= server
;
89 if (slist
->nr_servers
== 0) {
97 afs_put_serverlist(cell
->net
, slist
);
103 * Copy the annotations from an old server list to its potential replacement.
105 bool afs_annotate_server_list(struct afs_server_list
*new,
106 struct afs_server_list
*old
)
108 struct afs_server
*cur
;
111 if (old
->nr_servers
!= new->nr_servers
)
114 for (i
= 0; i
< old
->nr_servers
; i
++)
115 if (old
->servers
[i
].server
!= new->servers
[i
].server
)
121 /* Maintain the same current server as before if possible. */
122 cur
= old
->servers
[old
->index
].server
;
123 for (j
= 0; j
< new->nr_servers
; j
++) {
124 if (new->servers
[j
].server
== cur
) {
130 /* Keep the old callback interest records where possible so that we
131 * maintain callback interception.
135 while (i
< old
->nr_servers
&& j
< new->nr_servers
) {
136 if (new->servers
[j
].server
== old
->servers
[i
].server
) {
137 struct afs_cb_interest
*cbi
= old
->servers
[i
].cb_interest
;
139 new->servers
[j
].cb_interest
= cbi
;
140 refcount_inc(&cbi
->usage
);
147 if (new->servers
[j
].server
< old
->servers
[i
].server
) {