Merge branch 'sysfs-devel'
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
This commit is contained in:
commit
526fca3764
|
@ -29,6 +29,7 @@
|
|||
#include <linux/sunrpc/xprtmultipath.h>
|
||||
|
||||
struct rpc_inode;
|
||||
struct rpc_sysfs_client;
|
||||
|
||||
/*
|
||||
* The high-level client handle
|
||||
|
@ -71,6 +72,7 @@ struct rpc_clnt {
|
|||
#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
|
||||
struct dentry *cl_debugfs; /* debugfs directory */
|
||||
#endif
|
||||
struct rpc_sysfs_client *cl_sysfs; /* sysfs directory */
|
||||
/* cl_work is only needed after cl_xpi is no longer used,
|
||||
* and that are of similar size
|
||||
*/
|
||||
|
|
|
@ -53,6 +53,7 @@ enum rpc_display_format_t {
|
|||
|
||||
struct rpc_task;
|
||||
struct rpc_xprt;
|
||||
struct xprt_class;
|
||||
struct seq_file;
|
||||
struct svc_serv;
|
||||
struct net;
|
||||
|
@ -182,9 +183,11 @@ enum xprt_transports {
|
|||
XPRT_TRANSPORT_LOCAL = 257,
|
||||
};
|
||||
|
||||
struct rpc_sysfs_xprt;
|
||||
struct rpc_xprt {
|
||||
struct kref kref; /* Reference count */
|
||||
const struct rpc_xprt_ops *ops; /* transport methods */
|
||||
unsigned int id; /* transport id */
|
||||
|
||||
const struct rpc_timeout *timeout; /* timeout parms */
|
||||
struct sockaddr_storage addr; /* server address */
|
||||
|
@ -288,6 +291,8 @@ struct rpc_xprt {
|
|||
atomic_t inject_disconnect;
|
||||
#endif
|
||||
struct rcu_head rcu;
|
||||
const struct xprt_class *xprt_class;
|
||||
struct rpc_sysfs_xprt *xprt_sysfs;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_SUNRPC_BACKCHANNEL)
|
||||
|
@ -370,6 +375,7 @@ struct rpc_xprt * xprt_alloc(struct net *net, size_t size,
|
|||
void xprt_free(struct rpc_xprt *);
|
||||
void xprt_add_backlog(struct rpc_xprt *xprt, struct rpc_task *task);
|
||||
bool xprt_wake_up_backlog(struct rpc_xprt *xprt, struct rpc_rqst *req);
|
||||
void xprt_cleanup_ids(void);
|
||||
|
||||
static inline int
|
||||
xprt_enable_swap(struct rpc_xprt *xprt)
|
||||
|
@ -408,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
|
||||
|
|
|
@ -10,10 +10,12 @@
|
|||
#define _NET_SUNRPC_XPRTMULTIPATH_H
|
||||
|
||||
struct rpc_xprt_iter_ops;
|
||||
struct rpc_sysfs_xprt_switch;
|
||||
struct rpc_xprt_switch {
|
||||
spinlock_t xps_lock;
|
||||
struct kref xps_kref;
|
||||
|
||||
unsigned int xps_id;
|
||||
unsigned int xps_nxprts;
|
||||
unsigned int xps_nactive;
|
||||
atomic_long_t xps_queuelen;
|
||||
|
@ -23,6 +25,7 @@ struct rpc_xprt_switch {
|
|||
|
||||
const struct rpc_xprt_iter_ops *xps_iter_ops;
|
||||
|
||||
struct rpc_sysfs_xprt_switch *xps_sysfs;
|
||||
struct rcu_head xps_rcu;
|
||||
};
|
||||
|
||||
|
@ -71,4 +74,7 @@ extern struct rpc_xprt *xprt_iter_get_next(struct rpc_xprt_iter *xpi);
|
|||
|
||||
extern bool rpc_xprt_switch_has_addr(struct rpc_xprt_switch *xps,
|
||||
const struct sockaddr *sap);
|
||||
|
||||
extern void xprt_multipath_cleanup_ids(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -12,7 +12,7 @@ sunrpc-y := clnt.o xprt.o socklib.o xprtsock.o sched.o \
|
|||
auth.o auth_null.o auth_unix.o \
|
||||
svc.o svcsock.o svcauth.o svcauth_unix.o \
|
||||
addr.o rpcb_clnt.o timer.o xdr.o \
|
||||
sunrpc_syms.o cache.o rpc_pipe.o \
|
||||
sunrpc_syms.o cache.o rpc_pipe.o sysfs.o \
|
||||
svc_xprt.o \
|
||||
xprtmultipath.o
|
||||
sunrpc-$(CONFIG_SUNRPC_DEBUG) += debugfs.o
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include <trace/events/sunrpc.h>
|
||||
|
||||
#include "sunrpc.h"
|
||||
#include "sysfs.h"
|
||||
#include "netns.h"
|
||||
|
||||
#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
|
||||
|
@ -327,6 +328,7 @@ err_auth:
|
|||
out:
|
||||
if (pipefs_sb)
|
||||
rpc_put_sb_net(net);
|
||||
rpc_sysfs_client_destroy(clnt);
|
||||
rpc_clnt_debugfs_unregister(clnt);
|
||||
return err;
|
||||
}
|
||||
|
@ -423,6 +425,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args,
|
|||
/* save the nodename */
|
||||
rpc_clnt_set_nodename(clnt, nodename);
|
||||
|
||||
rpc_sysfs_client_setup(clnt, xps, rpc_net_ns(clnt));
|
||||
err = rpc_client_register(clnt, args->authflavor, args->client_name);
|
||||
if (err)
|
||||
goto out_no_path;
|
||||
|
@ -733,6 +736,7 @@ int rpc_switch_client_transport(struct rpc_clnt *clnt,
|
|||
|
||||
rpc_unregister_client(clnt);
|
||||
__rpc_clnt_remove_pipedir(clnt);
|
||||
rpc_sysfs_client_destroy(clnt);
|
||||
rpc_clnt_debugfs_unregister(clnt);
|
||||
|
||||
/*
|
||||
|
@ -879,6 +883,7 @@ static void rpc_free_client_work(struct work_struct *work)
|
|||
* so they cannot be called in rpciod, so they are handled separately
|
||||
* here.
|
||||
*/
|
||||
rpc_sysfs_client_destroy(clnt);
|
||||
rpc_clnt_debugfs_unregister(clnt);
|
||||
rpc_free_clid(clnt);
|
||||
rpc_clnt_remove_pipedir(clnt);
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/sunrpc/xprtsock.h>
|
||||
|
||||
#include "sunrpc.h"
|
||||
#include "sysfs.h"
|
||||
#include "netns.h"
|
||||
|
||||
unsigned int sunrpc_net_id;
|
||||
|
@ -103,6 +104,10 @@ init_sunrpc(void)
|
|||
if (err)
|
||||
goto out4;
|
||||
|
||||
err = rpc_sysfs_init();
|
||||
if (err)
|
||||
goto out5;
|
||||
|
||||
sunrpc_debugfs_init();
|
||||
#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
|
||||
rpc_register_sysctl();
|
||||
|
@ -111,6 +116,8 @@ init_sunrpc(void)
|
|||
init_socket_xprt(); /* clnt sock transport */
|
||||
return 0;
|
||||
|
||||
out5:
|
||||
unregister_rpc_pipefs();
|
||||
out4:
|
||||
unregister_pernet_subsys(&sunrpc_net_ops);
|
||||
out3:
|
||||
|
@ -124,7 +131,10 @@ out:
|
|||
static void __exit
|
||||
cleanup_sunrpc(void)
|
||||
{
|
||||
rpc_sysfs_exit();
|
||||
rpc_cleanup_clids();
|
||||
xprt_cleanup_ids();
|
||||
xprt_multipath_cleanup_ids();
|
||||
rpcauth_remove_module();
|
||||
cleanup_socket_xprt();
|
||||
svc_cleanup_xprt_sock();
|
||||
|
|
|
@ -0,0 +1,506 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2020 Anna Schumaker <Anna.Schumaker@Netapp.com>
|
||||
*/
|
||||
#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;
|
||||
|
||||
static void rpc_sysfs_object_release(struct kobject *kobj)
|
||||
{
|
||||
kfree(kobj);
|
||||
}
|
||||
|
||||
static const struct kobj_ns_type_operations *
|
||||
rpc_sysfs_object_child_ns_type(struct kobject *kobj)
|
||||
{
|
||||
return &net_ns_type_operations;
|
||||
}
|
||||
|
||||
static struct kobj_type rpc_sysfs_object_type = {
|
||||
.release = rpc_sysfs_object_release,
|
||||
.sysfs_ops = &kobj_sysfs_ops,
|
||||
.child_ns_type = rpc_sysfs_object_child_ns_type,
|
||||
};
|
||||
|
||||
static struct kobject *rpc_sysfs_object_alloc(const char *name,
|
||||
struct kset *kset,
|
||||
struct kobject *parent)
|
||||
{
|
||||
struct kobject *kobj;
|
||||
|
||||
kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
|
||||
if (kobj) {
|
||||
kobj->kset = kset;
|
||||
if (kobject_init_and_add(kobj, &rpc_sysfs_object_type,
|
||||
parent, "%s", name) == 0)
|
||||
return kobj;
|
||||
kobject_put(kobj);
|
||||
}
|
||||
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 inline struct rpc_xprt_switch *
|
||||
rpc_sysfs_xprt_switch_kobj_get_xprt(struct kobject *kobj)
|
||||
{
|
||||
struct rpc_sysfs_xprt_switch *x = container_of(kobj,
|
||||
struct rpc_sysfs_xprt_switch, kobject);
|
||||
|
||||
return xprt_switch_get(x->xprt_switch);
|
||||
}
|
||||
|
||||
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_info_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, "last_used=%lu\ncur_cong=%lu\ncong_win=%lu\n"
|
||||
"max_num_slots=%u\nmin_num_slots=%u\nnum_reqs=%u\n"
|
||||
"binding_q_len=%u\nsending_q_len=%u\npending_q_len=%u\n"
|
||||
"backlog_q_len=%u\n", xprt->last_used, xprt->cong,
|
||||
xprt->cwnd, xprt->max_reqs, xprt->min_reqs,
|
||||
xprt->num_reqs, xprt->binding.qlen, xprt->sending.qlen,
|
||||
xprt->pending.qlen, xprt->backlog.qlen);
|
||||
xprt_put(xprt);
|
||||
return ret + 1;
|
||||
}
|
||||
|
||||
static ssize_t rpc_sysfs_xprt_state_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
|
||||
ssize_t ret;
|
||||
int locked, connected, connecting, close_wait, bound, binding,
|
||||
closing, congested, cwnd_wait, write_space;
|
||||
|
||||
if (!xprt)
|
||||
return 0;
|
||||
|
||||
if (!xprt->state) {
|
||||
ret = sprintf(buf, "state=CLOSED\n");
|
||||
} else {
|
||||
locked = test_bit(XPRT_LOCKED, &xprt->state);
|
||||
connected = test_bit(XPRT_CONNECTED, &xprt->state);
|
||||
connecting = test_bit(XPRT_CONNECTING, &xprt->state);
|
||||
close_wait = test_bit(XPRT_CLOSE_WAIT, &xprt->state);
|
||||
bound = test_bit(XPRT_BOUND, &xprt->state);
|
||||
binding = test_bit(XPRT_BINDING, &xprt->state);
|
||||
closing = test_bit(XPRT_CLOSING, &xprt->state);
|
||||
congested = test_bit(XPRT_CONGESTED, &xprt->state);
|
||||
cwnd_wait = test_bit(XPRT_CWND_WAIT, &xprt->state);
|
||||
write_space = test_bit(XPRT_WRITE_SPACE, &xprt->state);
|
||||
|
||||
ret = sprintf(buf, "state=%s %s %s %s %s %s %s %s %s %s\n",
|
||||
locked ? "LOCKED" : "",
|
||||
connected ? "CONNECTED" : "",
|
||||
connecting ? "CONNECTING" : "",
|
||||
close_wait ? "CLOSE_WAIT" : "",
|
||||
bound ? "BOUND" : "",
|
||||
binding ? "BOUNDING" : "",
|
||||
closing ? "CLOSING" : "",
|
||||
congested ? "CONGESTED" : "",
|
||||
cwnd_wait ? "CWND_WAIT" : "",
|
||||
write_space ? "WRITE_SPACE" : "");
|
||||
}
|
||||
|
||||
xprt_put(xprt);
|
||||
return ret + 1;
|
||||
}
|
||||
|
||||
static ssize_t rpc_sysfs_xprt_switch_info_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct rpc_xprt_switch *xprt_switch =
|
||||
rpc_sysfs_xprt_switch_kobj_get_xprt(kobj);
|
||||
ssize_t ret;
|
||||
|
||||
if (!xprt_switch)
|
||||
return 0;
|
||||
ret = sprintf(buf, "num_xprts=%u\nnum_active=%u\nqueue_len=%ld\n",
|
||||
xprt_switch->xps_nxprts, xprt_switch->xps_nactive,
|
||||
atomic_long_read(&xprt_switch->xps_queuelen));
|
||||
xprt_switch_put(xprt_switch);
|
||||
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);
|
||||
if (!rpc_sunrpc_kset)
|
||||
return -ENOMEM;
|
||||
rpc_sunrpc_client_kobj =
|
||||
rpc_sysfs_object_alloc("rpc-clients", rpc_sunrpc_kset, NULL);
|
||||
if (!rpc_sunrpc_client_kobj)
|
||||
goto err_client;
|
||||
rpc_sunrpc_xprt_switch_kobj =
|
||||
rpc_sysfs_object_alloc("xprt-switches", rpc_sunrpc_kset, NULL);
|
||||
if (!rpc_sunrpc_xprt_switch_kobj)
|
||||
goto err_switch;
|
||||
return 0;
|
||||
err_switch:
|
||||
kobject_put(rpc_sunrpc_client_kobj);
|
||||
rpc_sunrpc_client_kobj = NULL;
|
||||
err_client:
|
||||
kset_unregister(rpc_sunrpc_kset);
|
||||
rpc_sunrpc_kset = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static void rpc_sysfs_client_release(struct kobject *kobj)
|
||||
{
|
||||
struct rpc_sysfs_client *c;
|
||||
|
||||
c = container_of(kobj, struct rpc_sysfs_client, kobject);
|
||||
kfree(c);
|
||||
}
|
||||
|
||||
static void rpc_sysfs_xprt_switch_release(struct kobject *kobj)
|
||||
{
|
||||
struct rpc_sysfs_xprt_switch *xprt_switch;
|
||||
|
||||
xprt_switch = container_of(kobj, struct rpc_sysfs_xprt_switch, kobject);
|
||||
kfree(xprt_switch);
|
||||
}
|
||||
|
||||
static void rpc_sysfs_xprt_release(struct kobject *kobj)
|
||||
{
|
||||
struct rpc_sysfs_xprt *xprt;
|
||||
|
||||
xprt = container_of(kobj, struct rpc_sysfs_xprt, kobject);
|
||||
kfree(xprt);
|
||||
}
|
||||
|
||||
static const void *rpc_sysfs_client_namespace(struct kobject *kobj)
|
||||
{
|
||||
return container_of(kobj, struct rpc_sysfs_client, kobject)->net;
|
||||
}
|
||||
|
||||
static const void *rpc_sysfs_xprt_switch_namespace(struct kobject *kobj)
|
||||
{
|
||||
return container_of(kobj, struct rpc_sysfs_xprt_switch, kobject)->net;
|
||||
}
|
||||
|
||||
static const void *rpc_sysfs_xprt_namespace(struct kobject *kobj)
|
||||
{
|
||||
return container_of(kobj, struct rpc_sysfs_xprt,
|
||||
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 kobj_attribute rpc_sysfs_xprt_info = __ATTR(xprt_info,
|
||||
0444, rpc_sysfs_xprt_info_show, NULL);
|
||||
|
||||
static struct kobj_attribute rpc_sysfs_xprt_change_state = __ATTR(xprt_state,
|
||||
0644, rpc_sysfs_xprt_state_show, NULL);
|
||||
|
||||
static struct attribute *rpc_sysfs_xprt_attrs[] = {
|
||||
&rpc_sysfs_xprt_dstaddr.attr,
|
||||
&rpc_sysfs_xprt_info.attr,
|
||||
&rpc_sysfs_xprt_change_state.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct kobj_attribute rpc_sysfs_xprt_switch_info =
|
||||
__ATTR(xprt_switch_info, 0444, rpc_sysfs_xprt_switch_info_show, NULL);
|
||||
|
||||
static struct attribute *rpc_sysfs_xprt_switch_attrs[] = {
|
||||
&rpc_sysfs_xprt_switch_info.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct kobj_type rpc_sysfs_client_type = {
|
||||
.release = rpc_sysfs_client_release,
|
||||
.sysfs_ops = &kobj_sysfs_ops,
|
||||
.namespace = rpc_sysfs_client_namespace,
|
||||
};
|
||||
|
||||
static struct kobj_type rpc_sysfs_xprt_switch_type = {
|
||||
.release = rpc_sysfs_xprt_switch_release,
|
||||
.default_attrs = rpc_sysfs_xprt_switch_attrs,
|
||||
.sysfs_ops = &kobj_sysfs_ops,
|
||||
.namespace = rpc_sysfs_xprt_switch_namespace,
|
||||
};
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
void rpc_sysfs_exit(void)
|
||||
{
|
||||
kobject_put(rpc_sunrpc_client_kobj);
|
||||
kobject_put(rpc_sunrpc_xprt_switch_kobj);
|
||||
kset_unregister(rpc_sunrpc_kset);
|
||||
}
|
||||
|
||||
static struct rpc_sysfs_client *rpc_sysfs_client_alloc(struct kobject *parent,
|
||||
struct net *net,
|
||||
int clid)
|
||||
{
|
||||
struct rpc_sysfs_client *p;
|
||||
|
||||
p = kzalloc(sizeof(*p), GFP_KERNEL);
|
||||
if (p) {
|
||||
p->net = net;
|
||||
p->kobject.kset = rpc_sunrpc_kset;
|
||||
if (kobject_init_and_add(&p->kobject, &rpc_sysfs_client_type,
|
||||
parent, "clnt-%d", clid) == 0)
|
||||
return p;
|
||||
kobject_put(&p->kobject);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct rpc_sysfs_xprt_switch *
|
||||
rpc_sysfs_xprt_switch_alloc(struct kobject *parent,
|
||||
struct rpc_xprt_switch *xprt_switch,
|
||||
struct net *net,
|
||||
gfp_t gfp_flags)
|
||||
{
|
||||
struct rpc_sysfs_xprt_switch *p;
|
||||
|
||||
p = kzalloc(sizeof(*p), gfp_flags);
|
||||
if (p) {
|
||||
p->net = net;
|
||||
p->kobject.kset = rpc_sunrpc_kset;
|
||||
if (kobject_init_and_add(&p->kobject,
|
||||
&rpc_sysfs_xprt_switch_type,
|
||||
parent, "switch-%d",
|
||||
xprt_switch->xps_id) == 0)
|
||||
return p;
|
||||
kobject_put(&p->kobject);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct rpc_sysfs_xprt *rpc_sysfs_xprt_alloc(struct kobject *parent,
|
||||
struct rpc_xprt *xprt,
|
||||
gfp_t gfp_flags)
|
||||
{
|
||||
struct rpc_sysfs_xprt *p;
|
||||
|
||||
p = kzalloc(sizeof(*p), gfp_flags);
|
||||
if (!p)
|
||||
goto out;
|
||||
p->kobject.kset = rpc_sunrpc_kset;
|
||||
if (kobject_init_and_add(&p->kobject, &rpc_sysfs_xprt_type,
|
||||
parent, "xprt-%d-%s", xprt->id,
|
||||
xprt->address_strings[RPC_DISPLAY_PROTO]) == 0)
|
||||
return p;
|
||||
kobject_put(&p->kobject);
|
||||
out:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void rpc_sysfs_client_setup(struct rpc_clnt *clnt,
|
||||
struct rpc_xprt_switch *xprt_switch,
|
||||
struct net *net)
|
||||
{
|
||||
struct rpc_sysfs_client *rpc_client;
|
||||
|
||||
rpc_client = rpc_sysfs_client_alloc(rpc_sunrpc_client_kobj,
|
||||
net, clnt->cl_clid);
|
||||
if (rpc_client) {
|
||||
char name[] = "switch";
|
||||
struct rpc_sysfs_xprt_switch *xswitch =
|
||||
(struct rpc_sysfs_xprt_switch *)xprt_switch->xps_sysfs;
|
||||
int ret;
|
||||
|
||||
clnt->cl_sysfs = rpc_client;
|
||||
rpc_client->clnt = clnt;
|
||||
rpc_client->xprt_switch = xprt_switch;
|
||||
kobject_uevent(&rpc_client->kobject, KOBJ_ADD);
|
||||
ret = sysfs_create_link_nowarn(&rpc_client->kobject,
|
||||
&xswitch->kobject, name);
|
||||
if (ret)
|
||||
pr_warn("can't create link to %s in sysfs (%d)\n",
|
||||
name, ret);
|
||||
}
|
||||
}
|
||||
|
||||
void rpc_sysfs_xprt_switch_setup(struct rpc_xprt_switch *xprt_switch,
|
||||
struct rpc_xprt *xprt,
|
||||
gfp_t gfp_flags)
|
||||
{
|
||||
struct rpc_sysfs_xprt_switch *rpc_xprt_switch;
|
||||
struct net *net;
|
||||
|
||||
if (xprt_switch->xps_net)
|
||||
net = xprt_switch->xps_net;
|
||||
else
|
||||
net = xprt->xprt_net;
|
||||
rpc_xprt_switch =
|
||||
rpc_sysfs_xprt_switch_alloc(rpc_sunrpc_xprt_switch_kobj,
|
||||
xprt_switch, net, gfp_flags);
|
||||
if (rpc_xprt_switch) {
|
||||
xprt_switch->xps_sysfs = rpc_xprt_switch;
|
||||
rpc_xprt_switch->xprt_switch = xprt_switch;
|
||||
rpc_xprt_switch->xprt = xprt;
|
||||
kobject_uevent(&rpc_xprt_switch->kobject, KOBJ_ADD);
|
||||
}
|
||||
}
|
||||
|
||||
void rpc_sysfs_xprt_setup(struct rpc_xprt_switch *xprt_switch,
|
||||
struct rpc_xprt *xprt,
|
||||
gfp_t gfp_flags)
|
||||
{
|
||||
struct rpc_sysfs_xprt *rpc_xprt;
|
||||
struct rpc_sysfs_xprt_switch *switch_obj =
|
||||
(struct rpc_sysfs_xprt_switch *)xprt_switch->xps_sysfs;
|
||||
|
||||
rpc_xprt = rpc_sysfs_xprt_alloc(&switch_obj->kobject, xprt, gfp_flags);
|
||||
if (rpc_xprt) {
|
||||
xprt->xprt_sysfs = rpc_xprt;
|
||||
rpc_xprt->xprt = xprt;
|
||||
kobject_uevent(&rpc_xprt->kobject, KOBJ_ADD);
|
||||
}
|
||||
}
|
||||
|
||||
void rpc_sysfs_client_destroy(struct rpc_clnt *clnt)
|
||||
{
|
||||
struct rpc_sysfs_client *rpc_client = clnt->cl_sysfs;
|
||||
|
||||
if (rpc_client) {
|
||||
char name[] = "switch";
|
||||
|
||||
sysfs_remove_link(&rpc_client->kobject, name);
|
||||
kobject_uevent(&rpc_client->kobject, KOBJ_REMOVE);
|
||||
kobject_del(&rpc_client->kobject);
|
||||
kobject_put(&rpc_client->kobject);
|
||||
clnt->cl_sysfs = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void rpc_sysfs_xprt_switch_destroy(struct rpc_xprt_switch *xprt_switch)
|
||||
{
|
||||
struct rpc_sysfs_xprt_switch *rpc_xprt_switch = xprt_switch->xps_sysfs;
|
||||
|
||||
if (rpc_xprt_switch) {
|
||||
kobject_uevent(&rpc_xprt_switch->kobject, KOBJ_REMOVE);
|
||||
kobject_del(&rpc_xprt_switch->kobject);
|
||||
kobject_put(&rpc_xprt_switch->kobject);
|
||||
xprt_switch->xps_sysfs = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void rpc_sysfs_xprt_destroy(struct rpc_xprt *xprt)
|
||||
{
|
||||
struct rpc_sysfs_xprt *rpc_xprt = xprt->xprt_sysfs;
|
||||
|
||||
if (rpc_xprt) {
|
||||
kobject_uevent(&rpc_xprt->kobject, KOBJ_REMOVE);
|
||||
kobject_del(&rpc_xprt->kobject);
|
||||
kobject_put(&rpc_xprt->kobject);
|
||||
xprt->xprt_sysfs = NULL;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2020 Anna Schumaker <Anna.Schumaker@Netapp.com>
|
||||
*/
|
||||
#ifndef __SUNRPC_SYSFS_H
|
||||
#define __SUNRPC_SYSFS_H
|
||||
|
||||
struct rpc_sysfs_client {
|
||||
struct kobject kobject;
|
||||
struct net *net;
|
||||
struct rpc_clnt *clnt;
|
||||
struct rpc_xprt_switch *xprt_switch;
|
||||
};
|
||||
|
||||
struct rpc_sysfs_xprt_switch {
|
||||
struct kobject kobject;
|
||||
struct net *net;
|
||||
struct rpc_xprt_switch *xprt_switch;
|
||||
struct rpc_xprt *xprt;
|
||||
};
|
||||
|
||||
struct rpc_sysfs_xprt {
|
||||
struct kobject kobject;
|
||||
struct rpc_xprt *xprt;
|
||||
};
|
||||
|
||||
int rpc_sysfs_init(void);
|
||||
void rpc_sysfs_exit(void);
|
||||
|
||||
void rpc_sysfs_client_setup(struct rpc_clnt *clnt,
|
||||
struct rpc_xprt_switch *xprt_switch,
|
||||
struct net *net);
|
||||
void rpc_sysfs_client_destroy(struct rpc_clnt *clnt);
|
||||
void rpc_sysfs_xprt_switch_setup(struct rpc_xprt_switch *xprt_switch,
|
||||
struct rpc_xprt *xprt, gfp_t gfp_flags);
|
||||
void rpc_sysfs_xprt_switch_destroy(struct rpc_xprt_switch *xprt);
|
||||
void rpc_sysfs_xprt_setup(struct rpc_xprt_switch *xprt_switch,
|
||||
struct rpc_xprt *xprt, gfp_t gfp_flags);
|
||||
void rpc_sysfs_xprt_destroy(struct rpc_xprt *xprt);
|
||||
|
||||
#endif
|
|
@ -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;
|
||||
|
@ -1746,6 +1747,30 @@ static void xprt_free_all_slots(struct rpc_xprt *xprt)
|
|||
}
|
||||
}
|
||||
|
||||
static DEFINE_IDA(rpc_xprt_ids);
|
||||
|
||||
void xprt_cleanup_ids(void)
|
||||
{
|
||||
ida_destroy(&rpc_xprt_ids);
|
||||
}
|
||||
|
||||
static int xprt_alloc_id(struct rpc_xprt *xprt)
|
||||
{
|
||||
int id;
|
||||
|
||||
id = ida_simple_get(&rpc_xprt_ids, 0, 0, GFP_KERNEL);
|
||||
if (id < 0)
|
||||
return id;
|
||||
|
||||
xprt->id = id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xprt_free_id(struct rpc_xprt *xprt)
|
||||
{
|
||||
ida_simple_remove(&rpc_xprt_ids, xprt->id);
|
||||
}
|
||||
|
||||
struct rpc_xprt *xprt_alloc(struct net *net, size_t size,
|
||||
unsigned int num_prealloc,
|
||||
unsigned int max_alloc)
|
||||
|
@ -1758,6 +1783,7 @@ struct rpc_xprt *xprt_alloc(struct net *net, size_t size,
|
|||
if (xprt == NULL)
|
||||
goto out;
|
||||
|
||||
xprt_alloc_id(xprt);
|
||||
xprt_init(xprt, net);
|
||||
|
||||
for (i = 0; i < num_prealloc; i++) {
|
||||
|
@ -1786,6 +1812,8 @@ 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);
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
#include <linux/sunrpc/addr.h>
|
||||
#include <linux/sunrpc/xprtmultipath.h>
|
||||
|
||||
#include "sysfs.h"
|
||||
|
||||
typedef struct rpc_xprt *(*xprt_switch_find_xprt_t)(struct rpc_xprt_switch *xps,
|
||||
const struct rpc_xprt *cur);
|
||||
|
||||
|
@ -55,6 +57,7 @@ void rpc_xprt_switch_add_xprt(struct rpc_xprt_switch *xps,
|
|||
if (xps->xps_net == xprt->xprt_net || xps->xps_net == NULL)
|
||||
xprt_switch_add_xprt_locked(xps, xprt);
|
||||
spin_unlock(&xps->xps_lock);
|
||||
rpc_sysfs_xprt_setup(xps, xprt, GFP_KERNEL);
|
||||
}
|
||||
|
||||
static void xprt_switch_remove_xprt_locked(struct rpc_xprt_switch *xps,
|
||||
|
@ -86,6 +89,30 @@ void rpc_xprt_switch_remove_xprt(struct rpc_xprt_switch *xps,
|
|||
xprt_put(xprt);
|
||||
}
|
||||
|
||||
static DEFINE_IDA(rpc_xprtswitch_ids);
|
||||
|
||||
void xprt_multipath_cleanup_ids(void)
|
||||
{
|
||||
ida_destroy(&rpc_xprtswitch_ids);
|
||||
}
|
||||
|
||||
static int xprt_switch_alloc_id(struct rpc_xprt_switch *xps, gfp_t gfp_flags)
|
||||
{
|
||||
int id;
|
||||
|
||||
id = ida_simple_get(&rpc_xprtswitch_ids, 0, 0, gfp_flags);
|
||||
if (id < 0)
|
||||
return id;
|
||||
|
||||
xps->xps_id = id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xprt_switch_free_id(struct rpc_xprt_switch *xps)
|
||||
{
|
||||
ida_simple_remove(&rpc_xprtswitch_ids, xps->xps_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* xprt_switch_alloc - Allocate a new struct rpc_xprt_switch
|
||||
* @xprt: pointer to struct rpc_xprt
|
||||
|
@ -103,12 +130,15 @@ struct rpc_xprt_switch *xprt_switch_alloc(struct rpc_xprt *xprt,
|
|||
if (xps != NULL) {
|
||||
spin_lock_init(&xps->xps_lock);
|
||||
kref_init(&xps->xps_kref);
|
||||
xprt_switch_alloc_id(xps, gfp_flags);
|
||||
xps->xps_nxprts = xps->xps_nactive = 0;
|
||||
atomic_long_set(&xps->xps_queuelen, 0);
|
||||
xps->xps_net = NULL;
|
||||
INIT_LIST_HEAD(&xps->xps_xprt_list);
|
||||
xps->xps_iter_ops = &rpc_xprt_iter_singular;
|
||||
rpc_sysfs_xprt_switch_setup(xps, xprt, gfp_flags);
|
||||
xprt_switch_add_xprt_locked(xps, xprt);
|
||||
rpc_sysfs_xprt_setup(xps, xprt, gfp_flags);
|
||||
}
|
||||
|
||||
return xps;
|
||||
|
@ -136,6 +166,8 @@ static void xprt_switch_free(struct kref *kref)
|
|||
struct rpc_xprt_switch, xps_kref);
|
||||
|
||||
xprt_switch_free_entries(xps);
|
||||
rpc_sysfs_xprt_switch_destroy(xps);
|
||||
xprt_switch_free_id(xps);
|
||||
kfree_rcu(xps, xps_rcu);
|
||||
}
|
||||
|
||||
|
|
|
@ -73,6 +73,7 @@ unsigned int xprt_rdma_max_inline_read = RPCRDMA_DEF_INLINE;
|
|||
unsigned int xprt_rdma_max_inline_write = RPCRDMA_DEF_INLINE;
|
||||
unsigned int xprt_rdma_memreg_strategy = RPCRDMA_FRWR;
|
||||
int xprt_rdma_pad_optimize;
|
||||
static struct xprt_class xprt_rdma;
|
||||
|
||||
#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
|
||||
|
||||
|
@ -349,6 +350,7 @@ xprt_setup_rdma(struct xprt_create *args)
|
|||
/* Ensure xprt->addr holds valid server TCP (not RDMA)
|
||||
* address, for any side protocols which peek at it */
|
||||
xprt->prot = IPPROTO_TCP;
|
||||
xprt->xprt_class = &xprt_rdma;
|
||||
xprt->addrlen = args->addrlen;
|
||||
memcpy(&xprt->addr, sap, xprt->addrlen);
|
||||
|
||||
|
|
|
@ -91,6 +91,11 @@ static unsigned int xprt_max_resvport_limit = RPC_MAX_RESVPORT;
|
|||
|
||||
static struct ctl_table_header *sunrpc_table_header;
|
||||
|
||||
static struct xprt_class xs_local_transport;
|
||||
static struct xprt_class xs_udp_transport;
|
||||
static struct xprt_class xs_tcp_transport;
|
||||
static struct xprt_class xs_bc_tcp_transport;
|
||||
|
||||
/*
|
||||
* FIXME: changing the UDP slot table size should also resize the UDP
|
||||
* socket buffers for existing UDP transports
|
||||
|
@ -2780,6 +2785,7 @@ static struct rpc_xprt *xs_setup_local(struct xprt_create *args)
|
|||
transport = container_of(xprt, struct sock_xprt, xprt);
|
||||
|
||||
xprt->prot = 0;
|
||||
xprt->xprt_class = &xs_local_transport;
|
||||
xprt->max_payload = RPC_MAX_FRAGMENT_SIZE;
|
||||
|
||||
xprt->bind_timeout = XS_BIND_TO;
|
||||
|
@ -2849,6 +2855,7 @@ static struct rpc_xprt *xs_setup_udp(struct xprt_create *args)
|
|||
transport = container_of(xprt, struct sock_xprt, xprt);
|
||||
|
||||
xprt->prot = IPPROTO_UDP;
|
||||
xprt->xprt_class = &xs_udp_transport;
|
||||
/* XXX: header size can vary due to auth type, IPv6, etc. */
|
||||
xprt->max_payload = (1U << 16) - (MAX_HEADER << 3);
|
||||
|
||||
|
@ -2929,6 +2936,7 @@ static struct rpc_xprt *xs_setup_tcp(struct xprt_create *args)
|
|||
transport = container_of(xprt, struct sock_xprt, xprt);
|
||||
|
||||
xprt->prot = IPPROTO_TCP;
|
||||
xprt->xprt_class = &xs_tcp_transport;
|
||||
xprt->max_payload = RPC_MAX_FRAGMENT_SIZE;
|
||||
|
||||
xprt->bind_timeout = XS_BIND_TO;
|
||||
|
@ -3002,6 +3010,7 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
|
|||
transport = container_of(xprt, struct sock_xprt, xprt);
|
||||
|
||||
xprt->prot = IPPROTO_TCP;
|
||||
xprt->xprt_class = &xs_bc_tcp_transport;
|
||||
xprt->max_payload = RPC_MAX_FRAGMENT_SIZE;
|
||||
xprt->timeout = &xs_tcp_default_timeout;
|
||||
|
||||
|
|
Loading…
Reference in New Issue