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