~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/afs/cell.c

Version: ~ [ linux-5.7-rc7 ] ~ [ linux-5.6.14 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.42 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.124 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.181 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.224 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.224 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.84 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /* AFS cell and server record management
  2  *
  3  * Copyright (C) 2002, 2017 Red Hat, Inc. All Rights Reserved.
  4  * Written by David Howells (dhowells@redhat.com)
  5  *
  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.
 10  */
 11 
 12 #include <linux/slab.h>
 13 #include <linux/key.h>
 14 #include <linux/ctype.h>
 15 #include <linux/dns_resolver.h>
 16 #include <linux/sched.h>
 17 #include <linux/inet.h>
 18 #include <linux/namei.h>
 19 #include <keys/rxrpc-type.h>
 20 #include "internal.h"
 21 
 22 static unsigned __read_mostly afs_cell_gc_delay = 10;
 23 static unsigned __read_mostly afs_cell_min_ttl = 10 * 60;
 24 static unsigned __read_mostly afs_cell_max_ttl = 24 * 60 * 60;
 25 
 26 static void afs_manage_cell(struct work_struct *);
 27 
 28 static void afs_dec_cells_outstanding(struct afs_net *net)
 29 {
 30         if (atomic_dec_and_test(&net->cells_outstanding))
 31                 wake_up_var(&net->cells_outstanding);
 32 }
 33 
 34 /*
 35  * Set the cell timer to fire after a given delay, assuming it's not already
 36  * set for an earlier time.
 37  */
 38 static void afs_set_cell_timer(struct afs_net *net, time64_t delay)
 39 {
 40         if (net->live) {
 41                 atomic_inc(&net->cells_outstanding);
 42                 if (timer_reduce(&net->cells_timer, jiffies + delay * HZ))
 43                         afs_dec_cells_outstanding(net);
 44         }
 45 }
 46 
 47 /*
 48  * Look up and get an activation reference on a cell record under RCU
 49  * conditions.  The caller must hold the RCU read lock.
 50  */
 51 struct afs_cell *afs_lookup_cell_rcu(struct afs_net *net,
 52                                      const char *name, unsigned int namesz)
 53 {
 54         struct afs_cell *cell = NULL;
 55         struct rb_node *p;
 56         int n, seq = 0, ret = 0;
 57 
 58         _enter("%*.*s", namesz, namesz, name);
 59 
 60         if (name && namesz == 0)
 61                 return ERR_PTR(-EINVAL);
 62         if (namesz > AFS_MAXCELLNAME)
 63                 return ERR_PTR(-ENAMETOOLONG);
 64 
 65         do {
 66                 /* Unfortunately, rbtree walking doesn't give reliable results
 67                  * under just the RCU read lock, so we have to check for
 68                  * changes.
 69                  */
 70                 if (cell)
 71                         afs_put_cell(net, cell);
 72                 cell = NULL;
 73                 ret = -ENOENT;
 74 
 75                 read_seqbegin_or_lock(&net->cells_lock, &seq);
 76 
 77                 if (!name) {
 78                         cell = rcu_dereference_raw(net->ws_cell);
 79                         if (cell) {
 80                                 afs_get_cell(cell);
 81                                 break;
 82                         }
 83                         ret = -EDESTADDRREQ;
 84                         continue;
 85                 }
 86 
 87                 p = rcu_dereference_raw(net->cells.rb_node);
 88                 while (p) {
 89                         cell = rb_entry(p, struct afs_cell, net_node);
 90 
 91                         n = strncasecmp(cell->name, name,
 92                                         min_t(size_t, cell->name_len, namesz));
 93                         if (n == 0)
 94                                 n = cell->name_len - namesz;
 95                         if (n < 0) {
 96                                 p = rcu_dereference_raw(p->rb_left);
 97                         } else if (n > 0) {
 98                                 p = rcu_dereference_raw(p->rb_right);
 99                         } else {
100                                 if (atomic_inc_not_zero(&cell->usage)) {
101                                         ret = 0;
102                                         break;
103                                 }
104                                 /* We want to repeat the search, this time with
105                                  * the lock properly locked.
106                                  */
107                         }
108                         cell = NULL;
109                 }
110 
111         } while (need_seqretry(&net->cells_lock, seq));
112 
113         done_seqretry(&net->cells_lock, seq);
114 
115         return ret == 0 ? cell : ERR_PTR(ret);
116 }
117 
118 /*
119  * Set up a cell record and fill in its name, VL server address list and
120  * allocate an anonymous key
121  */
122 static struct afs_cell *afs_alloc_cell(struct afs_net *net,
123                                        const char *name, unsigned int namelen,
124                                        const char *addresses)
125 {
126         struct afs_cell *cell;
127         int i, ret;
128 
129         ASSERT(name);
130         if (namelen == 0)
131                 return ERR_PTR(-EINVAL);
132         if (namelen > AFS_MAXCELLNAME) {
133                 _leave(" = -ENAMETOOLONG");
134                 return ERR_PTR(-ENAMETOOLONG);
135         }
136         if (namelen == 5 && memcmp(name, "@cell", 5) == 0)
137                 return ERR_PTR(-EINVAL);
138 
139         _enter("%*.*s,%s", namelen, namelen, name, addresses);
140 
141         cell = kzalloc(sizeof(struct afs_cell), GFP_KERNEL);
142         if (!cell) {
143                 _leave(" = -ENOMEM");
144                 return ERR_PTR(-ENOMEM);
145         }
146 
147         cell->net = net;
148         cell->name_len = namelen;
149         for (i = 0; i < namelen; i++)
150                 cell->name[i] = tolower(name[i]);
151 
152         atomic_set(&cell->usage, 2);
153         INIT_WORK(&cell->manager, afs_manage_cell);
154         cell->flags = ((1 << AFS_CELL_FL_NOT_READY) |
155                        (1 << AFS_CELL_FL_NO_LOOKUP_YET));
156         INIT_LIST_HEAD(&cell->proc_volumes);
157         rwlock_init(&cell->proc_lock);
158         rwlock_init(&cell->vl_servers_lock);
159 
160         /* Fill in the VL server list if we were given a list of addresses to
161          * use.
162          */
163         if (addresses) {
164                 struct afs_vlserver_list *vllist;
165 
166                 vllist = afs_parse_text_addrs(net,
167                                               addresses, strlen(addresses), ':',
168                                               VL_SERVICE, AFS_VL_PORT);
169                 if (IS_ERR(vllist)) {
170                         ret = PTR_ERR(vllist);
171                         goto parse_failed;
172                 }
173 
174                 rcu_assign_pointer(cell->vl_servers, vllist);
175                 cell->dns_expiry = TIME64_MAX;
176                 __clear_bit(AFS_CELL_FL_NO_LOOKUP_YET, &cell->flags);
177         } else {
178                 cell->dns_expiry = ktime_get_real_seconds();
179         }
180 
181         _leave(" = %p", cell);
182         return cell;
183 
184 parse_failed:
185         if (ret == -EINVAL)
186                 printk(KERN_ERR "kAFS: bad VL server IP address\n");
187         kfree(cell);
188         _leave(" = %d", ret);
189         return ERR_PTR(ret);
190 }
191 
192 /*
193  * afs_lookup_cell - Look up or create a cell record.
194  * @net:        The network namespace
195  * @name:       The name of the cell.
196  * @namesz:     The strlen of the cell name.
197  * @vllist:     A colon/comma separated list of numeric IP addresses or NULL.
198  * @excl:       T if an error should be given if the cell name already exists.
199  *
200  * Look up a cell record by name and query the DNS for VL server addresses if
201  * needed.  Note that that actual DNS query is punted off to the manager thread
202  * so that this function can return immediately if interrupted whilst allowing
203  * cell records to be shared even if not yet fully constructed.
204  */
205 struct afs_cell *afs_lookup_cell(struct afs_net *net,
206                                  const char *name, unsigned int namesz,
207                                  const char *vllist, bool excl)
208 {
209         struct afs_cell *cell, *candidate, *cursor;
210         struct rb_node *parent, **pp;
211         int ret, n;
212 
213         _enter("%s,%s", name, vllist);
214 
215         if (!excl) {
216                 rcu_read_lock();
217                 cell = afs_lookup_cell_rcu(net, name, namesz);
218                 rcu_read_unlock();
219                 if (!IS_ERR(cell))
220                         goto wait_for_cell;
221         }
222 
223         /* Assume we're probably going to create a cell and preallocate and
224          * mostly set up a candidate record.  We can then use this to stash the
225          * name, the net namespace and VL server addresses.
226          *
227          * We also want to do this before we hold any locks as it may involve
228          * upcalling to userspace to make DNS queries.
229          */
230         candidate = afs_alloc_cell(net, name, namesz, vllist);
231         if (IS_ERR(candidate)) {
232                 _leave(" = %ld", PTR_ERR(candidate));
233                 return candidate;
234         }
235 
236         /* Find the insertion point and check to see if someone else added a
237          * cell whilst we were allocating.
238          */
239         write_seqlock(&net->cells_lock);
240 
241         pp = &net->cells.rb_node;
242         parent = NULL;
243         while (*pp) {
244                 parent = *pp;
245                 cursor = rb_entry(parent, struct afs_cell, net_node);
246 
247                 n = strncasecmp(cursor->name, name,
248                                 min_t(size_t, cursor->name_len, namesz));
249                 if (n == 0)
250                         n = cursor->name_len - namesz;
251                 if (n < 0)
252                         pp = &(*pp)->rb_left;
253                 else if (n > 0)
254                         pp = &(*pp)->rb_right;
255                 else
256                         goto cell_already_exists;
257         }
258 
259         cell = candidate;
260         candidate = NULL;
261         rb_link_node_rcu(&cell->net_node, parent, pp);
262         rb_insert_color(&cell->net_node, &net->cells);
263         atomic_inc(&net->cells_outstanding);
264         write_sequnlock(&net->cells_lock);
265 
266         queue_work(afs_wq, &cell->manager);
267 
268 wait_for_cell:
269         _debug("wait_for_cell");
270         ret = wait_on_bit(&cell->flags, AFS_CELL_FL_NOT_READY, TASK_INTERRUPTIBLE);
271         smp_rmb();
272 
273         switch (READ_ONCE(cell->state)) {
274         case AFS_CELL_FAILED:
275                 ret = cell->error;
276                 goto error;
277         default:
278                 _debug("weird %u %d", cell->state, cell->error);
279                 goto error;
280         case AFS_CELL_ACTIVE:
281                 break;
282         }
283 
284         _leave(" = %p [cell]", cell);
285         return cell;
286 
287 cell_already_exists:
288         _debug("cell exists");
289         cell = cursor;
290         if (excl) {
291                 ret = -EEXIST;
292         } else {
293                 afs_get_cell(cursor);
294                 ret = 0;
295         }
296         write_sequnlock(&net->cells_lock);
297         kfree(candidate);
298         if (ret == 0)
299                 goto wait_for_cell;
300         goto error_noput;
301 error:
302         afs_put_cell(net, cell);
303 error_noput:
304         _leave(" = %d [error]", ret);
305         return ERR_PTR(ret);
306 }
307 
308 /*
309  * set the root cell information
310  * - can be called with a module parameter string
311  * - can be called from a write to /proc/fs/afs/rootcell
312  */
313 int afs_cell_init(struct afs_net *net, const char *rootcell)
314 {
315         struct afs_cell *old_root, *new_root;
316         const char *cp, *vllist;
317         size_t len;
318 
319         _enter("");
320 
321         if (!rootcell) {
322                 /* module is loaded with no parameters, or built statically.
323                  * - in the future we might initialize cell DB here.
324                  */
325                 _leave(" = 0 [no root]");
326                 return 0;
327         }
328 
329         cp = strchr(rootcell, ':');
330         if (!cp) {
331                 _debug("kAFS: no VL server IP addresses specified");
332                 vllist = NULL;
333                 len = strlen(rootcell);
334         } else {
335                 vllist = cp + 1;
336                 len = cp - rootcell;
337         }
338 
339         /* allocate a cell record for the root cell */
340         new_root = afs_lookup_cell(net, rootcell, len, vllist, false);
341         if (IS_ERR(new_root)) {
342                 _leave(" = %ld", PTR_ERR(new_root));
343                 return PTR_ERR(new_root);
344         }
345 
346         if (!test_and_set_bit(AFS_CELL_FL_NO_GC, &new_root->flags))
347                 afs_get_cell(new_root);
348 
349         /* install the new cell */
350         write_seqlock(&net->cells_lock);
351         old_root = rcu_access_pointer(net->ws_cell);
352         rcu_assign_pointer(net->ws_cell, new_root);
353         write_sequnlock(&net->cells_lock);
354 
355         afs_put_cell(net, old_root);
356         _leave(" = 0");
357         return 0;
358 }
359 
360 /*
361  * Update a cell's VL server address list from the DNS.
362  */
363 static void afs_update_cell(struct afs_cell *cell)
364 {
365         struct afs_vlserver_list *vllist, *old;
366         unsigned int min_ttl = READ_ONCE(afs_cell_min_ttl);
367         unsigned int max_ttl = READ_ONCE(afs_cell_max_ttl);
368         time64_t now, expiry = 0;
369 
370         _enter("%s", cell->name);
371 
372         vllist = afs_dns_query(cell, &expiry);
373 
374         now = ktime_get_real_seconds();
375         if (min_ttl > max_ttl)
376                 max_ttl = min_ttl;
377         if (expiry < now + min_ttl)
378                 expiry = now + min_ttl;
379         else if (expiry > now + max_ttl)
380                 expiry = now + max_ttl;
381 
382         if (IS_ERR(vllist)) {
383                 switch (PTR_ERR(vllist)) {
384                 case -ENODATA:
385                 case -EDESTADDRREQ:
386                         /* The DNS said that the cell does not exist or there
387                          * weren't any addresses to be had.
388                          */
389                         set_bit(AFS_CELL_FL_NOT_FOUND, &cell->flags);
390                         clear_bit(AFS_CELL_FL_DNS_FAIL, &cell->flags);
391                         cell->dns_expiry = expiry;
392                         break;
393 
394                 case -EAGAIN:
395                 case -ECONNREFUSED:
396                 default:
397                         set_bit(AFS_CELL_FL_DNS_FAIL, &cell->flags);
398                         cell->dns_expiry = now + 10;
399                         break;
400                 }
401 
402                 cell->error = -EDESTADDRREQ;
403         } else {
404                 clear_bit(AFS_CELL_FL_DNS_FAIL, &cell->flags);
405                 clear_bit(AFS_CELL_FL_NOT_FOUND, &cell->flags);
406 
407                 /* Exclusion on changing vl_addrs is achieved by a
408                  * non-reentrant work item.
409                  */
410                 old = rcu_dereference_protected(cell->vl_servers, true);
411                 rcu_assign_pointer(cell->vl_servers, vllist);
412                 cell->dns_expiry = expiry;
413 
414                 if (old)
415                         afs_put_vlserverlist(cell->net, old);
416         }
417 
418         if (test_and_clear_bit(AFS_CELL_FL_NO_LOOKUP_YET, &cell->flags))
419                 wake_up_bit(&cell->flags, AFS_CELL_FL_NO_LOOKUP_YET);
420 
421         now = ktime_get_real_seconds();
422         afs_set_cell_timer(cell->net, cell->dns_expiry - now);
423         _leave("");
424 }
425 
426 /*
427  * Destroy a cell record
428  */
429 static void afs_cell_destroy(struct rcu_head *rcu)
430 {
431         struct afs_cell *cell = container_of(rcu, struct afs_cell, rcu);
432 
433         _enter("%p{%s}", cell, cell->name);
434 
435         ASSERTCMP(atomic_read(&cell->usage), ==, 0);
436 
437         afs_put_vlserverlist(cell->net, rcu_access_pointer(cell->vl_servers));
438         key_put(cell->anonymous_key);
439         kfree(cell);
440 
441         _leave(" [destroyed]");
442 }
443 
444 /*
445  * Queue the cell manager.
446  */
447 static void afs_queue_cell_manager(struct afs_net *net)
448 {
449         int outstanding = atomic_inc_return(&net->cells_outstanding);
450 
451         _enter("%d", outstanding);
452 
453         if (!queue_work(afs_wq, &net->cells_manager))
454                 afs_dec_cells_outstanding(net);
455 }
456 
457 /*
458  * Cell management timer.  We have an increment on cells_outstanding that we
459  * need to pass along to the work item.
460  */
461 void afs_cells_timer(struct timer_list *timer)
462 {
463         struct afs_net *net = container_of(timer, struct afs_net, cells_timer);
464 
465         _enter("");
466         if (!queue_work(afs_wq, &net->cells_manager))
467                 afs_dec_cells_outstanding(net);
468 }
469 
470 /*
471  * Get a reference on a cell record.
472  */
473 struct afs_cell *afs_get_cell(struct afs_cell *cell)
474 {
475         atomic_inc(&cell->usage);
476         return cell;
477 }
478 
479 /*
480  * Drop a reference on a cell record.
481  */
482 void afs_put_cell(struct afs_net *net, struct afs_cell *cell)
483 {
484         time64_t now, expire_delay;
485 
486         if (!cell)
487                 return;
488 
489         _enter("%s", cell->name);
490 
491         now = ktime_get_real_seconds();
492         cell->last_inactive = now;
493         expire_delay = 0;
494         if (!test_bit(AFS_CELL_FL_DNS_FAIL, &cell->flags) &&
495             !test_bit(AFS_CELL_FL_NOT_FOUND, &cell->flags))
496                 expire_delay = afs_cell_gc_delay;
497 
498         if (atomic_dec_return(&cell->usage) > 1)
499                 return;
500 
501         /* 'cell' may now be garbage collected. */
502         afs_set_cell_timer(net, expire_delay);
503 }
504 
505 /*
506  * Allocate a key to use as a placeholder for anonymous user security.
507  */
508 static int afs_alloc_anon_key(struct afs_cell *cell)
509 {
510         struct key *key;
511         char keyname[4 + AFS_MAXCELLNAME + 1], *cp, *dp;
512 
513         /* Create a key to represent an anonymous user. */
514         memcpy(keyname, "afs@", 4);
515         dp = keyname + 4;
516         cp = cell->name;
517         do {
518                 *dp++ = tolower(*cp);
519         } while (*cp++);
520 
521         key = rxrpc_get_null_key(keyname);
522         if (IS_ERR(key))
523                 return PTR_ERR(key);
524 
525         cell->anonymous_key = key;
526 
527         _debug("anon key %p{%x}",
528                cell->anonymous_key, key_serial(cell->anonymous_key));
529         return 0;
530 }
531 
532 /*
533  * Activate a cell.
534  */
535 static int afs_activate_cell(struct afs_net *net, struct afs_cell *cell)
536 {
537         struct hlist_node **p;
538         struct afs_cell *pcell;
539         int ret;
540 
541         if (!cell->anonymous_key) {
542                 ret = afs_alloc_anon_key(cell);
543                 if (ret < 0)
544                         return ret;
545         }
546 
547 #ifdef CONFIG_AFS_FSCACHE
548         cell->cache = fscache_acquire_cookie(afs_cache_netfs.primary_index,
549                                              &afs_cell_cache_index_def,
550                                              cell->name, strlen(cell->name),
551                                              NULL, 0,
552                                              cell, 0, true);
553 #endif
554         ret = afs_proc_cell_setup(cell);
555         if (ret < 0)
556                 return ret;
557 
558         mutex_lock(&net->proc_cells_lock);
559         for (p = &net->proc_cells.first; *p; p = &(*p)->next) {
560                 pcell = hlist_entry(*p, struct afs_cell, proc_link);
561                 if (strcmp(cell->name, pcell->name) < 0)
562                         break;
563         }
564 
565         cell->proc_link.pprev = p;
566         cell->proc_link.next = *p;
567         rcu_assign_pointer(*p, &cell->proc_link.next);
568         if (cell->proc_link.next)
569                 cell->proc_link.next->pprev = &cell->proc_link.next;
570 
571         afs_dynroot_mkdir(net, cell);
572         mutex_unlock(&net->proc_cells_lock);
573         return 0;
574 }
575 
576 /*
577  * Deactivate a cell.
578  */
579 static void afs_deactivate_cell(struct afs_net *net, struct afs_cell *cell)
580 {
581         _enter("%s", cell->name);
582 
583         afs_proc_cell_remove(cell);
584 
585         mutex_lock(&net->proc_cells_lock);
586         hlist_del_rcu(&cell->proc_link);
587         afs_dynroot_rmdir(net, cell);
588         mutex_unlock(&net->proc_cells_lock);
589 
590 #ifdef CONFIG_AFS_FSCACHE
591         fscache_relinquish_cookie(cell->cache, NULL, false);
592         cell->cache = NULL;
593 #endif
594 
595         _leave("");
596 }
597 
598 /*
599  * Manage a cell record, initialising and destroying it, maintaining its DNS
600  * records.
601  */
602 static void afs_manage_cell(struct work_struct *work)
603 {
604         struct afs_cell *cell = container_of(work, struct afs_cell, manager);
605         struct afs_net *net = cell->net;
606         bool deleted;
607         int ret, usage;
608 
609         _enter("%s", cell->name);
610 
611 again:
612         _debug("state %u", cell->state);
613         switch (cell->state) {
614         case AFS_CELL_INACTIVE:
615         case AFS_CELL_FAILED:
616                 write_seqlock(&net->cells_lock);
617                 usage = 1;
618                 deleted = atomic_try_cmpxchg_relaxed(&cell->usage, &usage, 0);
619                 if (deleted)
620                         rb_erase(&cell->net_node, &net->cells);
621                 write_sequnlock(&net->cells_lock);
622                 if (deleted)
623                         goto final_destruction;
624                 if (cell->state == AFS_CELL_FAILED)
625                         goto done;
626                 cell->state = AFS_CELL_UNSET;
627                 goto again;
628 
629         case AFS_CELL_UNSET:
630                 cell->state = AFS_CELL_ACTIVATING;
631                 goto again;
632 
633         case AFS_CELL_ACTIVATING:
634                 ret = afs_activate_cell(net, cell);
635                 if (ret < 0)
636                         goto activation_failed;
637 
638                 cell->state = AFS_CELL_ACTIVE;
639                 smp_wmb();
640                 clear_bit(AFS_CELL_FL_NOT_READY, &cell->flags);
641                 wake_up_bit(&cell->flags, AFS_CELL_FL_NOT_READY);
642                 goto again;
643 
644         case AFS_CELL_ACTIVE:
645                 if (atomic_read(&cell->usage) > 1) {
646                         time64_t now = ktime_get_real_seconds();
647                         if (cell->dns_expiry <= now && net->live)
648                                 afs_update_cell(cell);
649                         goto done;
650                 }
651                 cell->state = AFS_CELL_DEACTIVATING;
652                 goto again;
653 
654         case AFS_CELL_DEACTIVATING:
655                 set_bit(AFS_CELL_FL_NOT_READY, &cell->flags);
656                 if (atomic_read(&cell->usage) > 1)
657                         goto reverse_deactivation;
658                 afs_deactivate_cell(net, cell);
659                 cell->state = AFS_CELL_INACTIVE;
660                 goto again;
661 
662         default:
663                 break;
664         }
665         _debug("bad state %u", cell->state);
666         BUG(); /* Unhandled state */
667 
668 activation_failed:
669         cell->error = ret;
670         afs_deactivate_cell(net, cell);
671 
672         cell->state = AFS_CELL_FAILED;
673         smp_wmb();
674         if (test_and_clear_bit(AFS_CELL_FL_NOT_READY, &cell->flags))
675                 wake_up_bit(&cell->flags, AFS_CELL_FL_NOT_READY);
676         goto again;
677 
678 reverse_deactivation:
679         cell->state = AFS_CELL_ACTIVE;
680         smp_wmb();
681         clear_bit(AFS_CELL_FL_NOT_READY, &cell->flags);
682         wake_up_bit(&cell->flags, AFS_CELL_FL_NOT_READY);
683         _leave(" [deact->act]");
684         return;
685 
686 done:
687         _leave(" [done %u]", cell->state);
688         return;
689 
690 final_destruction:
691         call_rcu(&cell->rcu, afs_cell_destroy);
692         afs_dec_cells_outstanding(net);
693         _leave(" [destruct %d]", atomic_read(&net->cells_outstanding));
694 }
695 
696 /*
697  * Manage the records of cells known to a network namespace.  This includes
698  * updating the DNS records and garbage collecting unused cells that were
699  * automatically added.
700  *
701  * Note that constructed cell records may only be removed from net->cells by
702  * this work item, so it is safe for this work item to stash a cursor pointing
703  * into the tree and then return to caller (provided it skips cells that are
704  * still under construction).
705  *
706  * Note also that we were given an increment on net->cells_outstanding by
707  * whoever queued us that we need to deal with before returning.
708  */
709 void afs_manage_cells(struct work_struct *work)
710 {
711         struct afs_net *net = container_of(work, struct afs_net, cells_manager);
712         struct rb_node *cursor;
713         time64_t now = ktime_get_real_seconds(), next_manage = TIME64_MAX;
714         bool purging = !net->live;
715 
716         _enter("");
717 
718         /* Trawl the cell database looking for cells that have expired from
719          * lack of use and cells whose DNS results have expired and dispatch
720          * their managers.
721          */
722         read_seqlock_excl(&net->cells_lock);
723 
724         for (cursor = rb_first(&net->cells); cursor; cursor = rb_next(cursor)) {
725                 struct afs_cell *cell =
726                         rb_entry(cursor, struct afs_cell, net_node);
727                 unsigned usage;
728                 bool sched_cell = false;
729 
730                 usage = atomic_read(&cell->usage);
731                 _debug("manage %s %u", cell->name, usage);
732 
733                 ASSERTCMP(usage, >=, 1);
734 
735                 if (purging) {
736                         if (test_and_clear_bit(AFS_CELL_FL_NO_GC, &cell->flags))
737                                 usage = atomic_dec_return(&cell->usage);
738                         ASSERTCMP(usage, ==, 1);
739                 }
740 
741                 if (usage == 1) {
742                         time64_t expire_at = cell->last_inactive;
743 
744                         if (!test_bit(AFS_CELL_FL_DNS_FAIL, &cell->flags) &&
745                             !test_bit(AFS_CELL_FL_NOT_FOUND, &cell->flags))
746                                 expire_at += afs_cell_gc_delay;
747                         if (purging || expire_at <= now)
748                                 sched_cell = true;
749                         else if (expire_at < next_manage)
750                                 next_manage = expire_at;
751                 }
752 
753                 if (!purging) {
754                         if (cell->dns_expiry <= now)
755                                 sched_cell = true;
756                         else if (cell->dns_expiry <= next_manage)
757                                 next_manage = cell->dns_expiry;
758                 }
759 
760                 if (sched_cell)
761                         queue_work(afs_wq, &cell->manager);
762         }
763 
764         read_sequnlock_excl(&net->cells_lock);
765 
766         /* Update the timer on the way out.  We have to pass an increment on
767          * cells_outstanding in the namespace that we are in to the timer or
768          * the work scheduler.
769          */
770         if (!purging && next_manage < TIME64_MAX) {
771                 now = ktime_get_real_seconds();
772 
773                 if (next_manage - now <= 0) {
774                         if (queue_work(afs_wq, &net->cells_manager))
775                                 atomic_inc(&net->cells_outstanding);
776                 } else {
777                         afs_set_cell_timer(net, next_manage - now);
778                 }
779         }
780 
781         afs_dec_cells_outstanding(net);
782         _leave(" [%d]", atomic_read(&net->cells_outstanding));
783 }
784 
785 /*
786  * Purge in-memory cell database.
787  */
788 void afs_cell_purge(struct afs_net *net)
789 {
790         struct afs_cell *ws;
791 
792         _enter("");
793 
794         write_seqlock(&net->cells_lock);
795         ws = rcu_access_pointer(net->ws_cell);
796         RCU_INIT_POINTER(net->ws_cell, NULL);
797         write_sequnlock(&net->cells_lock);
798         afs_put_cell(net, ws);
799 
800         _debug("del timer");
801         if (del_timer_sync(&net->cells_timer))
802                 atomic_dec(&net->cells_outstanding);
803 
804         _debug("kick mgr");
805         afs_queue_cell_manager(net);
806 
807         _debug("wait");
808         wait_var_event(&net->cells_outstanding,
809                        !atomic_read(&net->cells_outstanding));
810         _leave("");
811 }
812 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp