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 _leave(" = %p{%d}", server, atomic_read(&server->usage)); 95 } else { 96 _leave(" = NULL [nomem]"); 97 } 98 return server; 99 } 100 101 /* 102 * get an FS-server record for a cell 103 */ 104 struct afs_server *afs_lookup_server(struct afs_cell *cell, 105 const struct in_addr *addr) 106 { 107 struct afs_server *server, *candidate; 108 109 _enter("%p,%pI4", cell, &addr->s_addr); 110 111 /* quick scan of the list to see if we already have the server */ 112 read_lock(&cell->servers_lock); 113 114 list_for_each_entry(server, &cell->servers, link) { 115 if (server->addr.s_addr == addr->s_addr) 116 goto found_server_quickly; 117 } 118 read_unlock(&cell->servers_lock); 119 120 candidate = afs_alloc_server(cell, addr); 121 if (!candidate) { 122 _leave(" = -ENOMEM"); 123 return ERR_PTR(-ENOMEM); 124 } 125 126 write_lock(&cell->servers_lock); 127 128 /* check the cell's server list again */ 129 list_for_each_entry(server, &cell->servers, link) { 130 if (server->addr.s_addr == addr->s_addr) 131 goto found_server; 132 } 133 134 _debug("new"); 135 server = candidate; 136 if (afs_install_server(server) < 0) 137 goto server_in_two_cells; 138 139 afs_get_cell(cell); 140 list_add_tail(&server->link, &cell->servers); 141 142 write_unlock(&cell->servers_lock); 143 _leave(" = %p{%d}", server, atomic_read(&server->usage)); 144 return server; 145 146 /* found a matching server quickly */ 147 found_server_quickly: 148 _debug("found quickly"); 149 afs_get_server(server); 150 read_unlock(&cell->servers_lock); 151 no_longer_unused: 152 if (!list_empty(&server->grave)) { 153 spin_lock(&afs_server_graveyard_lock); 154 list_del_init(&server->grave); 155 spin_unlock(&afs_server_graveyard_lock); 156 } 157 _leave(" = %p{%d}", server, atomic_read(&server->usage)); 158 return server; 159 160 /* found a matching server on the second pass */ 161 found_server: 162 _debug("found"); 163 afs_get_server(server); 164 write_unlock(&cell->servers_lock); 165 kfree(candidate); 166 goto no_longer_unused; 167 168 /* found a server that seems to be in two cells */ 169 server_in_two_cells: 170 write_unlock(&cell->servers_lock); 171 kfree(candidate); 172 printk(KERN_NOTICE "kAFS: Server %pI4 appears to be in two cells\n", 173 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 sockaddr_rxrpc *srx) 182 { 183 struct afs_server *server = NULL; 184 struct rb_node *p; 185 struct in_addr addr = srx->transport.sin.sin_addr; 186 187 _enter("{%d,%pI4}", srx->transport.family, &addr.s_addr); 188 189 if (srx->transport.family != AF_INET) { 190 WARN(true, "AFS does not yes support non-IPv4 addresses\n"); 191 return NULL; 192 } 193 194 read_lock(&afs_servers_lock); 195 196 p = afs_servers.rb_node; 197 while (p) { 198 server = rb_entry(p, struct afs_server, master_rb); 199 200 _debug("- consider %p", p); 201 202 if (addr.s_addr < server->addr.s_addr) { 203 p = p->rb_left; 204 } else if (addr.s_addr > server->addr.s_addr) { 205 p = p->rb_right; 206 } else { 207 afs_get_server(server); 208 goto found; 209 } 210 } 211 212 server = NULL; 213 found: 214 read_unlock(&afs_servers_lock); 215 ASSERTIFCMP(server, server->addr.s_addr, ==, addr.s_addr); 216 _leave(" = %p", server); 217 return server; 218 } 219 220 /* 221 * destroy a server record 222 * - removes from the cell list 223 */ 224 void afs_put_server(struct afs_server *server) 225 { 226 if (!server) 227 return; 228 229 _enter("%p{%d}", server, atomic_read(&server->usage)); 230 231 _debug("PUT SERVER %d", atomic_read(&server->usage)); 232 233 ASSERTCMP(atomic_read(&server->usage), >, 0); 234 235 if (likely(!atomic_dec_and_test(&server->usage))) { 236 _leave(""); 237 return; 238 } 239 240 afs_flush_callback_breaks(server); 241 242 spin_lock(&afs_server_graveyard_lock); 243 if (atomic_read(&server->usage) == 0) { 244 list_move_tail(&server->grave, &afs_server_graveyard); 245 server->time_of_death = get_seconds(); 246 queue_delayed_work(afs_wq, &afs_server_reaper, 247 afs_server_timeout * HZ); 248 } 249 spin_unlock(&afs_server_graveyard_lock); 250 _leave(" [dead]"); 251 } 252 253 /* 254 * destroy a dead server 255 */ 256 static void afs_destroy_server(struct afs_server *server) 257 { 258 _enter("%p", server); 259 260 ASSERTIF(server->cb_break_head != server->cb_break_tail, 261 delayed_work_pending(&server->cb_break_work)); 262 263 ASSERTCMP(server->fs_vnodes.rb_node, ==, NULL); 264 ASSERTCMP(server->cb_promises.rb_node, ==, NULL); 265 ASSERTCMP(server->cb_break_head, ==, server->cb_break_tail); 266 ASSERTCMP(atomic_read(&server->cb_break_n), ==, 0); 267 268 afs_put_cell(server->cell); 269 kfree(server); 270 } 271 272 /* 273 * reap dead server records 274 */ 275 static void afs_reap_server(struct work_struct *work) 276 { 277 LIST_HEAD(corpses); 278 struct afs_server *server; 279 unsigned long delay, expiry; 280 time_t now; 281 282 now = get_seconds(); 283 spin_lock(&afs_server_graveyard_lock); 284 285 while (!list_empty(&afs_server_graveyard)) { 286 server = list_entry(afs_server_graveyard.next, 287 struct afs_server, grave); 288 289 /* the queue is ordered most dead first */ 290 expiry = server->time_of_death + afs_server_timeout; 291 if (expiry > now) { 292 delay = (expiry - now) * HZ; 293 mod_delayed_work(afs_wq, &afs_server_reaper, delay); 294 break; 295 } 296 297 write_lock(&server->cell->servers_lock); 298 write_lock(&afs_servers_lock); 299 if (atomic_read(&server->usage) > 0) { 300 list_del_init(&server->grave); 301 } else { 302 list_move_tail(&server->grave, &corpses); 303 list_del_init(&server->link); 304 rb_erase(&server->master_rb, &afs_servers); 305 } 306 write_unlock(&afs_servers_lock); 307 write_unlock(&server->cell->servers_lock); 308 } 309 310 spin_unlock(&afs_server_graveyard_lock); 311 312 /* now reap the corpses we've extracted */ 313 while (!list_empty(&corpses)) { 314 server = list_entry(corpses.next, struct afs_server, grave); 315 list_del(&server->grave); 316 afs_destroy_server(server); 317 } 318 } 319 320 /* 321 * discard all the server records for rmmod 322 */ 323 void __exit afs_purge_servers(void) 324 { 325 afs_server_timeout = 0; 326 mod_delayed_work(afs_wq, &afs_server_reaper, 0); 327 } 328