• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   */
afs_install_server(struct afs_server * server)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   */
afs_alloc_server(struct afs_cell * cell,const struct in_addr * addr)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   */
afs_lookup_server(struct afs_cell * cell,const struct in_addr * addr)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   */
afs_find_server(const struct sockaddr_rxrpc * srx)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   */
afs_put_server(struct afs_server * server)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 = ktime_get_real_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   */
afs_destroy_server(struct afs_server * server)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   */
afs_reap_server(struct work_struct * work)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  	time64_t now;
281  
282  	now = ktime_get_real_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   */
afs_purge_servers(void)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