| David Howells | ec26815 | 2007-04-26 15:49:28 -0700 | [diff] [blame] | 1 | /* AFS server record management | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2 |  * | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 3 |  * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 14 | #include "internal.h" | 
 | 15 |  | 
| Adrian Bunk | c1206a2 | 2007-10-16 23:26:41 -0700 | [diff] [blame] | 16 | static unsigned afs_server_timeout = 10;	/* server timeout in seconds */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 17 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 18 | static void afs_reap_server(struct work_struct *); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 19 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 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); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 23 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 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); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 28 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 29 | /* | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 30 |  * install a server record in the master tree | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 31 |  */ | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 32 | static int afs_install_server(struct afs_server *server) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 33 | { | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 34 | 	struct afs_server *xserver; | 
 | 35 | 	struct rb_node **pp, *p; | 
 | 36 | 	int ret; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 37 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 38 | 	_enter("%p", server); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 39 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 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 |  | 
| Yan Burman | b593e48 | 2006-12-06 20:40:32 -0800 | [diff] [blame] | 76 | 	server = kzalloc(sizeof(struct afs_server), GFP_KERNEL); | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 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; | 
| Denis Kirjanov | 037776f | 2010-06-01 17:15:39 +0100 | [diff] [blame] | 94 | 		_leave(" = %p{%d}", server, atomic_read(&server->usage)); | 
 | 95 | 	} else { | 
 | 96 | 		_leave(" = NULL [nomem]"); | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 97 | 	} | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 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 |  | 
| Harvey Harrison | be85940 | 2008-10-31 00:56:28 -0700 | [diff] [blame] | 109 | 	_enter("%p,%pI4", cell, &addr->s_addr); | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 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) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 122 | 		_leave(" = -ENOMEM"); | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 123 | 		return ERR_PTR(-ENOMEM); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 124 | 	} | 
 | 125 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 126 | 	write_lock(&cell->servers_lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 127 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 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; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 132 | 	} | 
 | 133 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 134 | 	_debug("new"); | 
 | 135 | 	server = candidate; | 
 | 136 | 	if (afs_install_server(server) < 0) | 
 | 137 | 		goto server_in_two_cells; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 138 |  | 
 | 139 | 	afs_get_cell(cell); | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 140 | 	list_add_tail(&server->link, &cell->servers); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 141 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 142 | 	write_unlock(&cell->servers_lock); | 
 | 143 | 	_leave(" = %p{%d}", server, atomic_read(&server->usage)); | 
 | 144 | 	return server; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 145 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 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; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 159 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 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; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 167 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 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); | 
| Harvey Harrison | be85940 | 2008-10-31 00:56:28 -0700 | [diff] [blame] | 172 | 	printk(KERN_NOTICE "kAFS: Server %pI4 appears to be in two cells\n", | 
 | 173 | 	       addr); | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 174 | 	_leave(" = -EEXIST"); | 
 | 175 | 	return ERR_PTR(-EEXIST); | 
 | 176 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 177 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 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; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 186 |  | 
