2021-03-23 05:48:40

by Nagendra Tomar

[permalink] [raw]
Subject: [PATCH 1/5] nfs: Add mount option for forcing RPC requests for one file over one connection

From: Nagendra S Tomar <[email protected]>

Adds a new rpc_xprt_iter_ops which returns a xprt suitable for carrying
an RPC based on an additional u32 hash parameter to identify the RPC
target file.
Other xprt policies, like roundrobin, which do not make use of the hash
ignore it.

Signed-off-by: Nagendra S Tomar <[email protected]>
---
net/sunrpc/clnt.c | 4 +-
net/sunrpc/xprtmultipath.c | 91 ++++++++++++++++++++++++++++++++++--
3 files changed, 95 insertions(+), 9 deletions(-)

diff --git a/include/linux/sunrpc/xprtmultipath.h b/include/linux/sunrpc/xprtmultipath.h
index c6cce3fbf29d..62caecfaa4f8 100644
--- a/include/linux/sunrpc/xprtmultipath.h
+++ b/include/linux/sunrpc/xprtmultipath.h
@@ -37,7 +37,11 @@ struct rpc_xprt_iter {
struct rpc_xprt_iter_ops {
void (*xpi_rewind)(struct rpc_xprt_iter *);
struct rpc_xprt *(*xpi_xprt)(struct rpc_xprt_iter *);
- struct rpc_xprt *(*xpi_next)(struct rpc_xprt_iter *);
+ /*
+ * 2nd parameter is a hash value identifying the RPC target file.
+ * A xprt policy may use it to affine RPCs for a file to a xprt.
+ */
+ struct rpc_xprt *(*xpi_next)(struct rpc_xprt_iter *, u32);
};

extern struct rpc_xprt_switch *xprt_switch_alloc(struct rpc_xprt *xprt,
@@ -47,6 +51,7 @@ extern struct rpc_xprt_switch *xprt_switch_get(struct rpc_xprt_switch *xps);
extern void xprt_switch_put(struct rpc_xprt_switch *xps);

extern void rpc_xprt_switch_set_roundrobin(struct rpc_xprt_switch *xps);
+extern void rpc_xprt_switch_set_hash(struct rpc_xprt_switch *xps);

extern void rpc_xprt_switch_add_xprt(struct rpc_xprt_switch *xps,
struct rpc_xprt *xprt);
@@ -67,7 +72,7 @@ extern struct rpc_xprt_switch *xprt_iter_xchg_switch(

extern struct rpc_xprt *xprt_iter_xprt(struct rpc_xprt_iter *xpi);
extern struct rpc_xprt *xprt_iter_get_xprt(struct rpc_xprt_iter *xpi);
-extern struct rpc_xprt *xprt_iter_get_next(struct rpc_xprt_iter *xpi);
+extern struct rpc_xprt *xprt_iter_get_next(struct rpc_xprt_iter *xpi, u32 hash);

extern bool rpc_xprt_switch_has_addr(struct rpc_xprt_switch *xps,
const struct sockaddr *sap);
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 612f0a641f4c..1b2a02460601 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -809,7 +809,7 @@ int rpc_clnt_iterate_for_each_xprt(struct rpc_clnt *clnt,
if (ret)
return ret;
for (;;) {
- struct rpc_xprt *xprt = xprt_iter_get_next(&xpi);
+ struct rpc_xprt *xprt = xprt_iter_get_next(&xpi, 0);

if (!xprt)
break;
@@ -1055,7 +1055,7 @@ rpc_task_get_first_xprt(struct rpc_clnt *clnt)
static struct rpc_xprt *
rpc_task_get_next_xprt(struct rpc_clnt *clnt)
{
- return rpc_task_get_xprt(clnt, xprt_iter_get_next(&clnt->cl_xpi));
+ return rpc_task_get_xprt(clnt, xprt_iter_get_next(&clnt->cl_xpi, 0));
}

static
diff --git a/net/sunrpc/xprtmultipath.c b/net/sunrpc/xprtmultipath.c
index 78c075a68c04..7901afa432f0 100644
--- a/net/sunrpc/xprtmultipath.c
+++ b/net/sunrpc/xprtmultipath.c
@@ -24,6 +24,7 @@ typedef struct rpc_xprt *(*xprt_switch_find_xprt_t)(struct rpc_xprt_switch *xps,

static const struct rpc_xprt_iter_ops rpc_xprt_iter_singular;
static const struct rpc_xprt_iter_ops rpc_xprt_iter_roundrobin;
+static const struct rpc_xprt_iter_ops rpc_xprt_iter_hash;
static const struct rpc_xprt_iter_ops rpc_xprt_iter_listall;

static void xprt_switch_add_xprt_locked(struct rpc_xprt_switch *xps,
@@ -176,6 +177,12 @@ void rpc_xprt_switch_set_roundrobin(struct rpc_xprt_switch *xps)
WRITE_ONCE(xps->xps_iter_ops, &rpc_xprt_iter_roundrobin);
}

+void rpc_xprt_switch_set_hash(struct rpc_xprt_switch *xps)
+{
+ if (READ_ONCE(xps->xps_iter_ops) != &rpc_xprt_iter_hash)
+ WRITE_ONCE(xps->xps_iter_ops, &rpc_xprt_iter_hash);
+}
+
static
const struct rpc_xprt_iter_ops *xprt_iter_ops(const struct rpc_xprt_iter *xpi)
{
@@ -223,6 +230,13 @@ struct rpc_xprt *xprt_iter_first_entry(struct rpc_xprt_iter *xpi)
return xprt_switch_find_first_entry(&xps->xps_xprt_list);
}

+static
+struct rpc_xprt *xprt_iter_next_entry_singular(struct rpc_xprt_iter *xpi,
+ u32 hash)
+{
+ return xprt_iter_first_entry(xpi);
+}
+
static
struct rpc_xprt *xprt_switch_find_current_entry(struct list_head *head,
const struct rpc_xprt *cur)
@@ -352,12 +366,55 @@ struct rpc_xprt *xprt_switch_find_next_entry_roundrobin(struct rpc_xprt_switch *
}

static
-struct rpc_xprt *xprt_iter_next_entry_roundrobin(struct rpc_xprt_iter *xpi)
+struct rpc_xprt *xprt_iter_next_entry_roundrobin(struct rpc_xprt_iter *xpi,
+ u32 hash)
{
return xprt_iter_next_entry_multiple(xpi,
xprt_switch_find_next_entry_roundrobin);
}

+struct rpc_xprt *__xprt_switch_find_next_entry_hash(struct rpc_xprt_switch *xps,
+ u32 hash)
+{
+ struct list_head *head = &xps->xps_xprt_list;
+ struct rpc_xprt *pos;
+ const u32 nactive = READ_ONCE(xps->xps_nactive);
+ const u32 xprt_idx = (hash % nactive);
+ u32 idx = 0;
+
+ list_for_each_entry_rcu(pos, head, xprt_switch) {
+ if (xprt_idx > idx++)
+ continue;
+ if (xprt_is_active(pos))
+ return pos;
+ }
+ return NULL;
+}
+
+static
+struct rpc_xprt *xprt_switch_find_next_entry_hash(struct rpc_xprt_switch *xps,
+ u32 hash)
+{
+ struct list_head *head = &xps->xps_xprt_list;
+ struct rpc_xprt *xprt;
+
+ xprt = __xprt_switch_find_next_entry_hash(xps, hash);
+ if (xprt == NULL)
+ xprt = xprt_switch_find_first_entry(head);
+ return xprt;
+}
+
+static
+struct rpc_xprt *xprt_iter_next_entry_hash(struct rpc_xprt_iter *xpi,
+ u32 hash)
+{
+ struct rpc_xprt_switch *xps = rcu_dereference(xpi->xpi_xpswitch);
+
+ if (xps == NULL)
+ return NULL;
+ return xprt_switch_find_next_entry_hash(xps, hash);
+}
+
static
struct rpc_xprt *xprt_switch_find_next_entry_all(struct rpc_xprt_switch *xps,
const struct rpc_xprt *cur)
@@ -366,7 +423,7 @@ struct rpc_xprt *xprt_switch_find_next_entry_all(struct rpc_xprt_switch *xps,
}

static
-struct rpc_xprt *xprt_iter_next_entry_all(struct rpc_xprt_iter *xpi)
+struct rpc_xprt *xprt_iter_next_entry_all(struct rpc_xprt_iter *xpi, u32 hash)
{
return xprt_iter_next_entry_multiple(xpi,
xprt_switch_find_next_entry_all);
@@ -482,6 +539,22 @@ struct rpc_xprt *xprt_iter_get_helper(struct rpc_xprt_iter *xpi,
return ret;
}

+static
+struct rpc_xprt *xprt_iter_get_helper_1(struct rpc_xprt_iter *xpi,
+ struct rpc_xprt *(*fn)(struct rpc_xprt_iter *, u32),
+ u32 arg)
+{
+ struct rpc_xprt *ret;
+
+ do {
+ ret = fn(xpi, arg);
+ if (ret == NULL)
+ break;
+ ret = xprt_get(ret);
+ } while (ret == NULL);
+ return ret;
+}
+
/**
* xprt_iter_get_xprt - Returns the rpc_xprt pointed to by the cursor
* @xpi: pointer to rpc_xprt_iter
@@ -506,12 +579,12 @@ struct rpc_xprt *xprt_iter_get_xprt(struct rpc_xprt_iter *xpi)
* Returns a reference to the struct rpc_xprt that immediately follows the
* entry pointed to by the cursor.
*/
-struct rpc_xprt *xprt_iter_get_next(struct rpc_xprt_iter *xpi)
+struct rpc_xprt *xprt_iter_get_next(struct rpc_xprt_iter *xpi, u32 hash)
{
struct rpc_xprt *xprt;

rcu_read_lock();
- xprt = xprt_iter_get_helper(xpi, xprt_iter_ops(xpi)->xpi_next);
+ xprt = xprt_iter_get_helper_1(xpi, xprt_iter_ops(xpi)->xpi_next, hash);
rcu_read_unlock();
return xprt;
}
@@ -521,7 +594,7 @@ static
const struct rpc_xprt_iter_ops rpc_xprt_iter_singular = {
.xpi_rewind = xprt_iter_no_rewind,
.xpi_xprt = xprt_iter_first_entry,
- .xpi_next = xprt_iter_first_entry,
+ .xpi_next = xprt_iter_next_entry_singular,
};

/* Policy for round-robin iteration of entries in the rpc_xprt_switch */
@@ -532,6 +605,14 @@ const struct rpc_xprt_iter_ops rpc_xprt_iter_roundrobin = {
.xpi_next = xprt_iter_next_entry_roundrobin,
};

+/* Policy for returning a hashed entry from the rpc_xprt_switch */
+static
+const struct rpc_xprt_iter_ops rpc_xprt_iter_hash = {
+ .xpi_rewind = xprt_iter_default_rewind,
+ .xpi_xprt = xprt_iter_current_entry,
+ .xpi_next = xprt_iter_next_entry_hash,
+};
+
/* Policy for once-through iteration of entries in the rpc_xprt_switch */
static
const struct rpc_xprt_iter_ops rpc_xprt_iter_listall = {