Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 59fa1c4a authored by David Howells's avatar David Howells
Browse files

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: default avatarDavid Howells <dhowells@redhat.com>
parent e3b2ffe0
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -238,7 +238,9 @@ struct afs_net {
	rwlock_t		servers_lock;
	struct list_head	server_graveyard;	/* Inactive server LRU list */
	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 */
	struct proc_dir_entry	*proc_afs;		/* /proc/net/afs directory */
@@ -700,6 +702,7 @@ do { \
	atomic_inc(&(S)->usage);				\
} while(0)

extern void afs_server_timer(struct timer_list *);
extern struct afs_server *afs_lookup_server(struct afs_cell *,
					    const struct in_addr *);
extern struct afs_server *afs_find_server(struct afs_net *,
+2 −1
Original line number Diff line number Diff line
@@ -62,7 +62,8 @@ static int __net_init afs_net_init(struct afs_net *net)
	rwlock_init(&net->servers_lock);
	INIT_LIST_HEAD(&net->server_graveyard);
	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 */
	ret = afs_proc_init(net);
+51 −8
Original line number Diff line number Diff line
@@ -15,6 +15,25 @@

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
 */
@@ -81,6 +100,7 @@ static struct afs_server *afs_alloc_server(struct afs_cell *cell,

		memcpy(&server->addr, addr, sizeof(struct in_addr));
		server->addr.s_addr = addr->s_addr;
		afs_inc_servers_outstanding(cell->net);
		_leave(" = %p{%d}", server, atomic_read(&server->usage));
	} else {
		_leave(" = NULL [nomem]");
@@ -159,6 +179,7 @@ struct afs_server *afs_lookup_server(struct afs_cell *cell,
server_in_two_cells:
	write_unlock(&cell->servers_lock);
	kfree(candidate);
	afs_dec_servers_outstanding(cell->net);
	printk(KERN_NOTICE "kAFS: Server %pI4 appears to be in two cells\n",
	       addr);
	_leave(" = -EEXIST");
@@ -208,6 +229,18 @@ struct afs_server *afs_find_server(struct afs_net *net,
	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
 * - removes from the cell list
@@ -236,8 +269,7 @@ void afs_put_server(struct afs_server *server)
	if (atomic_read(&server->usage) == 0) {
		list_move_tail(&server->grave, &net->server_graveyard);
		server->time_of_death = ktime_get_real_seconds();
		queue_delayed_work(afs_wq, &net->server_reaper,
				   net->live ? afs_server_timeout * HZ : 0);
		afs_set_server_timer(net, afs_server_timeout);
	}
	spin_unlock(&net->server_graveyard_lock);
	_leave(" [dead]");
@@ -246,7 +278,7 @@ void afs_put_server(struct afs_server *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);

@@ -260,6 +292,7 @@ static void afs_destroy_server(struct afs_server *server)

	afs_put_cell(server->cell);
	kfree(server);
	afs_dec_servers_outstanding(net);
}

/*
@@ -269,7 +302,7 @@ void afs_reap_server(struct work_struct *work)
{
	LIST_HEAD(corpses);
	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;
	time64_t now;

@@ -284,8 +317,8 @@ void afs_reap_server(struct work_struct *work)
		if (net->live) {
			expiry = server->time_of_death + afs_server_timeout;
			if (expiry > now) {
				delay = (expiry - now) * HZ;
				mod_delayed_work(afs_wq, &net->server_reaper, delay);
				delay = (expiry - now);
				afs_set_server_timer(net, delay);
				break;
			}
		}
@@ -309,8 +342,10 @@ void afs_reap_server(struct work_struct *work)
	while (!list_empty(&corpses)) {
		server = list_entry(corpses.next, struct afs_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)
{
	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);
}