| Harvey Harrison | be85940 | 2008-10-31 00:56:28 -0700 | [diff] [blame] | 187 | 	_enter("%pI4", &addr.s_addr); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 188 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 189 | 	read_lock(&afs_servers_lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 190 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 191 | 	p = afs_servers.rb_node; | 
 | 192 | 	while (p) { | 
 | 193 | 		server = rb_entry(p, struct afs_server, master_rb); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 194 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 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; | 
| David Howells | ec26815 | 2007-04-26 15:49:28 -0700 | [diff] [blame] | 213 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 214 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 215 | /* | 
 | 216 |  * destroy a server record | 
 | 217 |  * - removes from the cell list | 
 | 218 |  */ | 
 | 219 | void afs_put_server(struct afs_server *server) | 
 | 220 | { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 221 | 	if (!server) | 
 | 222 | 		return; | 
 | 223 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 224 | 	_enter("%p{%d}", server, atomic_read(&server->usage)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 225 |  | 
| David Howells | 260a980 | 2007-04-26 15:59:35 -0700 | [diff] [blame] | 226 | 	_debug("PUT SERVER %d", atomic_read(&server->usage)); | 
 | 227 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 228 | 	ASSERTCMP(atomic_read(&server->usage), >, 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 229 |  | 
 | 230 | 	if (likely(!atomic_dec_and_test(&server->usage))) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 231 | 		_leave(""); | 
 | 232 | 		return; | 
 | 233 | 	} | 
 | 234 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 235 | 	afs_flush_callback_breaks(server); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 236 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 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(); | 
| Tejun Heo | 0ad53ee | 2011-01-14 15:56:37 +0000 | [diff] [blame] | 241 | 		queue_delayed_work(afs_wq, &afs_server_reaper, | 
 | 242 | 				   afs_server_timeout * HZ); | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 243 | 	} | 
 | 244 | 	spin_unlock(&afs_server_graveyard_lock); | 
 | 245 | 	_leave(" [dead]"); | 
| David Howells | ec26815 | 2007-04-26 15:49:28 -0700 | [diff] [blame] | 246 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 247 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 248 | /* | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 249 |  * destroy a dead server | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 250 |  */ | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 251 | static void afs_destroy_server(struct afs_server *server) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 252 | { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 253 | 	_enter("%p", server); | 
 | 254 |  | 
| David Howells | 416351f | 2007-05-09 02:33:45 -0700 | [diff] [blame] | 255 | 	ASSERTIF(server->cb_break_head != server->cb_break_tail, | 
 | 256 | 		 delayed_work_pending(&server->cb_break_work)); | 
 | 257 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 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); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 262 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 263 | 	afs_put_cell(server->cell); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 264 | 	kfree(server); | 
| David Howells | ec26815 | 2007-04-26 15:49:28 -0700 | [diff] [blame] | 265 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 266 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 267 | /* | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 268 |  * reap dead server records | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 269 |  */ | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 270 | static void afs_reap_server(struct work_struct *work) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 271 | { | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 272 | 	LIST_HEAD(corpses); | 
 | 273 | 	struct afs_server *server; | 
 | 274 | 	unsigned long delay, expiry; | 
 | 275 | 	time_t now; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 276 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 277 | 	now = get_seconds(); | 
 | 278 | 	spin_lock(&afs_server_graveyard_lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 279 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 280 | 	while (!list_empty(&afs_server_graveyard)) { | 
 | 281 | 		server = list_entry(afs_server_graveyard.next, | 
 | 282 | 				    struct afs_server, grave); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 283 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 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; | 
| Tejun Heo | 0ad53ee | 2011-01-14 15:56:37 +0000 | [diff] [blame] | 288 | 			if (!queue_delayed_work(afs_wq, &afs_server_reaper, | 
 | 289 | 						delay)) { | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 290 | 				cancel_delayed_work(&afs_server_reaper); | 
| Tejun Heo | 0ad53ee | 2011-01-14 15:56:37 +0000 | [diff] [blame] | 291 | 				queue_delayed_work(afs_wq, &afs_server_reaper, | 
 | 292 | 						   delay); | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 293 | 			} | 
 | 294 | 			break; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 295 | 		} | 
 | 296 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 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); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 305 | 		} | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 306 | 		write_unlock(&afs_servers_lock); | 
 | 307 | 		write_unlock(&server->cell->servers_lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 308 | 	} | 
 | 309 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 310 | 	spin_unlock(&afs_server_graveyard_lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 311 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 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); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 317 | 	} | 
| David Howells | ec26815 | 2007-04-26 15:49:28 -0700 | [diff] [blame] | 318 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 319 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 320 | /* | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 321 |  * discard all the server records for rmmod | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 322 |  */ | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 323 | void __exit afs_purge_servers(void) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 324 | { | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 325 | 	afs_server_timeout = 0; | 
 | 326 | 	cancel_delayed_work(&afs_server_reaper); | 
| Tejun Heo | 0ad53ee | 2011-01-14 15:56:37 +0000 | [diff] [blame] | 327 | 	queue_delayed_work(afs_wq, &afs_server_reaper, 0); | 
| David Howells | ec26815 | 2007-04-26 15:49:28 -0700 | [diff] [blame] | 328 | } |