1 /* AFS server record management
3 * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved.
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.
12 #include <linux/sched.h>
13 #include <linux/slab.h>
17 static unsigned afs_server_timeout = 10; /* server timeout in seconds */
19 static void afs_inc_servers_outstanding(struct afs_net *net)
21 atomic_inc(&net->servers_outstanding);
24 static void afs_dec_servers_outstanding(struct afs_net *net)
26 if (atomic_dec_and_test(&net->servers_outstanding))
27 wake_up_atomic_t(&net->servers_outstanding);
30 void afs_server_timer(struct timer_list *timer)
32 struct afs_net *net = container_of(timer, struct afs_net, server_timer);
34 if (!queue_work(afs_wq, &net->server_reaper))
35 afs_dec_servers_outstanding(net);
39 * install a server record in the master tree
41 static int afs_install_server(struct afs_server *server)
43 struct afs_server *xserver;
44 struct afs_net *net = server->cell->net;
45 struct rb_node **pp, *p;
50 write_lock(&net->servers_lock);
53 pp = &net->servers.rb_node;
57 _debug("- consider %p", p);
58 xserver = rb_entry(p, struct afs_server, master_rb);
59 diff = memcmp(&server->addr, &xserver->addr, sizeof(server->addr));
63 pp = &(*pp)->rb_right;
68 rb_link_node(&server->master_rb, p, pp);
69 rb_insert_color(&server->master_rb, &net->servers);
73 write_unlock(&net->servers_lock);
78 * allocate a new server record
80 static struct afs_server *afs_alloc_server(struct afs_cell *cell,
81 const struct sockaddr_rxrpc *addr)
83 struct afs_server *server;
87 server = kzalloc(sizeof(struct afs_server), GFP_KERNEL);
89 atomic_set(&server->usage, 1);
90 server->net = cell->net;
93 INIT_LIST_HEAD(&server->link);
94 INIT_LIST_HEAD(&server->grave);
95 init_rwsem(&server->sem);
96 spin_lock_init(&server->fs_lock);
97 INIT_LIST_HEAD(&server->cb_interests);
98 rwlock_init(&server->cb_break_lock);
100 server->addr = *addr;
101 afs_inc_servers_outstanding(cell->net);
102 _leave(" = %p{%d}", server, atomic_read(&server->usage));
104 _leave(" = NULL [nomem]");
110 * get an FS-server record for a cell
112 struct afs_server *afs_lookup_server(struct afs_cell *cell,
113 struct sockaddr_rxrpc *addr)
115 struct afs_server *server, *candidate;
117 _enter("%p,%pIS", cell, &addr->transport);
119 /* quick scan of the list to see if we already have the server */
120 read_lock(&cell->servers_lock);
122 list_for_each_entry(server, &cell->servers, link) {
123 if (memcmp(&server->addr, addr, sizeof(*addr)) == 0)
124 goto found_server_quickly;
126 read_unlock(&cell->servers_lock);
128 candidate = afs_alloc_server(cell, addr);
130 _leave(" = -ENOMEM");
131 return ERR_PTR(-ENOMEM);
134 write_lock(&cell->servers_lock);
136 /* check the cell's server list again */
137 list_for_each_entry(server, &cell->servers, link) {
138 if (memcmp(&server->addr, addr, sizeof(*addr)) == 0)
144 if (afs_install_server(server) < 0)
145 goto server_in_two_cells;
148 list_add_tail(&server->link, &cell->servers);
150 write_unlock(&cell->servers_lock);
151 _leave(" = %p{%d}", server, atomic_read(&server->usage));
154 /* found a matching server quickly */
155 found_server_quickly:
156 _debug("found quickly");
157 afs_get_server(server);
158 read_unlock(&cell->servers_lock);
160 if (!list_empty(&server->grave)) {
161 spin_lock(&cell->net->server_graveyard_lock);
162 list_del_init(&server->grave);
163 spin_unlock(&cell->net->server_graveyard_lock);
165 _leave(" = %p{%d}", server, atomic_read(&server->usage));
168 /* found a matching server on the second pass */
171 afs_get_server(server);
172 write_unlock(&cell->servers_lock);
174 goto no_longer_unused;
176 /* found a server that seems to be in two cells */
178 write_unlock(&cell->servers_lock);
180 afs_dec_servers_outstanding(cell->net);
181 printk(KERN_NOTICE "kAFS: Server %pI4 appears to be in two cells\n",
183 _leave(" = -EEXIST");
184 return ERR_PTR(-EEXIST);
188 * look up a server by its IP address
190 struct afs_server *afs_find_server(struct afs_net *net,
191 const struct sockaddr_rxrpc *srx)
193 struct afs_server *server = NULL;
197 _enter("{%d,%pIS}", srx->transport.family, &srx->transport);
199 read_lock(&net->servers_lock);
201 p = net->servers.rb_node;
203 server = rb_entry(p, struct afs_server, master_rb);
205 _debug("- consider %p", p);
207 diff = memcmp(srx, &server->addr, sizeof(*srx));
210 } else if (diff > 0) {
213 afs_get_server(server);
220 read_unlock(&net->servers_lock);
221 _leave(" = %p", server);
225 static void afs_set_server_timer(struct afs_net *net, time64_t delay)
227 afs_inc_servers_outstanding(net);
229 if (timer_reduce(&net->server_timer, jiffies + delay * HZ))
230 afs_dec_servers_outstanding(net);
232 if (!queue_work(afs_wq, &net->server_reaper))
233 afs_dec_servers_outstanding(net);
238 * destroy a server record
239 * - removes from the cell list
241 void afs_put_server(struct afs_net *net, struct afs_server *server)
246 _enter("%p{%d}", server, atomic_read(&server->usage));
248 _debug("PUT SERVER %d", atomic_read(&server->usage));
250 ASSERTCMP(atomic_read(&server->usage), >, 0);
252 if (likely(!atomic_dec_and_test(&server->usage))) {
257 spin_lock(&net->server_graveyard_lock);
258 if (atomic_read(&server->usage) == 0) {
259 list_move_tail(&server->grave, &net->server_graveyard);
260 server->time_of_death = ktime_get_real_seconds();
261 afs_set_server_timer(net, afs_server_timeout);
263 spin_unlock(&net->server_graveyard_lock);
268 * destroy a dead server
270 static void afs_destroy_server(struct afs_net *net, struct afs_server *server)
272 _enter("%p", server);
274 afs_fs_give_up_all_callbacks(server, NULL, false);
275 afs_put_cell(net, server->cell);
277 afs_dec_servers_outstanding(net);
281 * reap dead server records
283 void afs_reap_server(struct work_struct *work)
286 struct afs_server *server;
287 struct afs_net *net = container_of(work, struct afs_net, server_reaper);
288 unsigned long delay, expiry;
291 now = ktime_get_real_seconds();
292 spin_lock(&net->server_graveyard_lock);
294 while (!list_empty(&net->server_graveyard)) {
295 server = list_entry(net->server_graveyard.next,
296 struct afs_server, grave);
298 /* the queue is ordered most dead first */
300 expiry = server->time_of_death + afs_server_timeout;
302 delay = (expiry - now);
303 afs_set_server_timer(net, delay);
308 write_lock(&server->cell->servers_lock);
309 write_lock(&net->servers_lock);
310 if (atomic_read(&server->usage) > 0) {
311 list_del_init(&server->grave);
313 list_move_tail(&server->grave, &corpses);
314 list_del_init(&server->link);
315 rb_erase(&server->master_rb, &net->servers);
317 write_unlock(&net->servers_lock);
318 write_unlock(&server->cell->servers_lock);
321 spin_unlock(&net->server_graveyard_lock);
323 /* now reap the corpses we've extracted */
324 while (!list_empty(&corpses)) {
325 server = list_entry(corpses.next, struct afs_server, grave);
326 list_del(&server->grave);
327 afs_destroy_server(net, server);
330 afs_dec_servers_outstanding(net);
334 * Discard all the server records from a net namespace when it is destroyed or
335 * the afs module is removed.
337 void __net_exit afs_purge_servers(struct afs_net *net)
339 if (del_timer_sync(&net->server_timer))
340 atomic_dec(&net->servers_outstanding);
342 afs_inc_servers_outstanding(net);
343 if (!queue_work(afs_wq, &net->server_reaper))
344 afs_dec_servers_outstanding(net);
346 wait_on_atomic_t(&net->servers_outstanding, atomic_t_wait,
347 TASK_UNINTERRUPTIBLE);