From 9cc6fc50f7bc69ac28bee45eed13cbc65a86210f Mon Sep 17 00:00:00 2001
From: David Howells <dhowells@redhat.com>
Date: Thu, 2 Nov 2017 15:27:50 +0000
Subject: afs: Move server rotation code into its own file

Move server rotation code into its own file.

Signed-off-by: David Howells <dhowells@redhat.com>
---
 fs/afs/Makefile |   1 +
 fs/afs/rotate.c | 254 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/afs/volume.c | 250 -------------------------------------------------------
 3 files changed, 255 insertions(+), 250 deletions(-)
 create mode 100644 fs/afs/rotate.c

diff --git a/fs/afs/Makefile b/fs/afs/Makefile
index 849383986d3b..192d476d7c76 100644
--- a/fs/afs/Makefile
+++ b/fs/afs/Makefile
@@ -20,6 +20,7 @@ kafs-objs := \
 	misc.o \
 	mntpt.o \
 	proc.o \
+	rotate.o \
 	rxrpc.o \
 	security.o \
 	server.o \
diff --git a/fs/afs/rotate.c b/fs/afs/rotate.c
new file mode 100644
index 000000000000..c7975b3ba59a
--- /dev/null
+++ b/fs/afs/rotate.c
@@ -0,0 +1,254 @@
+/* Handle fileserver selection and rotation.
+ *
+ * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include "internal.h"
+
+/*
+ * Initialise a filesystem server cursor for iterating over FS servers.
+ */
+void afs_init_fs_cursor(struct afs_fs_cursor *fc, struct afs_vnode *vnode)
+{
+	memset(fc, 0, sizeof(*fc));
+}
+
+/*
+ * Set a filesystem server cursor for using a specific FS server.
+ */
+int afs_set_fs_cursor(struct afs_fs_cursor *fc, struct afs_vnode *vnode)
+{
+	afs_init_fs_cursor(fc, vnode);
+
+	read_seqlock_excl(&vnode->cb_lock);
+	if (vnode->cb_interest) {
+		if (vnode->cb_interest->server->fs_state == 0)
+			fc->server = afs_get_server(vnode->cb_interest->server);
+		else
+			fc->ac.error = vnode->cb_interest->server->fs_state;
+	} else {
+		fc->ac.error = -ESTALE;
+	}
+	read_sequnlock_excl(&vnode->cb_lock);
+
+	return fc->ac.error;
+}
+
+/*
+ * pick a server to use to try accessing this volume
+ * - returns with an elevated usage count on the server chosen
+ */
+bool afs_volume_pick_fileserver(struct afs_fs_cursor *fc, struct afs_vnode *vnode)
+{
+	struct afs_volume *volume = vnode->volume;
+	struct afs_server *server;
+	int ret, state, loop;
+
+	_enter("%s", volume->vlocation->vldb.name);
+
+	/* stick with the server we're already using if we can */
+	if (vnode->cb_interest && vnode->cb_interest->server->fs_state == 0) {
+		fc->server = afs_get_server(vnode->cb_interest->server);
+		goto set_server;
+	}
+
+	down_read(&volume->server_sem);
+
+	/* handle the no-server case */
+	if (volume->nservers == 0) {
+		fc->ac.error = volume->rjservers ? -ENOMEDIUM : -ESTALE;
+		up_read(&volume->server_sem);
+		_leave(" = f [no servers %d]", fc->ac.error);
+		return false;
+	}
+
+	/* basically, just search the list for the first live server and use
+	 * that */
+	ret = 0;
+	for (loop = 0; loop < volume->nservers; loop++) {
+		server = volume->servers[loop];
+		state = server->fs_state;
+
+		_debug("consider %d [%d]", loop, state);
+
+		switch (state) {
+		case 0:
+			goto picked_server;
+
+		case -ENETUNREACH:
+			if (ret == 0)
+				ret = state;
+			break;
+
+		case -EHOSTUNREACH:
+			if (ret == 0 ||
+			    ret == -ENETUNREACH)
+				ret = state;
+			break;
+
+		case -ECONNREFUSED:
+			if (ret == 0 ||
+			    ret == -ENETUNREACH ||
+			    ret == -EHOSTUNREACH)
+				ret = state;
+			break;
+
+		default:
+		case -EREMOTEIO:
+			if (ret == 0 ||
+			    ret == -ENETUNREACH ||
+			    ret == -EHOSTUNREACH ||
+			    ret == -ECONNREFUSED)
+				ret = state;
+			break;
+		}
+	}
+
+error:
+	fc->ac.error = ret;
+
+	/* no available servers
+	 * - TODO: handle the no active servers case better
+	 */
+	up_read(&volume->server_sem);
+	_leave(" = f [%d]", fc->ac.error);
+	return false;
+
+picked_server:
+	/* Found an apparently healthy server.  We need to register an interest
+	 * in receiving callbacks before we talk to it.
+	 */
+	ret = afs_register_server_cb_interest(vnode,
+					      &volume->cb_interests[loop], server);
+	if (ret < 0)
+		goto error;
+
+	fc->server = afs_get_server(server);
+	up_read(&volume->server_sem);
+set_server:
+	fc->ac.alist = afs_get_addrlist(fc->server->addrs);
+	fc->ac.addr = &fc->ac.alist->addrs[0];
+	_debug("USING SERVER: %pIS\n", &fc->ac.addr->transport);
+	_leave(" = t (picked %pIS)", &fc->ac.addr->transport);
+	return true;
+}
+
+/*
+ * release a server after use
+ * - releases the ref on the server struct that was acquired by picking
+ * - records result of using a particular server to access a volume
+ * - return true to try again, false if okay or to issue error
+ * - the caller must release the server struct if result was false
+ */
+bool afs_iterate_fs_cursor(struct afs_fs_cursor *fc,
+			   struct afs_vnode *vnode)
+{
+	struct afs_volume *volume = vnode->volume;
+	struct afs_server *server = fc->server;
+	unsigned loop;
+
+	_enter("%s,%pIS,%d",
+	       volume->vlocation->vldb.name, &fc->ac.addr->transport,
+	       fc->ac.error);
+
+	switch (fc->ac.error) {
+		/* success */
+	case 0:
+		server->fs_state = 0;
+		_leave(" = f");
+		return false;
+
+		/* the fileserver denied all knowledge of the volume */
+	case -ENOMEDIUM:
+		down_write(&volume->server_sem);
+
+		/* firstly, find where the server is in the active list (if it
+		 * is) */
+		for (loop = 0; loop < volume->nservers; loop++)
+			if (volume->servers[loop] == server)
+				goto present;
+
+		/* no longer there - may have been discarded by another op */
+		goto try_next_server_upw;
+
+	present:
+		volume->nservers--;
+		memmove(&volume->servers[loop],
+			&volume->servers[loop + 1],
+			sizeof(volume->servers[loop]) *
+			(volume->nservers - loop));
+		volume->servers[volume->nservers] = NULL;
+		afs_put_server(afs_v2net(vnode), server);
+		volume->rjservers++;
+
+		if (volume->nservers > 0)
+			/* another server might acknowledge its existence */
+			goto try_next_server_upw;
+
+		/* handle the case where all the fileservers have rejected the
+		 * volume
+		 * - TODO: try asking the fileservers for volume information
+		 * - TODO: contact the VL server again to see if the volume is
+		 *         no longer registered
+		 */
+		up_write(&volume->server_sem);
+		afs_put_server(afs_v2net(vnode), server);
+		fc->server = NULL;
+		_leave(" = f [completely rejected]");
+		return false;
+
+		/* problem reaching the server */
+	case -ENETUNREACH:
+	case -EHOSTUNREACH:
+	case -ECONNREFUSED:
+	case -ETIME:
+	case -ETIMEDOUT:
+	case -EREMOTEIO:
+		/* mark the server as dead
+		 * TODO: vary dead timeout depending on error
+		 */
+		spin_lock(&server->fs_lock);
+		if (!server->fs_state) {
+			server->fs_state = fc->ac.error;
+			printk("kAFS: SERVER DEAD state=%d\n", fc->ac.error);
+		}
+		spin_unlock(&server->fs_lock);
+		goto try_next_server;
+
+		/* miscellaneous error */
+	default:
+	case -ENOMEM:
+	case -ENONET:
+		/* tell the caller to accept the result */
+		afs_put_server(afs_v2net(vnode), server);
+		fc->server = NULL;
+		_leave(" = f [local failure]");
+		return false;
+	}
+
+	/* tell the caller to loop around and try the next server */
+try_next_server_upw:
+	up_write(&volume->server_sem);
+try_next_server:
+	afs_put_server(afs_v2net(vnode), server);
+	_leave(" = t [try next server]");
+	return true;
+}
+
+/*
+ * Clean up a fileserver cursor.
+ */
+int afs_end_fs_cursor(struct afs_fs_cursor *fc, struct afs_net *net)
+{
+	afs_end_cursor(&fc->ac);
+	afs_put_server(net, fc->server);
+	return fc->ac.error;
+}
diff --git a/fs/afs/volume.c b/fs/afs/volume.c
index d282cd0ff268..3c5ad1cc50f3 100644
--- a/fs/afs/volume.c
+++ b/fs/afs/volume.c
@@ -10,12 +10,7 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/fs.h>
-#include <linux/pagemap.h>
-#include <linux/sched.h>
 #include "internal.h"
 
 static const char *afs_voltypes[] = { "R/W", "R/O", "BAK" };
