Blame view

fs/afs/server_list.c 2.91 KB
2874c5fd2   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
d2ddc776a   David Howells   afs: Overhaul vol...
2
3
4
5
  /* AFS fileserver list management.
   *
   * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
   * Written by David Howells (dhowells@redhat.com)
d2ddc776a   David Howells   afs: Overhaul vol...
6
7
8
9
10
11
12
13
14
   */
  
  #include <linux/kernel.h>
  #include <linux/slab.h>
  #include "internal.h"
  
  void afs_put_serverlist(struct afs_net *net, struct afs_server_list *slist)
  {
  	int i;
0fafdc9f8   David Howells   afs: Fix file loc...
15
  	if (slist && refcount_dec_and_test(&slist->usage)) {
20325960f   David Howells   afs: Reorganise v...
16
  		for (i = 0; i < slist->nr_servers; i++)
977e5f8ed   David Howells   afs: Split the us...
17
18
  			afs_unuse_server(net, slist->servers[i].server,
  					 afs_server_trace_put_slist);
d2ddc776a   David Howells   afs: Overhaul vol...
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
  		kfree(slist);
  	}
  }
  
  /*
   * Build a server list from a VLDB record.
   */
  struct afs_server_list *afs_alloc_server_list(struct afs_cell *cell,
  					      struct key *key,
  					      struct afs_vldb_entry *vldb,
  					      u8 type_mask)
  {
  	struct afs_server_list *slist;
  	struct afs_server *server;
  	int ret = -ENOMEM, nr_servers = 0, i, j;
  
  	for (i = 0; i < vldb->nr_servers; i++)
  		if (vldb->fs_mask[i] & type_mask)
  			nr_servers++;
c2b8bd49d   Gustavo A. R. Silva   afs: Use struct_s...
38
  	slist = kzalloc(struct_size(slist, servers, nr_servers), GFP_KERNEL);
d2ddc776a   David Howells   afs: Overhaul vol...
39
40
41
42
  	if (!slist)
  		goto error;
  
  	refcount_set(&slist->usage, 1);
d4a96bec7   David Howells   afs: Fix refcount...
43
  	rwlock_init(&slist->lock);
d2ddc776a   David Howells   afs: Overhaul vol...
44

194d28cf1   David Howells   afs: Retain more ...
45
46
  	for (i = 0; i < AFS_MAXTYPES; i++)
  		slist->vids[i] = vldb->vid[i];
d2ddc776a   David Howells   afs: Overhaul vol...
47
48
49
50
  	/* Make sure a records exists for each server in the list. */
  	for (i = 0; i < vldb->nr_servers; i++) {
  		if (!(vldb->fs_mask[i] & type_mask))
  			continue;
810068059   David Howells   afs: Use the serv...
51
52
  		server = afs_lookup_server(cell, key, &vldb->fs_server[i],
  					   vldb->addr_version[i]);
d2ddc776a   David Howells   afs: Overhaul vol...
53
54
  		if (IS_ERR(server)) {
  			ret = PTR_ERR(server);
45df84627   David Howells   afs: Fix server l...
55
56
  			if (ret == -ENOENT ||
  			    ret == -ENOMEDIUM)
d2ddc776a   David Howells   afs: Overhaul vol...
57
58
59
  				continue;
  			goto error_2;
  		}
d4a96bec7   David Howells   afs: Fix refcount...
60
  		/* Insertion-sort by UUID */
d2ddc776a   David Howells   afs: Overhaul vol...
61
  		for (j = 0; j < slist->nr_servers; j++)
d4a96bec7   David Howells   afs: Fix refcount...
62
63
64
  			if (memcmp(&slist->servers[j].server->uuid,
  				   &server->uuid,
  				   sizeof(server->uuid)) >= 0)
d2ddc776a   David Howells   afs: Overhaul vol...
65
66
67
  				break;
  		if (j < slist->nr_servers) {
  			if (slist->servers[j].server == server) {
452181936   David Howells   afs: Trace afs_se...
68
69
  				afs_put_server(cell->net, server,
  					       afs_server_trace_put_slist_isort);
d2ddc776a   David Howells   afs: Overhaul vol...
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
  				continue;
  			}
  
  			memmove(slist->servers + j + 1,
  				slist->servers + j,
  				(slist->nr_servers - j) * sizeof(struct afs_server_entry));
  		}
  
  		slist->servers[j].server = server;
  		slist->nr_servers++;
  	}
  
  	if (slist->nr_servers == 0) {
  		ret = -EDESTADDRREQ;
  		goto error_2;
  	}
  
  	return slist;
  
  error_2:
  	afs_put_serverlist(cell->net, slist);
  error:
  	return ERR_PTR(ret);
  }
  
  /*
   * Copy the annotations from an old server list to its potential replacement.
   */
  bool afs_annotate_server_list(struct afs_server_list *new,
  			      struct afs_server_list *old)
  {
  	struct afs_server *cur;
  	int i, j;
  
  	if (old->nr_servers != new->nr_servers)
  		goto changed;
  
  	for (i = 0; i < old->nr_servers; i++)
  		if (old->servers[i].server != new->servers[i].server)
  			goto changed;
  
  	return false;
  
  changed:
3bf0fb6f3   David Howells   afs: Probe multip...
114
115
  	/* Maintain the same preferred server as before if possible. */
  	cur = old->servers[old->preferred].server;
d2ddc776a   David Howells   afs: Overhaul vol...
116
117
  	for (j = 0; j < new->nr_servers; j++) {
  		if (new->servers[j].server == cur) {
3bf0fb6f3   David Howells   afs: Probe multip...
118
  			new->preferred = j;
d2ddc776a   David Howells   afs: Overhaul vol...
119
120
121
  			break;
  		}
  	}
d2ddc776a   David Howells   afs: Overhaul vol...
122
123
  	return true;
  }