Commit 587bc725 authored by Olga Kornievskaia's avatar Olga Kornievskaia Committed by Trond Myklebust
Browse files

sunrpc: add dst_attr attributes to the sysfs xprt directory



Allow to query and set the destination's address of a transport.
Setting of the destination address is allowed only for TCP or RDMA
based connections.

Signed-off-by: default avatarOlga Kornievskaia <kolga@netapp.com>
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
parent d408ebe0
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -414,6 +414,7 @@ void xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie);

bool			xprt_lock_connect(struct rpc_xprt *, struct rpc_task *, void *);
void			xprt_unlock_connect(struct rpc_xprt *, void *);
void			xprt_release_write(struct rpc_xprt *, struct rpc_task *);

/*
 * Reserved bit positions in xprt->state
+105 −0
Original line number Diff line number Diff line
@@ -4,8 +4,23 @@
 */
#include <linux/sunrpc/clnt.h>
#include <linux/kobject.h>
#include <linux/sunrpc/addr.h>

#include "sysfs.h"

struct xprt_addr {
	const char *addr;
	struct rcu_head rcu;
};

static void free_xprt_addr(struct rcu_head *head)
{
	struct xprt_addr *addr = container_of(head, struct xprt_addr, rcu);

	kfree(addr->addr);
	kfree(addr);
}

static struct kset *rpc_sunrpc_kset;
static struct kobject *rpc_sunrpc_client_kobj, *rpc_sunrpc_xprt_switch_kobj;

@@ -43,6 +58,87 @@ static struct kobject *rpc_sysfs_object_alloc(const char *name,
	return NULL;
}

static inline struct rpc_xprt *
rpc_sysfs_xprt_kobj_get_xprt(struct kobject *kobj)
{
	struct rpc_sysfs_xprt *x = container_of(kobj,
		struct rpc_sysfs_xprt, kobject);

	return xprt_get(x->xprt);
}

static ssize_t rpc_sysfs_xprt_dstaddr_show(struct kobject *kobj,
					   struct kobj_attribute *attr,
					   char *buf)
{
	struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
	ssize_t ret;

	if (!xprt)
		return 0;
	ret = sprintf(buf, "%s\n", xprt->address_strings[RPC_DISPLAY_ADDR]);
	xprt_put(xprt);
	return ret + 1;
}

static ssize_t rpc_sysfs_xprt_dstaddr_store(struct kobject *kobj,
					    struct kobj_attribute *attr,
					    const char *buf, size_t count)
{
	struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
	struct sockaddr *saddr;
	char *dst_addr;
	int port;
	struct xprt_addr *saved_addr;
	size_t buf_len;

	if (!xprt)
		return 0;
	if (!(xprt->xprt_class->ident == XPRT_TRANSPORT_TCP ||
	      xprt->xprt_class->ident == XPRT_TRANSPORT_RDMA)) {
		xprt_put(xprt);
		return -EOPNOTSUPP;
	}

	if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE)) {
		count = -EINTR;
		goto out_put;
	}
	saddr = (struct sockaddr *)&xprt->addr;
	port = rpc_get_port(saddr);

	/* buf_len is the len until the first occurence of either
	 * '\n' or '\0'
	 */
	buf_len = strcspn(buf, "\n");

	dst_addr = kstrndup(buf, buf_len, GFP_KERNEL);
	if (!dst_addr)
		goto out_err;
	saved_addr = kzalloc(sizeof(*saved_addr), GFP_KERNEL);
	if (!saved_addr)
		goto out_err_free;
	saved_addr->addr =
		rcu_dereference_raw(xprt->address_strings[RPC_DISPLAY_ADDR]);
	rcu_assign_pointer(xprt->address_strings[RPC_DISPLAY_ADDR], dst_addr);
	call_rcu(&saved_addr->rcu, free_xprt_addr);
	xprt->addrlen = rpc_pton(xprt->xprt_net, buf, buf_len, saddr,
				 sizeof(*saddr));
	rpc_set_port(saddr, port);

	xprt_force_disconnect(xprt);
out:
	xprt_release_write(xprt, NULL);
out_put:
	xprt_put(xprt);
	return count;
out_err_free:
	kfree(dst_addr);
out_err:
	count = -ENOMEM;
	goto out;
}

int rpc_sysfs_init(void)
{
	rpc_sunrpc_kset = kset_create_and_add("sunrpc", NULL, kernel_kobj);
@@ -106,6 +202,14 @@ static const void *rpc_sysfs_xprt_namespace(struct kobject *kobj)
			    kobject)->xprt->xprt_net;
}

static struct kobj_attribute rpc_sysfs_xprt_dstaddr = __ATTR(dstaddr,
	0644, rpc_sysfs_xprt_dstaddr_show, rpc_sysfs_xprt_dstaddr_store);

static struct attribute *rpc_sysfs_xprt_attrs[] = {
	&rpc_sysfs_xprt_dstaddr.attr,
	NULL,
};

static struct kobj_type rpc_sysfs_client_type = {
	.release = rpc_sysfs_client_release,
	.sysfs_ops = &kobj_sysfs_ops,
@@ -120,6 +224,7 @@ static struct kobj_type rpc_sysfs_xprt_switch_type = {

static struct kobj_type rpc_sysfs_xprt_type = {
	.release = rpc_sysfs_xprt_release,
	.default_attrs = rpc_sysfs_xprt_attrs,
	.sysfs_ops = &kobj_sysfs_ops,
	.namespace = rpc_sysfs_xprt_namespace,
};
+3 −1
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@
#include <trace/events/sunrpc.h>

#include "sunrpc.h"
#include "sysfs.h"

/*
 * Local variables
@@ -443,7 +444,7 @@ void xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task)
}
EXPORT_SYMBOL_GPL(xprt_release_xprt_cong);

static inline void xprt_release_write(struct rpc_xprt *xprt, struct rpc_task *task)
void xprt_release_write(struct rpc_xprt *xprt, struct rpc_task *task)
{
	if (xprt->snd_task != task)
		return;
@@ -1812,6 +1813,7 @@ void xprt_free(struct rpc_xprt *xprt)
	put_net(xprt->xprt_net);
	xprt_free_all_slots(xprt);
	xprt_free_id(xprt);
	rpc_sysfs_xprt_destroy(xprt);
	kfree_rcu(xprt, rcu);
}
EXPORT_SYMBOL_GPL(xprt_free);
+0 −2
Original line number Diff line number Diff line
@@ -86,7 +86,6 @@ void rpc_xprt_switch_remove_xprt(struct rpc_xprt_switch *xps,
	spin_lock(&xps->xps_lock);
	xprt_switch_remove_xprt_locked(xps, xprt);
	spin_unlock(&xps->xps_lock);
	rpc_sysfs_xprt_destroy(xprt);
	xprt_put(xprt);
}

@@ -155,7 +154,6 @@ static void xprt_switch_free_entries(struct rpc_xprt_switch *xps)
				struct rpc_xprt, xprt_switch);
		xprt_switch_remove_xprt_locked(xps, xprt);
		spin_unlock(&xps->xps_lock);
		rpc_sysfs_xprt_destroy(xprt);
		xprt_put(xprt);
		spin_lock(&xps->xps_lock);
	}