@@ -208,248 +203,3 @@ void afs_put_volume(struct afs_cell *cell, struct afs_volume *volume)
 
 	_leave(" [destroyed]");
 }
-
-/*
- * Initialise a filesystem server cursor for iterating over FS servers.
- */
-void afs_init_fs_cursor(struct afs_fs_cursor *fc, struct afs_vnode *vnode)
-{
-	fc->ac.alist = NULL;
-	fc->ac.addr = NULL;
-	fc->ac.start = 0;
-	fc->ac.index = 0;
-	fc->ac.error = 0;
-	fc->server = NULL;
-}
-
-/*
- * Set a filesystem server cursor for using a specific FS server.
- */
-int afs_set_fs_cursor(struct afs_fs_cursor *fc, struct afs_vnode *vnode)
-{
-	afs_init_fs_cursor(fc, vnode);
-
-	read_seqlock_excl(&vnode->cb_lock);
-	if (vnode->cb_interest) {
-		if (vnode->cb_interest->server->fs_state == 0)
-			fc->server = afs_get_server(vnode->cb_interest->server);
-		else
-			fc->ac.error = vnode->cb_interest->server->fs_state;
-	} else {
-		fc->ac.error = -ESTALE;
-	}
-	read_sequnlock_excl(&vnode->cb_lock);
-
-	return fc->ac.error;
-}
-
-/*
- * pick a server to use to try accessing this volume
- * - returns with an elevated usage count on the server chosen
- */
-bool afs_volume_pick_fileserver(struct afs_fs_cursor *fc, struct afs_vnode *vnode)
-{
-	struct afs_volume *volume = vnode->volume;
-	struct afs_server *server;
-	int ret, state, loop;
-
-	_enter("%s", volume->vlocation->vldb.name);
-
-	/* stick with the server we're already using if we can */
-	if (vnode->cb_interest && vnode->cb_interest->server->fs_state == 0) {
-		fc->server = afs_get_server(vnode->cb_interest->server);
-		goto set_server;
-	}
-
-	down_read(&volume->server_sem);
-
-	/* handle the no-server case */
-	if (volume->nservers == 0) {
-		fc->ac.error = volume->rjservers ? -ENOMEDIUM : -ESTALE;
-		up_read(&volume->server_sem);
-		_leave(" = f [no servers %d]", fc->ac.error);
-		return false;
-	}
-
-	/* basically, just search the list for the first live server and use
-	 * that */
-	ret = 0;
-	for (loop = 0; loop < volume->nservers; loop++) {
-		server = volume->servers[loop];
-		state = server->fs_state;
-
-		_debug("consider %d [%d]", loop, state);
-
-		switch (state) {
-		case 0:
-			goto picked_server;
-
-		case -ENETUNREACH:
-			if (ret == 0)
-				ret = state;
-			break;
-
-		case -EHOSTUNREACH:
-			if (ret == 0 ||
-			    ret == -ENETUNREACH)
-				ret = state;
-			break;
-
-		case -ECONNREFUSED:
-			if (ret == 0 ||
-			    ret == -ENETUNREACH ||
-			    ret == -EHOSTUNREACH)
-				ret = state;
-			break;
-
-		default:
-		case -EREMOTEIO:
-			if (ret == 0 ||
-			    ret == -ENETUNREACH ||
-			    ret == -EHOSTUNREACH ||
-			    ret == -ECONNREFUSED)
-				ret = state;
-			break;
-		}
-	}
-
-error:
-	fc->ac.error = ret;
-
-	/* no available servers
-	 * - TODO: handle the no active servers case better
-	 */
-	up_read(&volume->server_sem);
-	_leave(" = f [%d]", fc->ac.error);
-	return false;
-
-picked_server:
-	/* Found an apparently healthy server.  We need to register an interest
-	 * in receiving callbacks before we talk to it.
-	 */
-	ret = afs_register_server_cb_interest(vnode,
-					      &volume->cb_interests[loop], server);
-	if (ret < 0)
-		goto error;
-
-	fc->server = afs_get_server(server);
-	up_read(&volume->server_sem);
-set_server:
-	fc->ac.alist = afs_get_addrlist(fc->server->addrs);
-	fc->ac.addr = &fc->ac.alist->addrs[0];
-	_debug("USING SERVER: %pIS\n", &fc->ac.addr->transport);
-	_leave(" = t (picked %pIS)", &fc->ac.addr->transport);
-	return true;
-}
-
-/*
- * release a server after use
- * - releases the ref on the server struct that was acquired by picking
- * - records result of using a particular server to access a volume
- * - return true to try again, false if okay or to issue error
- * - the caller must release the server struct if result was false
- */
-bool afs_iterate_fs_cursor(struct afs_fs_cursor *fc,
-			   struct afs_vnode *vnode)
-{
-	struct afs_volume *volume = vnode->volume;
-	struct afs_server *server = fc->server;
-	unsigned loop;
-
-	_enter("%s,%pIS,%d",
-	       volume->vlocation->vldb.name, &fc->ac.addr->transport,
-	       fc->ac.error);
-
-	switch (fc->ac.error) {
-		/* success */
-	case 0:
-		server->fs_state = 0;
-		_leave(" = f");
-		return false;
-
-		/* the fileserver denied all knowledge of the volume */
-	case -ENOMEDIUM:
-		down_write(&volume->server_sem);
-
-		/* firstly, find where the server is in the active list (if it
-		 * is) */
-		for (loop = 0; loop < volume->nservers; loop++)
-			if (volume->servers[loop] == server)
-				goto present;
-
-		/* no longer there - may have been discarded by another op */
-		goto try_next_server_upw;
-
-	present:
-		volume->nservers--;
-		memmove(&volume->servers[loop],
-			&volume->servers[loop + 1],
-			sizeof(volume->servers[loop]) *
-			(volume->nservers - loop));
-		volume->servers[volume->nservers] = NULL;
-		afs_put_server(afs_v2net(vnode), server);
-		volume->rjservers++;
-
-		if (volume->nservers > 0)
-			/* another server might acknowledge its existence */
-			goto try_next_server_upw;
-
-		/* handle the case where all the fileservers have rejected the
-		 * volume
-		 * - TODO: try asking the fileservers for volume information
-		 * - TODO: contact the VL server again to see if the volume is
-		 *         no longer registered
-		 */
-		up_write(&volume->server_sem);
-		afs_put_server(afs_v2net(vnode), server);
-		fc->server = NULL;
-		_leave(" = f [completely rejected]");
-		return false;
-
-		/* problem reaching the server */
-	case -ENETUNREACH:
-	case -EHOSTUNREACH:
-	case -ECONNREFUSED:
-	case -ETIME:
-	case -ETIMEDOUT:
-	case -EREMOTEIO:
-		/* mark the server as dead
-		 * TODO: vary dead timeout depending on error
-		 */
-		spin_lock(&server->fs_lock);
-		if (!server->fs_state) {
-			server->fs_state = fc->ac.error;
-			printk("kAFS: SERVER DEAD state=%d\n", fc->ac.error);
-		}
-		spin_unlock(&server->fs_lock);
-		goto try_next_server;
-
-		/* miscellaneous error */
-	default:
-	case -ENOMEM:
-	case -ENONET:
-		/* tell the caller to accept the result */
-		afs_put_server(afs_v2net(vnode), server);
-		fc->server = NULL;
-		_leave(" = f [local failure]");
-		return false;
-	}
-
-	/* tell the caller to loop around and try the next server */
-try_next_server_upw:
-	up_write(&volume->server_sem);
-try_next_server:
-	afs_put_server(afs_v2net(vnode), server);
-	_leave(" = t [try next server]");
-	return true;
-}
-
-/*
- * Clean up a fileserver cursor.
- */
-int afs_end_fs_cursor(struct afs_fs_cursor *fc, struct afs_net *net)
-{
-	afs_end_cursor(&fc->ac);
-	afs_put_server(net, fc->server);
-	return fc->ac.error;
-}
-- 
cgit v1.2.3