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
);
20 kfree_rcu(slist
, rcu
);
25 * Build a server list from a VLDB record.
27 struct afs_server_list
*afs_alloc_server_list(struct afs_volume
*volume
,
29 struct afs_vldb_entry
*vldb
)
31 struct afs_server_list
*slist
;
32 struct afs_server
*server
;
33 unsigned int type_mask
= 1 << volume
->type
;
34 bool use_newrepsites
= false;
35 int ret
= -ENOMEM
, nr_servers
= 0, newrep
= 0, i
, j
, usable
= 0;
37 /* Work out if we're going to restrict to NEWREPSITE-marked servers or
38 * not. If at least one site is marked as NEWREPSITE, then it's likely
39 * that "vos release" is busy updating RO sites. We cut over from one
40 * to the other when >=50% of the sites have been updated. Sites that
41 * are in the process of being updated are marked DONTUSE.
43 for (i
= 0; i
< vldb
->nr_servers
; i
++) {
44 if (!(vldb
->fs_mask
[i
] & type_mask
))
47 if (vldb
->vlsf_flags
[i
] & AFS_VLSF_DONTUSE
)
50 if (vldb
->vlsf_flags
[i
] & AFS_VLSF_NEWREPSITE
)
54 slist
= kzalloc(struct_size(slist
, servers
, nr_servers
), GFP_KERNEL
);
59 if (newrep
< usable
/ 2) {
60 slist
->ro_replicating
= AFS_RO_REPLICATING_USE_OLD
;
62 slist
->ro_replicating
= AFS_RO_REPLICATING_USE_NEW
;
63 use_newrepsites
= true;
67 refcount_set(&slist
->usage
, 1);
68 rwlock_init(&slist
->lock
);
70 /* Make sure a records exists for each server in the list. */
71 for (i
= 0; i
< vldb
->nr_servers
; i
++) {
72 unsigned long se_flags
= 0;
73 bool newrepsite
= vldb
->vlsf_flags
[i
] & AFS_VLSF_NEWREPSITE
;
75 if (!(vldb
->fs_mask
[i
] & type_mask
))
77 if (vldb
->vlsf_flags
[i
] & AFS_VLSF_DONTUSE
)
78 __set_bit(AFS_SE_EXCLUDED
, &se_flags
);
79 if (newrep
&& (newrepsite
^ use_newrepsites
))
80 __set_bit(AFS_SE_EXCLUDED
, &se_flags
);
82 server
= afs_lookup_server(volume
->cell
, key
, &vldb
->fs_server
[i
],
83 vldb
->addr_version
[i
]);
85 ret
= PTR_ERR(server
);
92 /* Insertion-sort by UUID */
93 for (j
= 0; j
< slist
->nr_servers
; j
++)
94 if (memcmp(&slist
->servers
[j
].server
->uuid
,
96 sizeof(server
->uuid
)) >= 0)
98 if (j
< slist
->nr_servers
) {
99 if (slist
->servers
[j
].server
== server
) {
100 afs_put_server(volume
->cell
->net
, server
,
101 afs_server_trace_put_slist_isort
);
105 memmove(slist
->servers
+ j
+ 1,
107 (slist
->nr_servers
- j
) * sizeof(struct afs_server_entry
));
110 slist
->servers
[j
].server
= server
;
111 slist
->servers
[j
].volume
= volume
;
112 slist
->servers
[j
].flags
= se_flags
;
113 slist
->servers
[j
].cb_expires_at
= AFS_NO_CB_PROMISE
;
117 if (slist
->nr_servers
== 0) {
125 afs_put_serverlist(volume
->cell
->net
, slist
);
131 * Copy the annotations from an old server list to its potential replacement.
133 bool afs_annotate_server_list(struct afs_server_list
*new,
134 struct afs_server_list
*old
)
136 unsigned long mask
= 1UL << AFS_SE_EXCLUDED
;
139 if (old
->nr_servers
!= new->nr_servers
||
140 old
->ro_replicating
!= new->ro_replicating
)
143 for (i
= 0; i
< old
->nr_servers
; i
++) {
144 if (old
->servers
[i
].server
!= new->servers
[i
].server
)
146 if ((old
->servers
[i
].flags
& mask
) != (new->servers
[i
].flags
& mask
))
155 * Attach a volume to the servers it is going to use.
157 void afs_attach_volume_to_servers(struct afs_volume
*volume
, struct afs_server_list
*slist
)
159 struct afs_server_entry
*se
, *pe
;
160 struct afs_server
*server
;
164 down_write(&volume
->cell
->vs_lock
);
166 for (i
= 0; i
< slist
->nr_servers
; i
++) {
167 se
= &slist
->servers
[i
];
170 list_for_each(p
, &server
->volumes
) {
171 pe
= list_entry(p
, struct afs_server_entry
, slink
);
172 if (volume
->vid
<= pe
->volume
->vid
)
175 list_add_tail(&se
->slink
, p
);
178 slist
->attached
= true;
179 up_write(&volume
->cell
->vs_lock
);
183 * Reattach a volume to the servers it is going to use when server list is
184 * replaced. We try to switch the attachment points to avoid rewalking the
187 void afs_reattach_volume_to_servers(struct afs_volume
*volume
, struct afs_server_list
*new,
188 struct afs_server_list
*old
)
190 unsigned int n
= 0, o
= 0;
192 down_write(&volume
->cell
->vs_lock
);
194 while (n
< new->nr_servers
|| o
< old
->nr_servers
) {
195 struct afs_server_entry
*pn
= n
< new->nr_servers
? &new->servers
[n
] : NULL
;
196 struct afs_server_entry
*po
= o
< old
->nr_servers
? &old
->servers
[o
] : NULL
;
197 struct afs_server_entry
*s
;
201 if (pn
&& po
&& pn
->server
== po
->server
) {
202 pn
->cb_expires_at
= po
->cb_expires_at
;
203 list_replace(&po
->slink
, &pn
->slink
);
210 diff
= memcmp(&pn
->server
->uuid
, &po
->server
->uuid
,
211 sizeof(pn
->server
->uuid
));
216 list_for_each(p
, &pn
->server
->volumes
) {
217 s
= list_entry(p
, struct afs_server_entry
, slink
);
218 if (volume
->vid
<= s
->volume
->vid
)
221 list_add_tail(&pn
->slink
, p
);
224 list_del(&po
->slink
);
229 up_write(&volume
->cell
->vs_lock
);
233 * Detach a volume from the servers it has been using.
235 void afs_detach_volume_from_servers(struct afs_volume
*volume
, struct afs_server_list
*slist
)
239 if (!slist
->attached
)
242 down_write(&volume
->cell
->vs_lock
);
244 for (i
= 0; i
< slist
->nr_servers
; i
++)
245 list_del(&slist
->servers
[i
].slink
);
247 slist
->attached
= false;
248 up_write(&volume
->cell
->vs_lock
);