Skip to content

Commit 0a5143f

Browse files
committed
afs: Implement VL server rotation
Track VL servers as independent entities rather than lumping all their addresses together into one set and implement server-level rotation by: (1) Add the concept of a VL server list, where each server has its own separate address list. This code is similar to the FS server list. (2) Use the DNS resolver to retrieve a set of servers and their associated addresses, ports, preference and weight ratings. (3) In the case of a legacy DNS resolver or an address list given directly through /proc/net/afs/cells, create a list containing just a dummy server record and attach all the addresses to that. (4) Implement a simple rotation policy, for the moment ignoring the priorities and weights assigned to the servers. (5) Show the address list through /proc/net/afs/<cell>/vlservers. This also displays the source and status of the data as indicated by the upcall. Signed-off-by: David Howells <dhowells@redhat.com>
1 parent e7f680f commit 0a5143f

File tree

11 files changed

+905
-218
lines changed

11 files changed

+905
-218
lines changed

fs/afs/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ kafs-y := \
2929
super.o \
3030
netdevices.o \
3131
vlclient.o \
32+
vl_rotate.o \
33+
vl_list.o \
3234
volume.o \
3335
write.o \
3436
xattr.o

fs/afs/addr_list.c

Lines changed: 84 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -64,38 +64,50 @@ struct afs_addr_list *afs_alloc_addrlist(unsigned int nr,
6464
/*
6565
* Parse a text string consisting of delimited addresses.
6666
*/
67-
struct afs_addr_list *afs_parse_text_addrs(const char *text, size_t len,
68-
char delim,
69-
unsigned short service,
70-
unsigned short port)
67+
struct afs_vlserver_list *afs_parse_text_addrs(struct afs_net *net,
68+
const char *text, size_t len,
69+
char delim,
70+
unsigned short service,
71+
unsigned short port)
7172
{
73+
struct afs_vlserver_list *vllist;
7274
struct afs_addr_list *alist;
7375
const char *p, *end = text + len;
76+
const char *problem;
7477
unsigned int nr = 0;
78+
int ret = -ENOMEM;
7579

7680
_enter("%*.*s,%c", (int)len, (int)len, text, delim);
7781

78-
if (!len)
82+
if (!len) {
83+
_leave(" = -EDESTADDRREQ [empty]");
7984
return ERR_PTR(-EDESTADDRREQ);
85+
}
8086

8187
if (delim == ':' && (memchr(text, ',', len) || !memchr(text, '.', len)))
8288
delim = ',';
8389

8490
/* Count the addresses */
8591
p = text;
8692
do {
87-
if (!*p)
88-
return ERR_PTR(-EINVAL);
93+
if (!*p) {
94+
problem = "nul";
95+
goto inval;
96+
}
8997
if (*p == delim)
9098
continue;
9199
nr++;
92100
if (*p == '[') {
93101
p++;
94-
if (p == end)
95-
return ERR_PTR(-EINVAL);
102+
if (p == end) {
103+
problem = "brace1";
104+
goto inval;
105+
}
96106
p = memchr(p, ']', end - p);
97-
if (!p)
98-
return ERR_PTR(-EINVAL);
107+
if (!p) {
108+
problem = "brace2";
109+
goto inval;
110+
}
99111
p++;
100112
if (p >= end)
101113
break;
@@ -109,10 +121,19 @@ struct afs_addr_list *afs_parse_text_addrs(const char *text, size_t len,
109121

110122
_debug("%u/%u addresses", nr, AFS_MAX_ADDRESSES);
111123

112-
alist = afs_alloc_addrlist(nr, service, port);
113-
if (!alist)
124+
vllist = afs_alloc_vlserver_list(1);
125+
if (!vllist)
114126
return ERR_PTR(-ENOMEM);
115127

128+
vllist->nr_servers = 1;
129+
vllist->servers[0].server = afs_alloc_vlserver("<dummy>", 7, AFS_VL_PORT);
130+
if (!vllist->servers[0].server)
131+
goto error_vl;
132+
133+
alist = afs_alloc_addrlist(nr, service, AFS_VL_PORT);
134+
if (!alist)
135+
goto error;
136+
116137
/* Extract the addresses */
117138
p = text;
118139
do {
@@ -135,17 +156,21 @@ struct afs_addr_list *afs_parse_text_addrs(const char *text, size_t len,
135156
break;
136157
}
137158

138-
if (in4_pton(p, q - p, (u8 *)&x[0], -1, &stop))
159+
if (in4_pton(p, q - p, (u8 *)&x[0], -1, &stop)) {
139160
family = AF_INET;
140-
else if (in6_pton(p, q - p, (u8 *)x, -1, &stop))
161+
} else if (in6_pton(p, q - p, (u8 *)x, -1, &stop)) {
141162
family = AF_INET6;
142-
else
163+
} else {
164+
problem = "family";
143165
goto bad_address;
166+
}
144167

145-
if (stop != q)
168+
p = q;
169+
if (stop != p) {
170+
problem = "nostop";
146171
goto bad_address;
172+
}
147173

148-
p = q;
149174
if (q < end && *q == ']')
150175
p++;
151176

@@ -154,18 +179,23 @@ struct afs_addr_list *afs_parse_text_addrs(const char *text, size_t len,
154179
/* Port number specification "+1234" */
155180
xport = 0;
156181
p++;
157-
if (p >= end || !isdigit(*p))
182+
if (p >= end || !isdigit(*p)) {
183+
problem = "port";
158184
goto bad_address;
185+
}
159186
do {
160187
xport *= 10;
161188
xport += *p - '0';
162-
if (xport > 65535)
189+
if (xport > 65535) {
190+
problem = "pval";
163191
goto bad_address;
192+
}
164193
p++;
165194
} while (p < end && isdigit(*p));
166195
} else if (*p == delim) {
167196
p++;
168197
} else {
198+
problem = "weird";
169199
goto bad_address;
170200
}
171201
}
@@ -177,12 +207,23 @@ struct afs_addr_list *afs_parse_text_addrs(const char *text, size_t len,
177207

178208
} while (p < end);
179209

210+
rcu_assign_pointer(vllist->servers[0].server->addresses, alist);
180211
_leave(" = [nr %u]", alist->nr_addrs);
181-
return alist;
212+
return vllist;
182213

183-
bad_address:
184-
kfree(alist);
214+
inval:
215+
_leave(" = -EINVAL [%s %zu %*.*s]",
216+
problem, p - text, (int)len, (int)len, text);
185217
return ERR_PTR(-EINVAL);
218+
bad_address:
219+
_leave(" = -EINVAL [%s %zu %*.*s]",
220+
problem, p - text, (int)len, (int)len, text);
221+
ret = -EINVAL;
222+
error:
223+
afs_put_addrlist(alist);
224+
error_vl:
225+
afs_put_vlserverlist(net, vllist);
226+
return ERR_PTR(ret);
186227
}
187228

188229
/*
@@ -201,30 +242,34 @@ static int afs_cmp_addr_list(const struct afs_addr_list *a1,
201242
/*
202243
* Perform a DNS query for VL servers and build a up an address list.
203244
*/
204-
struct afs_addr_list *afs_dns_query(struct afs_cell *cell, time64_t *_expiry)
245+
struct afs_vlserver_list *afs_dns_query(struct afs_cell *cell, time64_t *_expiry)
205246
{
206-
struct afs_addr_list *alist;
207-
char *vllist = NULL;
247+
struct afs_vlserver_list *vllist;
248+
char *result = NULL;
208249
int ret;
209250

210251
_enter("%s", cell->name);
211252

212-
ret = dns_query("afsdb", cell->name, cell->name_len,
213-
"", &vllist, _expiry);
214-
if (ret < 0)
253+
ret = dns_query("afsdb", cell->name, cell->name_len, "srv=1",
254+
&result, _expiry);
255+
if (ret < 0) {
256+
_leave(" = %d [dns]", ret);
215257
return ERR_PTR(ret);
216-
217-
alist = afs_parse_text_addrs(vllist, strlen(vllist), ',',
218-
VL_SERVICE, AFS_VL_PORT);
219-
if (IS_ERR(alist)) {
220-
kfree(vllist);
221-
if (alist != ERR_PTR(-ENOMEM))
222-
pr_err("Failed to parse DNS data\n");
223-
return alist;
224258
}
225259

226-
kfree(vllist);
227-
return alist;
260+
if (*_expiry == 0)
261+
*_expiry = ktime_get_real_seconds() + 60;
262+
263+
if (ret > 1 && result[0] == 0)
264+
vllist = afs_extract_vlserver_list(cell, result, ret);
265+
else
266+
vllist = afs_parse_text_addrs(cell->net, result, ret, ',',
267+
VL_SERVICE, AFS_VL_PORT);
268+
kfree(result);
269+
if (IS_ERR(vllist) && vllist != ERR_PTR(-ENOMEM))
270+
pr_err("Failed to parse DNS data %ld\n", PTR_ERR(vllist));
271+
272+
return vllist;
228273
}
229274

230275
/*
@@ -347,43 +392,3 @@ int afs_end_cursor(struct afs_addr_cursor *ac)
347392
ac->begun = false;
348393
return ac->error;
349394
}
350-
351-
/*
352-
* Set the address cursor for iterating over VL servers.
353-
*/
354-
int afs_set_vl_cursor(struct afs_addr_cursor *ac, struct afs_cell *cell)
355-
{
356-
struct afs_addr_list *alist;
357-
int ret;
358-
359-
if (!rcu_access_pointer(cell->vl_addrs)) {
360-
ret = wait_on_bit(&cell->flags, AFS_CELL_FL_NO_LOOKUP_YET,
361-
TASK_INTERRUPTIBLE);
362-
if (ret < 0)
363-
return ret;
364-
365-
if (!rcu_access_pointer(cell->vl_addrs) &&
366-
ktime_get_real_seconds() < cell->dns_expiry)
367-
return cell->error;
368-
}
369-
370-
read_lock(&cell->vl_addrs_lock);
371-
alist = rcu_dereference_protected(cell->vl_addrs,
372-
lockdep_is_held(&cell->vl_addrs_lock));
373-
if (alist->nr_addrs > 0)
374-
afs_get_addrlist(alist);
375-
else
376-
alist = NULL;
377-
read_unlock(&cell->vl_addrs_lock);
378-
379-
if (!alist)
380-
return -EDESTADDRREQ;
381-
382-
ac->alist = alist;
383-
ac->addr = NULL;
384-
ac->start = READ_ONCE(alist->index);
385-
ac->index = ac->start;
386-
ac->error = 0;
387-
ac->begun = false;
388-
return 0;
389-
}

fs/afs/cell.c

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ struct afs_cell *afs_lookup_cell_rcu(struct afs_net *net,
119119
*/
120120
static struct afs_cell *afs_alloc_cell(struct afs_net *net,
121121
const char *name, unsigned int namelen,
122-
const char *vllist)
122+
const char *addresses)
123123
{
124124
struct afs_cell *cell;
125125
int i, ret;
@@ -134,7 +134,7 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net,
134134
if (namelen == 5 && memcmp(name, "@cell", 5) == 0)
135135
return ERR_PTR(-EINVAL);
136136

137-
_enter("%*.*s,%s", namelen, namelen, name, vllist);
137+
_enter("%*.*s,%s", namelen, namelen, name, addresses);
138138

139139
cell = kzalloc(sizeof(struct afs_cell), GFP_KERNEL);
140140
if (!cell) {
@@ -153,22 +153,23 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net,
153153
(1 << AFS_CELL_FL_NO_LOOKUP_YET));
154154
INIT_LIST_HEAD(&cell->proc_volumes);
155155
rwlock_init(&cell->proc_lock);
156-
rwlock_init(&cell->vl_addrs_lock);
156+
rwlock_init(&cell->vl_servers_lock);
157157

158158
/* Fill in the VL server list if we were given a list of addresses to
159159
* use.
160160
*/
161-
if (vllist) {
162-
struct afs_addr_list *alist;
163-
164-
alist = afs_parse_text_addrs(vllist, strlen(vllist), ':',
165-
VL_SERVICE, AFS_VL_PORT);
166-
if (IS_ERR(alist)) {
167-
ret = PTR_ERR(alist);
161+
if (addresses) {
162+
struct afs_vlserver_list *vllist;
163+
164+
vllist = afs_parse_text_addrs(net,
165+
addresses, strlen(addresses), ':',
166+
VL_SERVICE, AFS_VL_PORT);
167+
if (IS_ERR(vllist)) {
168+
ret = PTR_ERR(vllist);
168169
goto parse_failed;
169170
}
170171

171-
rcu_assign_pointer(cell->vl_addrs, alist);
172+
rcu_assign_pointer(cell->vl_servers, vllist);
172173
cell->dns_expiry = TIME64_MAX;
173174
}
174175

@@ -356,14 +357,14 @@ int afs_cell_init(struct afs_net *net, const char *rootcell)
356357
*/
357358
static void afs_update_cell(struct afs_cell *cell)
358359
{
359-
struct afs_addr_list *alist, *old;
360+
struct afs_vlserver_list *vllist, *old;
360361
time64_t now, expiry;
361362

362363
_enter("%s", cell->name);
363364

364-
alist = afs_dns_query(cell, &expiry);
365-
if (IS_ERR(alist)) {
366-
switch (PTR_ERR(alist)) {
365+
vllist = afs_dns_query(cell, &expiry);
366+
if (IS_ERR(vllist)) {
367+
switch (PTR_ERR(vllist)) {
367368
case -ENODATA:
368369
/* The DNS said that the cell does not exist */
369370
set_bit(AFS_CELL_FL_NOT_FOUND, &cell->flags);
@@ -387,12 +388,12 @@ static void afs_update_cell(struct afs_cell *cell)
387388
/* Exclusion on changing vl_addrs is achieved by a
388389
* non-reentrant work item.
389390
*/
390-
old = rcu_dereference_protected(cell->vl_addrs, true);
391-
rcu_assign_pointer(cell->vl_addrs, alist);
391+
old = rcu_dereference_protected(cell->vl_servers, true);
392+
rcu_assign_pointer(cell->vl_servers, vllist);
392393
cell->dns_expiry = expiry;
393394

394395
if (old)
395-
afs_put_addrlist(old);
396+
afs_put_vlserverlist(cell->net, old);
396397
}
397398

398399
if (test_and_clear_bit(AFS_CELL_FL_NO_LOOKUP_YET, &cell->flags))
@@ -414,7 +415,7 @@ static void afs_cell_destroy(struct rcu_head *rcu)
414415

415416
ASSERTCMP(atomic_read(&cell->usage), ==, 0);
416417

417-
afs_put_addrlist(rcu_access_pointer(cell->vl_addrs));
418+
afs_put_vlserverlist(cell->net, rcu_access_pointer(cell->vl_servers));
418419
key_put(cell->anonymous_key);
419420
kfree(cell);
420421

fs/afs/dynroot.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ static int afs_probe_cell_name(struct dentry *dentry)
4646
return 0;
4747
}
4848

49-
ret = dns_query("afsdb", name, len, "", NULL, NULL);
49+
ret = dns_query("afsdb", name, len, "srv=1", NULL, NULL);
5050
if (ret == -ENODATA)
5151
ret = -EDESTADDRREQ;
5252
return ret;

0 commit comments

Comments
 (0)