mirror of https://gitee.com/openkylin/linux.git
afs: Fix server reaping
Fix server reaping and make sure it's all done before we start trying to purge cells, given that servers currently pin cells. Signed-off-by: David Howells <dhowells@redhat.com>
This commit is contained in:
parent
e3b2ffe0f0
commit
59fa1c4a9f
|
@ -238,7 +238,9 @@ struct afs_net {
|
||||||
rwlock_t servers_lock;
|
rwlock_t servers_lock;
|
||||||
struct list_head server_graveyard; /* Inactive server LRU list */
|
struct list_head server_graveyard; /* Inactive server LRU list */
|
||||||
spinlock_t server_graveyard_lock;
|
spinlock_t server_graveyard_lock;
|
||||||
struct delayed_work server_reaper;
|
struct timer_list server_timer;
|
||||||
|
struct work_struct server_reaper;
|
||||||
|
atomic_t servers_outstanding;
|
||||||
|
|
||||||
/* Misc */
|
/* Misc */
|
||||||
struct proc_dir_entry *proc_afs; /* /proc/net/afs directory */
|
struct proc_dir_entry *proc_afs; /* /proc/net/afs directory */
|
||||||
|
@ -700,6 +702,7 @@ do { \
|
||||||
atomic_inc(&(S)->usage); \
|
atomic_inc(&(S)->usage); \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
|
extern void afs_server_timer(struct timer_list *);
|
||||||
extern struct afs_server *afs_lookup_server(struct afs_cell *,
|
extern struct afs_server *afs_lookup_server(struct afs_cell *,
|
||||||
const struct in_addr *);
|
const struct in_addr *);
|
||||||
extern struct afs_server *afs_find_server(struct afs_net *,
|
extern struct afs_server *afs_find_server(struct afs_net *,
|
||||||
|
|
|
@ -62,7 +62,8 @@ static int __net_init afs_net_init(struct afs_net *net)
|
||||||
rwlock_init(&net->servers_lock);
|
rwlock_init(&net->servers_lock);
|
||||||
INIT_LIST_HEAD(&net->server_graveyard);
|
INIT_LIST_HEAD(&net->server_graveyard);
|
||||||
spin_lock_init(&net->server_graveyard_lock);
|
spin_lock_init(&net->server_graveyard_lock);
|
||||||
INIT_DELAYED_WORK(&net->server_reaper, afs_reap_server);
|
INIT_WORK(&net->server_reaper, afs_reap_server);
|
||||||
|
timer_setup(&net->server_timer, afs_server_timer, 0);
|
||||||
|
|
||||||
/* Register the /proc stuff */
|
/* Register the /proc stuff */
|
||||||
ret = afs_proc_init(net);
|
ret = afs_proc_init(net);
|
||||||
|
|
|
@ -15,6 +15,25 @@
|
||||||
|
|
||||||
static unsigned afs_server_timeout = 10; /* server timeout in seconds */
|
static unsigned afs_server_timeout = 10; /* server timeout in seconds */
|
||||||
|
|
||||||
|
static void afs_inc_servers_outstanding(struct afs_net *net)
|
||||||
|
{
|
||||||
|
atomic_inc(&net->servers_outstanding);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void afs_dec_servers_outstanding(struct afs_net *net)
|
||||||
|
{
|
||||||
|
if (atomic_dec_and_test(&net->servers_outstanding))
|
||||||
|
wake_up_atomic_t(&net->servers_outstanding);
|
||||||
|
}
|
||||||
|
|
||||||
|
void afs_server_timer(struct timer_list *timer)
|
||||||
|
{
|
||||||
|
struct afs_net *net = container_of(timer, struct afs_net, server_timer);
|
||||||
|
|
||||||
|
if (!queue_work(afs_wq, &net->server_reaper))
|
||||||
|
afs_dec_servers_outstanding(net);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* install a server record in the master tree
|
* install a server record in the master tree
|
||||||
*/
|
*/
|
||||||
|
@ -81,6 +100,7 @@ static struct afs_server *afs_alloc_server(struct afs_cell *cell,
|
||||||
|
|
||||||
memcpy(&server->addr, addr, sizeof(struct in_addr));
|
memcpy(&server->addr, addr, sizeof(struct in_addr));
|
||||||
server->addr.s_addr = addr->s_addr;
|
server->addr.s_addr = addr->s_addr;
|
||||||
|
afs_inc_servers_outstanding(cell->net);
|
||||||
_leave(" = %p{%d}", server, atomic_read(&server->usage));
|
_leave(" = %p{%d}", server, atomic_read(&server->usage));
|
||||||
} else {
|
} else {
|
||||||
_leave(" = NULL [nomem]");
|
_leave(" = NULL [nomem]");
|
||||||
|
@ -159,6 +179,7 @@ struct afs_server *afs_lookup_server(struct afs_cell *cell,
|
||||||
server_in_two_cells:
|
server_in_two_cells:
|
||||||
write_unlock(&cell->servers_lock);
|
write_unlock(&cell->servers_lock);
|
||||||
kfree(candidate);
|
kfree(candidate);
|
||||||
|
afs_dec_servers_outstanding(cell->net);
|
||||||
printk(KERN_NOTICE "kAFS: Server %pI4 appears to be in two cells\n",
|
printk(KERN_NOTICE "kAFS: Server %pI4 appears to be in two cells\n",
|
||||||
addr);
|
addr);
|
||||||
_leave(" = -EEXIST");
|
_leave(" = -EEXIST");
|
||||||
|
@ -208,6 +229,18 @@ struct afs_server *afs_find_server(struct afs_net *net,
|
||||||
return server;
|
return server;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void afs_set_server_timer(struct afs_net *net, time64_t delay)
|
||||||
|
{
|
||||||
|
afs_inc_servers_outstanding(net);
|
||||||
|
if (net->live) {
|
||||||
|
if (timer_reduce(&net->server_timer, jiffies + delay * HZ))
|
||||||
|
afs_dec_servers_outstanding(net);
|
||||||
|
} else {
|
||||||
|
if (!queue_work(afs_wq, &net->server_reaper))
|
||||||
|
afs_dec_servers_outstanding(net);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* destroy a server record
|
* destroy a server record
|
||||||
* - removes from the cell list
|
* - removes from the cell list
|
||||||
|
@ -236,8 +269,7 @@ void afs_put_server(struct afs_server *server)
|
||||||
if (atomic_read(&server->usage) == 0) {
|
if (atomic_read(&server->usage) == 0) {
|
||||||
list_move_tail(&server->grave, &net->server_graveyard);
|
list_move_tail(&server->grave, &net->server_graveyard);
|
||||||
server->time_of_death = ktime_get_real_seconds();
|
server->time_of_death = ktime_get_real_seconds();
|
||||||
queue_delayed_work(afs_wq, &net->server_reaper,
|
afs_set_server_timer(net, afs_server_timeout);
|
||||||
net->live ? afs_server_timeout * HZ : 0);
|
|
||||||
}
|
}
|
||||||
spin_unlock(&net->server_graveyard_lock);
|
spin_unlock(&net->server_graveyard_lock);
|
||||||
_leave(" [dead]");
|
_leave(" [dead]");
|
||||||
|
@ -246,7 +278,7 @@ void afs_put_server(struct afs_server *server)
|
||||||
/*
|
/*
|
||||||
* destroy a dead server
|
* destroy a dead server
|
||||||
*/
|
*/
|
||||||
static void afs_destroy_server(struct afs_server *server)
|
static void afs_destroy_server(struct afs_net *net, struct afs_server *server)
|
||||||
{
|
{
|
||||||
_enter("%p", server);
|
_enter("%p", server);
|
||||||
|
|
||||||
|
@ -260,6 +292,7 @@ static void afs_destroy_server(struct afs_server *server)
|
||||||
|
|
||||||
afs_put_cell(server->cell);
|
afs_put_cell(server->cell);
|
||||||
kfree(server);
|
kfree(server);
|
||||||
|
afs_dec_servers_outstanding(net);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -269,7 +302,7 @@ void afs_reap_server(struct work_struct *work)
|
||||||
{
|
{
|
||||||
LIST_HEAD(corpses);
|
LIST_HEAD(corpses);
|
||||||
struct afs_server *server;
|
struct afs_server *server;
|
||||||
struct afs_net *net = container_of(work, struct afs_net, server_reaper.work);
|
struct afs_net *net = container_of(work, struct afs_net, server_reaper);
|
||||||
unsigned long delay, expiry;
|
unsigned long delay, expiry;
|
||||||
time64_t now;
|
time64_t now;
|
||||||
|
|
||||||
|
@ -284,8 +317,8 @@ void afs_reap_server(struct work_struct *work)
|
||||||
if (net->live) {
|
if (net->live) {
|
||||||
expiry = server->time_of_death + afs_server_timeout;
|
expiry = server->time_of_death + afs_server_timeout;
|
||||||
if (expiry > now) {
|
if (expiry > now) {
|
||||||
delay = (expiry - now) * HZ;
|
delay = (expiry - now);
|
||||||
mod_delayed_work(afs_wq, &net->server_reaper, delay);
|
afs_set_server_timer(net, delay);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -309,8 +342,10 @@ void afs_reap_server(struct work_struct *work)
|
||||||
while (!list_empty(&corpses)) {
|
while (!list_empty(&corpses)) {
|
||||||
server = list_entry(corpses.next, struct afs_server, grave);
|
server = list_entry(corpses.next, struct afs_server, grave);
|
||||||
list_del(&server->grave);
|
list_del(&server->grave);
|
||||||
afs_destroy_server(server);
|
afs_destroy_server(net, server);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
afs_dec_servers_outstanding(net);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -319,5 +354,13 @@ void afs_reap_server(struct work_struct *work)
|
||||||
*/
|
*/
|
||||||
void __net_exit afs_purge_servers(struct afs_net *net)
|
void __net_exit afs_purge_servers(struct afs_net *net)
|
||||||
{
|
{
|
||||||
mod_delayed_work(afs_wq, &net->server_reaper, 0);
|
if (del_timer_sync(&net->server_timer))
|
||||||
|
atomic_dec(&net->servers_outstanding);
|
||||||
|
|
||||||
|
afs_inc_servers_outstanding(net);
|
||||||
|
if (!queue_work(afs_wq, &net->server_reaper))
|
||||||
|
afs_dec_servers_outstanding(net);
|
||||||
|
|
||||||
|
wait_on_atomic_t(&net->servers_outstanding, atomic_t_wait,
|
||||||
|
TASK_UNINTERRUPTIBLE);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue