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,%pI4", cell, &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: Server %pI4 appears to be in two cells\n", 172 addr); 173 _leave(" = -EEXIST"); 174 return ERR_PTR(-EEXIST); 175 } 176 177 /* 178 * look up a server by its IP address 179 */ 180 struct afs_server *afs_find_server(const struct in_addr *_addr) 181 { 182 struct afs_server *server = NULL; 183 struct rb_node *p; 184 struct in_addr addr = *_addr; 185 186 _enter("%pI4", &addr.s_addr); 187 188 read_lock(&afs_servers_lock); 189 190 p = afs_servers.rb_node; 191 while (p) { 192 server = rb_entry(p, struct afs_server, master_rb); 193 194 _debug("- consider %p", p); 195 196 if (addr.s_addr < server->addr.s_addr) { 197 p = p->rb_left; 198 } else if (addr.s_addr > server->addr.s_addr) { 199 p = p->rb_right; 200 } else { 201 afs_get_server(server); 202 goto found; 203 } 204 } 205 206 server = NULL; 207 found: 208 read_unlock(&afs_servers_lock); 209 ASSERTIFCMP(server, server->addr.s_addr, ==, addr.s_addr); 210 _leave(" = %p", server); 211 return server; 212 } 213 214 /* 215 * destroy a server record 216 * - removes from the cell list 217 */ 218 void afs_put_server(struct afs_server *server) 219 { 220 if (!server) 221 return; 222 223 _enter("%p{%d}", server, atomic_read(&server->usage)); 224 225 _debug("PUT SERVER %d", atomic_read(&server->usage)); 226 227 ASSERTCMP(atomic_read(&server->usage), >, 0); 228 229 if (likely(!atomic_dec_and_test(&server->usage))) { 230 _leave(""); 231 return; 232 } 233 234 afs_flush_callback_breaks(server); 235 236 spin_lock(&afs_server_graveyard_lock); 237 if (atomic_read(&server->usage) == 0) { 238 list_move_tail(&server->grave, &afs_server_graveyard); 239 server->time_of_death = get_seconds(); 240 schedule_delayed_work(&afs_server_reaper, 241 afs_server_timeout * HZ); 242 } 243 spin_unlock(&afs_server_graveyard_lock); 244 _leave(" [dead]"); 245 } 246 247 /* 248 * destroy a dead server 249 */ 250 static void afs_destroy_server(struct afs_server *server) 251 { 252 _enter("%p", server); 253 254 ASSERTIF(server->cb_break_head != server->cb_break_tail, 255 delayed_work_pending(&server->cb_break_work)); 256 257 ASSERTCMP(server->fs_vnodes.rb_node, ==, NULL); 258 ASSERTCMP(server->cb_promises.rb_node, ==, NULL); 259 ASSERTCMP(server->cb_break_head, ==, server->cb_break_tail); 260 ASSERTCMP(atomic_read(&server->cb_break_n), ==, 0); 261 262 afs_put_cell(server->cell); 263 kfree(server); 264 } 265 266 /* 267 * reap dead server records 268 */ 269 static void afs_reap_server(struct work_struct *work) 270 { 271 LIST_HEAD(corpses); 272 struct afs_server *server; 273 unsigned long delay, expiry; 274 time_t now; 275 276 now = get_seconds(); 277 spin_lock(&afs_server_graveyard_lock); 278 279 while (!list_empty(&afs_server_graveyard)) { 280 server = list_entry(afs_server_graveyard.next, 281 struct afs_server, grave); 282 283 /* the queue is ordered most dead first */ 284 expiry = server->time_of_death + afs_server_timeout; 285 if (expiry > now) { 286 delay = (expiry - now) * HZ; 287 if (!schedule_delayed_work(&afs_server_reaper, delay)) { 288 cancel_delayed_work(&afs_server_reaper); 289 schedule_delayed_work(&afs_server_reaper, 290 delay); 291 } 292 break; 293 } 294 295 write_lock(&server->cell->servers_lock); 296 write_lock(&afs_servers_lock); 297 if (atomic_read(&server->usage) > 0) { 298 list_del_init(&server->grave); 299 } else { 300 list_move_tail(&server->grave, &corpses); 301 list_del_init(&server->link); 302 rb_erase(&server->master_rb, &afs_servers); 303 } 304 write_unlock(&afs_servers_lock); 305 write_unlock(&server->cell->servers_lock); 306 } 307 308 spin_unlock(&afs_server_graveyard_lock); 309 310 /* now reap the corpses we've extracted */ 311 while (!list_empty(&corpses)) { 312 server = list_entry(corpses.next, struct afs_server, grave); 313 list_del(&server->grave); 314 afs_destroy_server(server); 315 } 316 } 317 318 /* 319 * discard all the server records for rmmod 320 */ 321 void __exit afs_purge_servers(void) 322 { 323 afs_server_timeout = 0; 324 cancel_delayed_work(&afs_server_reaper); 325 schedule_delayed_work(&afs_server_reaper, 0); 326 } 327