server.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  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,"NIPQUAD_FMT, cell, NIPQUAD(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:"
  142. " Server "NIPQUAD_FMT" appears to be in two cells\n",
  143. NIPQUAD(*addr));
  144. _leave(" = -EEXIST");
  145. return ERR_PTR(-EEXIST);
  146. }
  147. /*
  148. * look up a server by its IP address
  149. */
  150. struct afs_server *afs_find_server(const struct in_addr *_addr)
  151. {
  152. struct afs_server *server = NULL;
  153. struct rb_node *p;
  154. struct in_addr addr = *_addr;
  155. _enter(NIPQUAD_FMT, NIPQUAD(addr.s_addr));
  156. read_lock(&afs_servers_lock);
  157. p = afs_servers.rb_node;
  158. while (p) {
  159. server = rb_entry(p, struct afs_server, master_rb);
  160. _debug("- consider %p", p);
  161. if (addr.s_addr < server->addr.s_addr) {
  162. p = p->rb_left;
  163. } else if (addr.s_addr > server->addr.s_addr) {
  164. p = p->rb_right;
  165. } else {
  166. afs_get_server(server);
  167. goto found;
  168. }
  169. }
  170. server = NULL;
  171. found:
  172. read_unlock(&afs_servers_lock);
  173. ASSERTIFCMP(server, server->addr.s_addr, ==, addr.s_addr);
  174. _leave(" = %p", server);
  175. return server;
  176. }
  177. /*
  178. * destroy a server record
  179. * - removes from the cell list
  180. */
  181. void afs_put_server(struct afs_server *server)
  182. {
  183. if (!server)
  184. return;
  185. _enter("%p{%d}", server, atomic_read(&server->usage));
  186. _debug("PUT SERVER %d", atomic_read(&server->usage));
  187. ASSERTCMP(atomic_read(&server->usage), >, 0);
  188. if (likely(!atomic_dec_and_test(&server->usage))) {
  189. _leave("");
  190. return;
  191. }
  192. afs_flush_callback_breaks(server);
  193. spin_lock(&afs_server_graveyard_lock);
  194. if (atomic_read(&server->usage) == 0) {
  195. list_move_tail(&server->grave, &afs_server_graveyard);
  196. server->time_of_death = get_seconds();
  197. schedule_delayed_work(&afs_server_reaper,
  198. afs_server_timeout * HZ);
  199. }
  200. spin_unlock(&afs_server_graveyard_lock);
  201. _leave(" [dead]");
  202. }
  203. /*
  204. * destroy a dead server
  205. */
  206. static void afs_destroy_server(struct afs_server *server)
  207. {
  208. _enter("%p", server);
  209. ASSERTIF(server->cb_break_head != server->cb_break_tail,
  210. delayed_work_pending(&server->cb_break_work));
  211. ASSERTCMP(server->fs_vnodes.rb_node, ==, NULL);
  212. ASSERTCMP(server->cb_promises.rb_node, ==, NULL);
  213. ASSERTCMP(server->cb_break_head, ==, server->cb_break_tail);
  214. ASSERTCMP(atomic_read(&server->cb_break_n), ==, 0);
  215. afs_put_cell(server->cell);
  216. kfree(server);
  217. }
  218. /*
  219. * reap dead server records
  220. */
  221. static void afs_reap_server(struct work_struct *work)
  222. {
  223. LIST_HEAD(corpses);
  224. struct afs_server *server;
  225. unsigned long delay, expiry;
  226. time_t now;
  227. now = get_seconds();
  228. spin_lock(&afs_server_graveyard_lock);
  229. while (!list_empty(&afs_server_graveyard)) {
  230. server = list_entry(afs_server_graveyard.next,
  231. struct afs_server, grave);
  232. /* the queue is ordered most dead first */
  233. expiry = server->time_of_death + afs_server_timeout;
  234. if (expiry > now) {
  235. delay = (expiry - now) * HZ;
  236. if (!schedule_delayed_work(&afs_server_reaper, delay)) {
  237. cancel_delayed_work(&afs_server_reaper);
  238. schedule_delayed_work(&afs_server_reaper,
  239. delay);
  240. }
  241. break;
  242. }
  243. write_lock(&server->cell->servers_lock);
  244. write_lock(&afs_servers_lock);
  245. if (atomic_read(&server->usage) > 0) {
  246. list_del_init(&server->grave);
  247. } else {
  248. list_move_tail(&server->grave, &corpses);
  249. list_del_init(&server->link);
  250. rb_erase(&server->master_rb, &afs_servers);
  251. }
  252. write_unlock(&afs_servers_lock);
  253. write_unlock(&server->cell->servers_lock);
  254. }
  255. spin_unlock(&afs_server_graveyard_lock);
  256. /* now reap the corpses we've extracted */
  257. while (!list_empty(&corpses)) {
  258. server = list_entry(corpses.next, struct afs_server, grave);
  259. list_del(&server->grave);
  260. afs_destroy_server(server);
  261. }
  262. }
  263. /*
  264. * discard all the server records for rmmod
  265. */
  266. void __exit afs_purge_servers(void)
  267. {
  268. afs_server_timeout = 0;
  269. cancel_delayed_work(&afs_server_reaper);
  270. schedule_delayed_work(&afs_server_reaper, 0);
  271. }