server.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. /* AFS server record management
  2. *
  3. * Copyright (C) 2002, 2007 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. #include <linux/sched.h>
  12. #include <linux/slab.h>
  13. #include "internal.h"
  14. static unsigned afs_server_timeout = 10; /* server timeout in seconds */
  15. static void afs_reap_server(struct work_struct *);
  16. /* tree of all the servers, indexed by IP address */
  17. static struct rb_root afs_servers = RB_ROOT;
  18. static DEFINE_RWLOCK(afs_servers_lock);
  19. /* LRU list of all the servers not currently in use */
  20. static LIST_HEAD(afs_server_graveyard);
  21. static DEFINE_SPINLOCK(afs_server_graveyard_lock);
  22. static DECLARE_DELAYED_WORK(afs_server_reaper, afs_reap_server);
  23. /*
  24. * install a server record in the master tree
  25. */
  26. static int afs_install_server(struct afs_server *server)
  27. {
  28. struct afs_server *xserver;
  29. struct rb_node **pp, *p;
  30. int ret;
  31. _enter("%p", server);
  32. write_lock(&afs_servers_lock);
  33. ret = -EEXIST;
  34. pp = &afs_servers.rb_node;
  35. p = NULL;
  36. while (*pp) {
  37. p = *pp;
  38. _debug("- consider %p", p);
  39. xserver = rb_entry(p, struct afs_server, master_rb);
  40. if (server->addr.s_addr < xserver->addr.s_addr)
  41. pp = &(*pp)->rb_left;
  42. else if (server->addr.s_addr > xserver->addr.s_addr)
  43. pp = &(*pp)->rb_right;
  44. else
  45. goto error;
  46. }
  47. rb_link_node(&server->master_rb, p, pp);
  48. rb_insert_color(&server->master_rb, &afs_servers);
  49. ret = 0;
  50. error:
  51. write_unlock(&afs_servers_lock);
  52. return ret;
  53. }
  54. /*
  55. * allocate a new server record
  56. */
  57. static struct afs_server *afs_alloc_server(struct afs_cell *cell,
  58. const struct in_addr *addr)
  59. {
  60. struct afs_server *server;
  61. _enter("");
  62. server = kzalloc(sizeof(struct afs_server), GFP_KERNEL);
  63. if (server) {
  64. atomic_set(&server->usage, 1);
  65. server->cell = cell;
  66. INIT_LIST_HEAD(&server->link);
  67. INIT_LIST_HEAD(&server->grave);
  68. init_rwsem(&server->sem);
  69. spin_lock_init(&server->fs_lock);
  70. server->fs_vnodes = RB_ROOT;
  71. server->cb_promises = RB_ROOT;
  72. spin_lock_init(&server->cb_lock);
  73. init_waitqueue_head(&server->cb_break_waitq);
  74. INIT_DELAYED_WORK(&server->cb_break_work,
  75. afs_dispatch_give_up_callbacks);
  76. memcpy(&server->addr, addr, sizeof(struct in_addr));
  77. server->addr.s_addr = addr->s_addr;
  78. }
  79. _leave(" = %p{%d}", server, atomic_read(&server->usage));
  80. return server;
  81. }
  82. /*
  83. * get an FS-server record for a cell
  84. */
  85. struct afs_server *afs_lookup_server(struct afs_cell *cell,
  86. const struct in_addr *addr)
  87. {
  88. struct afs_server *server, *candidate;
  89. _enter("%p,%pI4", cell, &addr->s_addr);
  90. /* quick scan of the list to see if we already have the server */
  91. read_lock(&cell->servers_lock);
  92. list_for_each_entry(server, &cell->servers, link) {
  93. if (server->addr.s_addr == addr->s_addr)
  94. goto found_server_quickly;
  95. }
  96. read_unlock(&cell->servers_lock);
  97. candidate = afs_alloc_server(cell, addr);
  98. if (!candidate) {
  99. _leave(" = -ENOMEM");
  100. return ERR_PTR(-ENOMEM);
  101. }
  102. write_lock(&cell->servers_lock);
  103. /* check the cell's server list again */
  104. list_for_each_entry(server, &cell->servers, link) {
  105. if (server->addr.s_addr == addr->s_addr)
  106. goto found_server;
  107. }
  108. _debug("new");
  109. server = candidate;
  110. if (afs_install_server(server) < 0)
  111. goto server_in_two_cells;
  112. afs_get_cell(cell);
  113. list_add_tail(&server->link, &cell->servers);
  114. write_unlock(&cell->servers_lock);
  115. _leave(" = %p{%d}", server, atomic_read(&server->usage));
  116. return server;
  117. /* found a matching server quickly */
  118. found_server_quickly:
  119. _debug("found quickly");
  120. afs_get_server(server);
  121. read_unlock(&cell->servers_lock);
  122. no_longer_unused:
  123. if (!list_empty(&server->grave)) {
  124. spin_lock(&afs_server_graveyard_lock);
  125. list_del_init(&server->grave);
  126. spin_unlock(&afs_server_graveyard_lock);
  127. }
  128. _leave(" = %p{%d}", server, atomic_read(&server->usage));
  129. return server;
  130. /* found a matching server on the second pass */
  131. found_server:
  132. _debug("found");
  133. afs_get_server(server);
  134. write_unlock(&cell->servers_lock);
  135. kfree(candidate);
  136. goto no_longer_unused;
  137. /* found a server that seems to be in two cells */
  138. server_in_two_cells:
  139. write_unlock(&cell->servers_lock);
  140. kfree(candidate);
  141. printk(KERN_NOTICE "kAFS: Server %pI4 appears to be in two cells\n",
  142. addr);
  143. _leave(" = -EEXIST");
  144. return ERR_PTR(-EEXIST);
  145. }
  146. /*
  147. * look up a server by its IP address
  148. */
  149. struct afs_server *afs_find_server(const struct in_addr *_addr)
  150. {
  151. struct afs_server *server = NULL;
  152. struct rb_node *p;
  153. struct in_addr addr = *_addr;
  154. _enter("%pI4", &addr.s_addr);
  155. read_lock(&afs_servers_lock);
  156. p = afs_servers.rb_node;
  157. while (p) {
  158. server = rb_entry(p, struct afs_server, master_rb);
  159. _debug("- consider %p", p);
  160. if (addr.s_addr < server->addr.s_addr) {
  161. p = p->rb_left;
  162. } else if (addr.s_addr > server->addr.s_addr) {
  163. p = p->rb_right;
  164. } else {
  165. afs_get_server(server);
  166. goto found;
  167. }
  168. }
  169. server = NULL;
  170. found:
  171. read_unlock(&afs_servers_lock);
  172. ASSERTIFCMP(server, server->addr.s_addr, ==, addr.s_addr);
  173. _leave(" = %p", server);
  174. return server;
  175. }
  176. /*
  177. * destroy a server record
  178. * - removes from the cell list
  179. */
  180. void afs_put_server(struct afs_server *server)
  181. {
  182. if (!server)
  183. return;
  184. _enter("%p{%d}", server, atomic_read(&server->usage));
  185. _debug("PUT SERVER %d", atomic_read(&server->usage));
  186. ASSERTCMP(atomic_read(&server->usage), >, 0);
  187. if (likely(!atomic_dec_and_test(&server->usage))) {
  188. _leave("");
  189. return;
  190. }
  191. afs_flush_callback_breaks(server);
  192. spin_lock(&afs_server_graveyard_lock);
  193. if (atomic_read(&server->usage) == 0) {
  194. list_move_tail(&server->grave, &afs_server_graveyard);
  195. server->time_of_death = get_seconds();
  196. schedule_delayed_work(&afs_server_reaper,
  197. afs_server_timeout * HZ);
  198. }
  199. spin_unlock(&afs_server_graveyard_lock);
  200. _leave(" [dead]");
  201. }
  202. /*
  203. * destroy a dead server
  204. */
  205. static void afs_destroy_server(struct afs_server *server)
  206. {
  207. _enter("%p", server);
  208. ASSERTIF(server->cb_break_head != server->cb_break_tail,
  209. delayed_work_pending(&server->cb_break_work));
  210. ASSERTCMP(server->fs_vnodes.rb_node, ==, NULL);
  211. ASSERTCMP(server->cb_promises.rb_node, ==, NULL);
  212. ASSERTCMP(server->cb_break_head, ==, server->cb_break_tail);
  213. ASSERTCMP(atomic_read(&server->cb_break_n), ==, 0);
  214. afs_put_cell(server->cell);
  215. kfree(server);
  216. }
  217. /*
  218. * reap dead server records
  219. */
  220. static void afs_reap_server(struct work_struct *work)
  221. {
  222. LIST_HEAD(corpses);
  223. struct afs_server *server;
  224. unsigned long delay, expiry;
  225. time_t now;
  226. now = get_seconds();
  227. spin_lock(&afs_server_graveyard_lock);
  228. while (!list_empty(&afs_server_graveyard)) {
  229. server = list_entry(afs_server_graveyard.next,
  230. struct afs_server, grave);
  231. /* the queue is ordered most dead first */
  232. expiry = server->time_of_death + afs_server_timeout;
  233. if (expiry > now) {
  234. delay = (expiry - now) * HZ;
  235. if (!schedule_delayed_work(&afs_server_reaper, delay)) {
  236. cancel_delayed_work(&afs_server_reaper);
  237. schedule_delayed_work(&afs_server_reaper,
  238. delay);
  239. }
  240. break;
  241. }
  242. write_lock(&server->cell->servers_lock);
  243. write_lock(&afs_servers_lock);
  244. if (atomic_read(&server->usage) > 0) {
  245. list_del_init(&server->grave);
  246. } else {
  247. list_move_tail(&server->grave, &corpses);
  248. list_del_init(&server->link);
  249. rb_erase(&server->master_rb, &afs_servers);
  250. }
  251. write_unlock(&afs_servers_lock);
  252. write_unlock(&server->cell->servers_lock);
  253. }
  254. spin_unlock(&afs_server_graveyard_lock);
  255. /* now reap the corpses we've extracted */
  256. while (!list_empty(&corpses)) {
  257. server = list_entry(corpses.next, struct afs_server, grave);
  258. list_del(&server->grave);
  259. afs_destroy_server(server);
  260. }
  261. }
  262. /*
  263. * discard all the server records for rmmod
  264. */
  265. void __exit afs_purge_servers(void)
  266. {
  267. afs_server_timeout = 0;
  268. cancel_delayed_work(&afs_server_reaper);
  269. schedule_delayed_work(&afs_server_reaper, 0);
  270. }