aboutsummaryrefslogtreecommitdiffstats
path: root/fs/afs
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2019-05-07 10:06:36 -0400
committerDavid Howells <dhowells@redhat.com>2019-05-16 07:58:23 -0400
commitd5c32c89b208e39a39cd8639aa21c012ce0daf4d (patch)
tree856d5540f898c041c51f8868e53381f37d2ff0b7 /fs/afs
parenta49294eac27c7159cd8b89a96c3b1a857e37b683 (diff)
afs: Fix cell DNS lookup
Currently, once configured, AFS cells are looked up in the DNS at regular intervals - which is a waste of resources if those cells aren't being used. It also leads to a problem where cells preloaded, but not configured, before the network is brought up end up effectively statically configured with no VL servers and are unable to get any. Fix this by not doing the DNS lookup until the first time a cell is touched. It is waited for if we don't have any cached records yet, otherwise the DNS lookup to maintain the record is done in the background. This has the downside that the first time you touch a cell, you now have to wait for the upcall to do the required DNS lookups rather than them already being cached. Further, the record is not replaced if the old record has at least one server in it and the new record doesn't have any. Fixes: 0a5143f2f89c ("afs: Implement VL server rotation") Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'fs/afs')
-rw-r--r--fs/afs/cell.c169
-rw-r--r--fs/afs/internal.h10
-rw-r--r--fs/afs/vl_rotate.c26
3 files changed, 130 insertions, 75 deletions
diff --git a/fs/afs/cell.c b/fs/afs/cell.c
index 47f96be05163..9c3b07ba2222 100644
--- a/fs/afs/cell.c
+++ b/fs/afs/cell.c
@@ -152,8 +152,6 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net,
152 152
153 atomic_set(&cell->usage, 2); 153 atomic_set(&cell->usage, 2);
154 INIT_WORK(&cell->manager, afs_manage_cell); 154 INIT_WORK(&cell->manager, afs_manage_cell);
155 cell->flags = ((1 << AFS_CELL_FL_NOT_READY) |
156 (1 << AFS_CELL_FL_NO_LOOKUP_YET));
157 INIT_LIST_HEAD(&cell->proc_volumes); 155 INIT_LIST_HEAD(&cell->proc_volumes);
158 rwlock_init(&cell->proc_lock); 156 rwlock_init(&cell->proc_lock);
159 rwlock_init(&cell->vl_servers_lock); 157 rwlock_init(&cell->vl_servers_lock);
@@ -170,17 +168,25 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net,
170 goto parse_failed; 168 goto parse_failed;
171 } 169 }
172 170
171 vllist->source = DNS_RECORD_FROM_CONFIG;
172 vllist->status = DNS_LOOKUP_NOT_DONE;
173 cell->dns_expiry = TIME64_MAX; 173 cell->dns_expiry = TIME64_MAX;
174 } else { 174 } else {
175 ret = -ENOMEM; 175 ret = -ENOMEM;
176 vllist = afs_alloc_vlserver_list(0); 176 vllist = afs_alloc_vlserver_list(0);
177 if (!vllist) 177 if (!vllist)
178 goto error; 178 goto error;
179 vllist->source = DNS_RECORD_UNAVAILABLE;
180 vllist->status = DNS_LOOKUP_NOT_DONE;
179 cell->dns_expiry = ktime_get_real_seconds(); 181 cell->dns_expiry = ktime_get_real_seconds();
180 } 182 }
181 183
182 rcu_assign_pointer(cell->vl_servers, vllist); 184 rcu_assign_pointer(cell->vl_servers, vllist);
183 185
186 cell->dns_source = vllist->source;
187 cell->dns_status = vllist->status;
188 smp_store_release(&cell->dns_lookup_count, 1); /* vs source/status */
189
184 _leave(" = %p", cell); 190 _leave(" = %p", cell);
185 return cell; 191 return cell;
186 192
@@ -212,6 +218,7 @@ struct afs_cell *afs_lookup_cell(struct afs_net *net,
212{ 218{
213 struct afs_cell *cell, *candidate, *cursor; 219 struct afs_cell *cell, *candidate, *cursor;
214 struct rb_node *parent, **pp; 220 struct rb_node *parent, **pp;
221 enum afs_cell_state state;
215 int ret, n; 222 int ret, n;
216 223
217 _enter("%s,%s", name, vllist); 224 _enter("%s,%s", name, vllist);
@@ -271,18 +278,16 @@ struct afs_cell *afs_lookup_cell(struct afs_net *net,
271 278
272wait_for_cell: 279wait_for_cell:
273 _debug("wait_for_cell"); 280 _debug("wait_for_cell");
274 ret = wait_on_bit(&cell->flags, AFS_CELL_FL_NOT_READY, TASK_INTERRUPTIBLE); 281 wait_var_event(&cell->state,
275 smp_rmb(); 282 ({
276 283 state = smp_load_acquire(&cell->state); /* vs error */
277 switch (READ_ONCE(cell->state)) { 284 state == AFS_CELL_ACTIVE || state == AFS_CELL_FAILED;
278 case AFS_CELL_FAILED: 285 }));
286
287 /* Check the state obtained from the wait check. */
288 if (state == AFS_CELL_FAILED) {
279 ret = cell->error; 289 ret = cell->error;
280 goto error; 290 goto error;
281 default:
282 _debug("weird %u %d", cell->state, cell->error);
283 goto error;
284 case AFS_CELL_ACTIVE:
285 break;
286 } 291 }
287 292
288 _leave(" = %p [cell]", cell); 293 _leave(" = %p [cell]", cell);
@@ -364,16 +369,46 @@ int afs_cell_init(struct afs_net *net, const char *rootcell)
364/* 369/*
365 * Update a cell's VL server address list from the DNS. 370 * Update a cell's VL server address list from the DNS.
366 */ 371 */
367static void afs_update_cell(struct afs_cell *cell) 372static int afs_update_cell(struct afs_cell *cell)
368{ 373{
369 struct afs_vlserver_list *vllist, *old; 374 struct afs_vlserver_list *vllist, *old = NULL, *p;
370 unsigned int min_ttl = READ_ONCE(afs_cell_min_ttl); 375 unsigned int min_ttl = READ_ONCE(afs_cell_min_ttl);
371 unsigned int max_ttl = READ_ONCE(afs_cell_max_ttl); 376 unsigned int max_ttl = READ_ONCE(afs_cell_max_ttl);
372 time64_t now, expiry = 0; 377 time64_t now, expiry = 0;
378 int ret = 0;
373 379
374 _enter("%s", cell->name); 380 _enter("%s", cell->name);
375 381
376 vllist = afs_dns_query(cell, &expiry); 382 vllist = afs_dns_query(cell, &expiry);
383 if (IS_ERR(vllist)) {
384 ret = PTR_ERR(vllist);
385
386 _debug("%s: fail %d", cell->name, ret);
387 if (ret == -ENOMEM)
388 goto out_wake;
389
390 ret = -ENOMEM;
391 vllist = afs_alloc_vlserver_list(0);
392 if (!vllist)
393 goto out_wake;
394
395 switch (ret) {
396 case -ENODATA:
397 case -EDESTADDRREQ:
398 vllist->status = DNS_LOOKUP_GOT_NOT_FOUND;
399 break;
400 case -EAGAIN:
401 case -ECONNREFUSED:
402 vllist->status = DNS_LOOKUP_GOT_TEMP_FAILURE;
403 break;
404 default:
405 vllist->status = DNS_LOOKUP_GOT_LOCAL_FAILURE;
406 break;
407 }
408 }
409
410 _debug("%s: got list %d %d", cell->name, vllist->source, vllist->status);
411 cell->dns_status = vllist->status;
377 412
378 now = ktime_get_real_seconds(); 413 now = ktime_get_real_seconds();
379 if (min_ttl > max_ttl) 414 if (min_ttl > max_ttl)
@@ -383,46 +418,47 @@ static void afs_update_cell(struct afs_cell *cell)
383 else if (expiry > now + max_ttl) 418 else if (expiry > now + max_ttl)
384 expiry = now + max_ttl; 419 expiry = now + max_ttl;
385 420
386 if (IS_ERR(vllist)) { 421 _debug("%s: status %d", cell->name, vllist->status);
387 switch (PTR_ERR(vllist)) { 422 if (vllist->source == DNS_RECORD_UNAVAILABLE) {
388 case -ENODATA: 423 switch (vllist->status) {
389 case -EDESTADDRREQ: 424 case DNS_LOOKUP_GOT_NOT_FOUND:
390 /* The DNS said that the cell does not exist or there 425 /* The DNS said that the cell does not exist or there
391 * weren't any addresses to be had. 426 * weren't any addresses to be had.
392 */ 427 */
393 set_bit(AFS_CELL_FL_NOT_FOUND, &cell->flags);
394 clear_bit(AFS_CELL_FL_DNS_FAIL, &cell->flags);
395 cell->dns_expiry = expiry; 428 cell->dns_expiry = expiry;
396 break; 429 break;
397 430
398 case -EAGAIN: 431 case DNS_LOOKUP_BAD:
399 case -ECONNREFUSED: 432 case DNS_LOOKUP_GOT_LOCAL_FAILURE:
433 case DNS_LOOKUP_GOT_TEMP_FAILURE:
434 case DNS_LOOKUP_GOT_NS_FAILURE:
400 default: 435 default:
401 set_bit(AFS_CELL_FL_DNS_FAIL, &cell->flags);
402 cell->dns_expiry = now + 10; 436 cell->dns_expiry = now + 10;
403 break; 437 break;
404 } 438 }
405
406 cell->error = -EDESTADDRREQ;
407 } else { 439 } else {
408 clear_bit(AFS_CELL_FL_DNS_FAIL, &cell->flags);
409 clear_bit(AFS_CELL_FL_NOT_FOUND, &cell->flags);
410
411 write_lock(&cell->vl_servers_lock);
412 old = rcu_dereference_protected(cell->vl_servers, true);
413 rcu_assign_pointer(cell->vl_servers, vllist);
414 cell->dns_expiry = expiry; 440 cell->dns_expiry = expiry;
415 write_unlock(&cell->vl_servers_lock);
416
417 afs_put_vlserverlist(cell->net, old);
418 } 441 }
419 442
420 if (test_and_clear_bit(AFS_CELL_FL_NO_LOOKUP_YET, &cell->flags)) 443 /* Replace the VL server list if the new record has servers or the old
421 wake_up_bit(&cell->flags, AFS_CELL_FL_NO_LOOKUP_YET); 444 * record doesn't.
445 */
446 write_lock(&cell->vl_servers_lock);
447 p = rcu_dereference_protected(cell->vl_servers, true);
448 if (vllist->nr_servers > 0 || p->nr_servers == 0) {
449 rcu_assign_pointer(cell->vl_servers, vllist);
450 cell->dns_source = vllist->source;
451 old = p;
452 }
453 write_unlock(&cell->vl_servers_lock);
454 afs_put_vlserverlist(cell->net, old);
422 455
423 now = ktime_get_real_seconds(); 456out_wake:
424 afs_set_cell_timer(cell->net, cell->dns_expiry - now); 457 smp_store_release(&cell->dns_lookup_count,
425 _leave(""); 458 cell->dns_lookup_count + 1); /* vs source/status */
459 wake_up_var(&cell->dns_lookup_count);
460 _leave(" = %d", ret);
461 return ret;
426} 462}
427 463
428/* 464/*
@@ -493,8 +529,7 @@ void afs_put_cell(struct afs_net *net, struct afs_cell *cell)
493 now = ktime_get_real_seconds(); 529 now = ktime_get_real_seconds();
494 cell->last_inactive = now; 530 cell->last_inactive = now;
495 expire_delay = 0; 531 expire_delay = 0;
496 if (!test_bit(AFS_CELL_FL_DNS_FAIL, &cell->flags) && 532 if (cell->vl_servers->nr_servers)
497 !test_bit(AFS_CELL_FL_NOT_FOUND, &cell->flags))
498 expire_delay = afs_cell_gc_delay; 533 expire_delay = afs_cell_gc_delay;
499 534
500 if (atomic_dec_return(&cell->usage) > 1) 535 if (atomic_dec_return(&cell->usage) > 1)
@@ -625,11 +660,13 @@ again:
625 goto final_destruction; 660 goto final_destruction;
626 if (cell->state == AFS_CELL_FAILED) 661 if (cell->state == AFS_CELL_FAILED)
627 goto done; 662 goto done;
628 cell->state = AFS_CELL_UNSET; 663 smp_store_release(&cell->state, AFS_CELL_UNSET);
664 wake_up_var(&cell->state);
629 goto again; 665 goto again;
630 666
631 case AFS_CELL_UNSET: 667 case AFS_CELL_UNSET:
632 cell->state = AFS_CELL_ACTIVATING; 668 smp_store_release(&cell->state, AFS_CELL_ACTIVATING);
669 wake_up_var(&cell->state);
633 goto again; 670 goto again;
634 671
635 case AFS_CELL_ACTIVATING: 672 case AFS_CELL_ACTIVATING:
@@ -637,28 +674,29 @@ again:
637 if (ret < 0) 674 if (ret < 0)
638 goto activation_failed; 675 goto activation_failed;
639 676
640 cell->state = AFS_CELL_ACTIVE; 677 smp_store_release(&cell->state, AFS_CELL_ACTIVE);
641 smp_wmb(); 678 wake_up_var(&cell->state);
642 clear_bit(AFS_CELL_FL_NOT_READY, &cell->flags);
643 wake_up_bit(&cell->flags, AFS_CELL_FL_NOT_READY);
644 goto again; 679 goto again;
645 680
646 case AFS_CELL_ACTIVE: 681 case AFS_CELL_ACTIVE:
647 if (atomic_read(&cell->usage) > 1) { 682 if (atomic_read(&cell->usage) > 1) {
648 time64_t now = ktime_get_real_seconds(); 683 if (test_and_clear_bit(AFS_CELL_FL_DO_LOOKUP, &cell->flags)) {
649 if (cell->dns_expiry <= now && net->live) 684 ret = afs_update_cell(cell);
650 afs_update_cell(cell); 685 if (ret < 0)
686 cell->error = ret;
687 }
651 goto done; 688 goto done;
652 } 689 }
653 cell->state = AFS_CELL_DEACTIVATING; 690 smp_store_release(&cell->state, AFS_CELL_DEACTIVATING);
691 wake_up_var(&cell->state);
654 goto again; 692 goto again;
655 693
656 case AFS_CELL_DEACTIVATING: 694 case AFS_CELL_DEACTIVATING:
657 set_bit(AFS_CELL_FL_NOT_READY, &cell->flags);
658 if (atomic_read(&cell->usage) > 1) 695 if (atomic_read(&cell->usage) > 1)
659 goto reverse_deactivation; 696 goto reverse_deactivation;
660 afs_deactivate_cell(net, cell); 697 afs_deactivate_cell(net, cell);
661 cell->state = AFS_CELL_INACTIVE; 698 smp_store_release(&cell->state, AFS_CELL_INACTIVE);
699 wake_up_var(&cell->state);
662 goto again; 700 goto again;
663 701
664 default: 702 default:
@@ -671,17 +709,13 @@ activation_failed:
671 cell->error = ret; 709 cell->error = ret;
672 afs_deactivate_cell(net, cell); 710 afs_deactivate_cell(net, cell);
673 711
674 cell->state = AFS_CELL_FAILED; 712 smp_store_release(&cell->state, AFS_CELL_FAILED); /* vs error */
675 smp_wmb(); 713 wake_up_var(&cell->state);
676 if (test_and_clear_bit(AFS_CELL_FL_NOT_READY, &cell->flags))
677 wake_up_bit(&cell->flags, AFS_CELL_FL_NOT_READY);
678 goto again; 714 goto again;
679 715
680reverse_deactivation: 716reverse_deactivation:
681 cell->state = AFS_CELL_ACTIVE; 717 smp_store_release(&cell->state, AFS_CELL_ACTIVE);
682 smp_wmb(); 718 wake_up_var(&cell->state);
683 clear_bit(AFS_CELL_FL_NOT_READY, &cell->flags);
684 wake_up_bit(&cell->flags, AFS_CELL_FL_NOT_READY);
685 _leave(" [deact->act]"); 719 _leave(" [deact->act]");
686 return; 720 return;
687 721
@@ -741,11 +775,16 @@ void afs_manage_cells(struct work_struct *work)
741 } 775 }
742 776
743 if (usage == 1) { 777 if (usage == 1) {
778 struct afs_vlserver_list *vllist;
744 time64_t expire_at = cell->last_inactive; 779 time64_t expire_at = cell->last_inactive;
745 780
746 if (!test_bit(AFS_CELL_FL_DNS_FAIL, &cell->flags) && 781 read_lock(&cell->vl_servers_lock);
747 !test_bit(AFS_CELL_FL_NOT_FOUND, &cell->flags)) 782 vllist = rcu_dereference_protected(
783 cell->vl_servers,
784 lockdep_is_held(&cell->vl_servers_lock));
785 if (vllist->nr_servers > 0)
748 expire_at += afs_cell_gc_delay; 786 expire_at += afs_cell_gc_delay;
787 read_unlock(&cell->vl_servers_lock);
749 if (purging || expire_at <= now) 788 if (purging || expire_at <= now)
750 sched_cell = true; 789 sched_cell = true;
751 else if (expire_at < next_manage) 790 else if (expire_at < next_manage)
@@ -753,10 +792,8 @@ void afs_manage_cells(struct work_struct *work)
753 } 792 }
754 793
755 if (!purging) { 794 if (!purging) {
756 if (cell->dns_expiry <= now) 795 if (test_bit(AFS_CELL_FL_DO_LOOKUP, &cell->flags))
757 sched_cell = true; 796 sched_cell = true;
758 else if (cell->dns_expiry <= next_manage)
759 next_manage = cell->dns_expiry;
760 } 797 }
761 798
762 if (sched_cell) 799 if (sched_cell)
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 74ee0f8ef8dd..50d925f0a556 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -367,13 +367,13 @@ struct afs_cell {
367 time64_t last_inactive; /* Time of last drop of usage count */ 367 time64_t last_inactive; /* Time of last drop of usage count */
368 atomic_t usage; 368 atomic_t usage;
369 unsigned long flags; 369 unsigned long flags;
370#define AFS_CELL_FL_NOT_READY 0 /* The cell record is not ready for use */ 370#define AFS_CELL_FL_NO_GC 0 /* The cell was added manually, don't auto-gc */
371#define AFS_CELL_FL_NO_GC 1 /* The cell was added manually, don't auto-gc */ 371#define AFS_CELL_FL_DO_LOOKUP 1 /* DNS lookup requested */
372#define AFS_CELL_FL_NOT_FOUND 2 /* Permanent DNS error */
373#define AFS_CELL_FL_DNS_FAIL 3 /* Failed to access DNS */
374#define AFS_CELL_FL_NO_LOOKUP_YET 4 /* Not completed first DNS lookup yet */
375 enum afs_cell_state state; 372 enum afs_cell_state state;
376 short error; 373 short error;
374 enum dns_record_source dns_source:8; /* Latest source of data from lookup */
375 enum dns_lookup_status dns_status:8; /* Latest status of data from lookup */
376 unsigned int dns_lookup_count; /* Counter of DNS lookups */
377 377
378 /* Active fileserver interaction state. */ 378 /* Active fileserver interaction state. */
379 struct list_head proc_volumes; /* procfs volume list */ 379 struct list_head proc_volumes; /* procfs volume list */
diff --git a/fs/afs/vl_rotate.c b/fs/afs/vl_rotate.c
index 65629d73ad9d..3f845489a9f0 100644
--- a/fs/afs/vl_rotate.c
+++ b/fs/afs/vl_rotate.c
@@ -43,11 +43,29 @@ bool afs_begin_vlserver_operation(struct afs_vl_cursor *vc, struct afs_cell *cel
43static bool afs_start_vl_iteration(struct afs_vl_cursor *vc) 43static bool afs_start_vl_iteration(struct afs_vl_cursor *vc)
44{ 44{
45 struct afs_cell *cell = vc->cell; 45 struct afs_cell *cell = vc->cell;
46 unsigned int dns_lookup_count;
47
48 if (cell->dns_source == DNS_RECORD_UNAVAILABLE ||
49 cell->dns_expiry <= ktime_get_real_seconds()) {
50 dns_lookup_count = smp_load_acquire(&cell->dns_lookup_count);
51 set_bit(AFS_CELL_FL_DO_LOOKUP, &cell->flags);
52 queue_work(afs_wq, &cell->manager);
53
54 if (cell->dns_source == DNS_RECORD_UNAVAILABLE) {
55 if (wait_var_event_interruptible(
56 &cell->dns_lookup_count,
57 smp_load_acquire(&cell->dns_lookup_count)
58 != dns_lookup_count) < 0) {
59 vc->error = -ERESTARTSYS;
60 return false;
61 }
62 }
46 63
47 if (wait_on_bit(&cell->flags, AFS_CELL_FL_NO_LOOKUP_YET, 64 /* Status load is ordered after lookup counter load */
48 TASK_INTERRUPTIBLE)) { 65 if (cell->dns_source == DNS_RECORD_UNAVAILABLE) {
49 vc->error = -ERESTARTSYS; 66 vc->error = -EDESTADDRREQ;
50 return false; 67 return false;
68 }
51 } 69 }
52 70
53 read_lock(&cell->vl_servers_lock); 71 read_lock(&cell->vl_servers_lock);