mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 04:44:45 +01:00
This was done entirely with mindless brute force, using
git grep -l '\<k[vmz]*alloc_objs*(.*, GFP_KERNEL)' |
xargs sed -i 's/\(alloc_objs*(.*\), GFP_KERNEL)/\1)/'
to convert the new alloc_obj() users that had a simple GFP_KERNEL
argument to just drop that argument.
Note that due to the extreme simplicity of the scripting, any slightly
more complex cases spread over multiple lines would not be triggered:
they definitely exist, but this covers the vast bulk of the cases, and
the resulting diff is also then easier to check automatically.
For the same reason the 'flex' versions will be done as a separate
conversion.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
829 lines
21 KiB
C
829 lines
21 KiB
C
// 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 <linux/sunrpc/xprtsock.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(const struct kobject *kobj)
|
|
{
|
|
return &net_ns_type_operations;
|
|
}
|
|
|
|
static const 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_obj(*kobj);
|
|
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_clnt *
|
|
rpc_sysfs_client_kobj_get_clnt(struct kobject *kobj)
|
|
{
|
|
struct rpc_sysfs_client *c = container_of(kobj,
|
|
struct rpc_sysfs_client, kobject);
|
|
struct rpc_clnt *ret = c->clnt;
|
|
|
|
return refcount_inc_not_zero(&ret->cl_count) ? ret : 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_kobj_get_xprt_switch(struct kobject *kobj)
|
|
{
|
|
struct rpc_sysfs_xprt *x = container_of(kobj,
|
|
struct rpc_sysfs_xprt, kobject);
|
|
|
|
return xprt_switch_get(x->xprt_switch);
|
|
}
|
|
|
|
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_clnt_version_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct rpc_clnt *clnt = rpc_sysfs_client_kobj_get_clnt(kobj);
|
|
ssize_t ret;
|
|
|
|
if (!clnt)
|
|
return sprintf(buf, "<closed>\n");
|
|
|
|
ret = sprintf(buf, "%u", clnt->cl_vers);
|
|
refcount_dec(&clnt->cl_count);
|
|
return ret;
|
|
}
|
|
|
|
static ssize_t rpc_sysfs_clnt_program_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct rpc_clnt *clnt = rpc_sysfs_client_kobj_get_clnt(kobj);
|
|
ssize_t ret;
|
|
|
|
if (!clnt)
|
|
return sprintf(buf, "<closed>\n");
|
|
|
|
ret = sprintf(buf, "%s", clnt->cl_program->name);
|
|
refcount_dec(&clnt->cl_count);
|
|
return ret;
|
|
}
|
|
|
|
static ssize_t rpc_sysfs_clnt_max_connect_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct rpc_clnt *clnt = rpc_sysfs_client_kobj_get_clnt(kobj);
|
|
ssize_t ret;
|
|
|
|
if (!clnt)
|
|
return sprintf(buf, "<closed>\n");
|
|
|
|
ret = sprintf(buf, "%u\n", clnt->cl_max_connect);
|
|
refcount_dec(&clnt->cl_count);
|
|
return ret;
|
|
}
|
|
|
|
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) {
|
|
ret = sprintf(buf, "<closed>\n");
|
|
goto out;
|
|
}
|
|
ret = sprintf(buf, "%s\n", xprt->address_strings[RPC_DISPLAY_ADDR]);
|
|
xprt_put(xprt);
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
static ssize_t rpc_sysfs_xprt_srcaddr_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
|
|
size_t buflen = PAGE_SIZE;
|
|
ssize_t ret;
|
|
|
|
if (!xprt || !xprt_connected(xprt)) {
|
|
ret = sprintf(buf, "<closed>\n");
|
|
} else if (xprt->ops->get_srcaddr) {
|
|
ret = xprt->ops->get_srcaddr(xprt, buf, buflen);
|
|
if (ret > 0) {
|
|
if (ret < buflen - 1) {
|
|
buf[ret] = '\n';
|
|
ret++;
|
|
buf[ret] = '\0';
|
|
}
|
|
} else
|
|
ret = sprintf(buf, "<closed>\n");
|
|
} else
|
|
ret = sprintf(buf, "<not a socket>\n");
|
|
xprt_put(xprt);
|
|
return ret;
|
|
}
|
|
|
|
static const char *xprtsec_strings[] = {
|
|
[RPC_XPRTSEC_NONE] = "none",
|
|
[RPC_XPRTSEC_TLS_ANON] = "tls-anon",
|
|
[RPC_XPRTSEC_TLS_X509] = "tls-x509",
|
|
};
|
|
|
|
static ssize_t rpc_sysfs_xprt_xprtsec_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) {
|
|
ret = sprintf(buf, "<closed>\n");
|
|
goto out;
|
|
}
|
|
|
|
ret = sprintf(buf, "%s\n", xprtsec_strings[xprt->xprtsec.policy]);
|
|
xprt_put(xprt);
|
|
out:
|
|
return ret;
|
|
|
|
}
|
|
|
|
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);
|
|
unsigned short srcport = 0;
|
|
size_t buflen = PAGE_SIZE;
|
|
ssize_t ret;
|
|
|
|
if (!xprt || !xprt_connected(xprt)) {
|
|
ret = sprintf(buf, "<closed>\n");
|
|
goto out;
|
|
}
|
|
|
|
if (xprt->ops->get_srcport)
|
|
srcport = xprt->ops->get_srcport(xprt);
|
|
|
|
ret = snprintf(buf, buflen,
|
|
"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\nmain_xprt=%d\nsrc_port=%u\n"
|
|
"tasks_queuelen=%ld\ndst_port=%s\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->main, srcport,
|
|
atomic_long_read(&xprt->queuelen),
|
|
xprt->address_strings[RPC_DISPLAY_PORT]);
|
|
out:
|
|
xprt_put(xprt);
|
|
return ret;
|
|
}
|
|
|
|
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, offline, remove;
|
|
|
|
if (!(xprt && 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);
|
|
offline = test_bit(XPRT_OFFLINE, &xprt->state);
|
|
remove = test_bit(XPRT_REMOVE, &xprt->state);
|
|
|
|
ret = sprintf(buf, "state=%s %s %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" : "",
|
|
offline ? "OFFLINE" : "",
|
|
remove ? "REMOVE" : "");
|
|
}
|
|
|
|
xprt_put(xprt);
|
|
return ret;
|
|
}
|
|
|
|
static ssize_t rpc_sysfs_xprt_del_xprt_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr,
|
|
char *buf)
|
|
{
|
|
return sprintf(buf, "# delete this xprt\n");
|
|
}
|
|
|
|
|
|
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\n"
|
|
"num_unique_destaddr=%u\nqueue_len=%ld\n",
|
|
xprt_switch->xps_nxprts, xprt_switch->xps_nactive,
|
|
xprt_switch->xps_nunique_destaddr_xprts,
|
|
atomic_long_read(&xprt_switch->xps_queuelen));
|
|
xprt_switch_put(xprt_switch);
|
|
return ret;
|
|
}
|
|
|
|
static ssize_t rpc_sysfs_xprt_switch_add_xprt_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr,
|
|
char *buf)
|
|
{
|
|
return sprintf(buf, "# add one xprt to this xprt_switch\n");
|
|
}
|
|
|
|
static ssize_t rpc_sysfs_xprt_switch_add_xprt_store(struct kobject *kobj,
|
|
struct kobj_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
struct rpc_xprt_switch *xprt_switch =
|
|
rpc_sysfs_xprt_switch_kobj_get_xprt(kobj);
|
|
struct xprt_create xprt_create_args;
|
|
struct rpc_xprt *xprt, *new;
|
|
|
|
if (!xprt_switch)
|
|
return 0;
|
|
|
|
xprt = rpc_xprt_switch_get_main_xprt(xprt_switch);
|
|
if (!xprt)
|
|
goto out;
|
|
|
|
xprt_create_args.ident = xprt->xprt_class->ident;
|
|
xprt_create_args.net = xprt->xprt_net;
|
|
xprt_create_args.dstaddr = (struct sockaddr *)&xprt->addr;
|
|
xprt_create_args.addrlen = xprt->addrlen;
|
|
xprt_create_args.servername = xprt->servername;
|
|
xprt_create_args.bc_xprt = xprt->bc_xprt;
|
|
xprt_create_args.xprtsec = xprt->xprtsec;
|
|
xprt_create_args.connect_timeout = xprt->connect_timeout;
|
|
xprt_create_args.reconnect_timeout = xprt->max_reconnect_timeout;
|
|
|
|
new = xprt_create_transport(&xprt_create_args);
|
|
if (IS_ERR_OR_NULL(new)) {
|
|
count = PTR_ERR(new);
|
|
goto out_put_xprt;
|
|
}
|
|
|
|
rpc_xprt_switch_add_xprt(xprt_switch, new);
|
|
xprt_put(new);
|
|
|
|
out_put_xprt:
|
|
xprt_put(xprt);
|
|
out:
|
|
xprt_switch_put(xprt_switch);
|
|
return count;
|
|
}
|
|
|
|
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_TCP_TLS ||
|
|
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 occurrence 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_obj(*saved_addr);
|
|
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;
|
|
}
|
|
|
|
static ssize_t rpc_sysfs_xprt_state_change(struct kobject *kobj,
|
|
struct kobj_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
|
|
int offline = 0, online = 0, remove = 0;
|
|
struct rpc_xprt_switch *xps = rpc_sysfs_xprt_kobj_get_xprt_switch(kobj);
|
|
|
|
if (!xprt || !xps) {
|
|
count = 0;
|
|
goto out_put;
|
|
}
|
|
|
|
if (!strncmp(buf, "offline", 7))
|
|
offline = 1;
|
|
else if (!strncmp(buf, "online", 6))
|
|
online = 1;
|
|
else if (!strncmp(buf, "remove", 6))
|
|
remove = 1;
|
|
else {
|
|
count = -EINVAL;
|
|
goto out_put;
|
|
}
|
|
|
|
if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE)) {
|
|
count = -EINTR;
|
|
goto out_put;
|
|
}
|
|
if (xprt->main) {
|
|
count = -EINVAL;
|
|
goto release_tasks;
|
|
}
|
|
if (offline) {
|
|
xprt_set_offline_locked(xprt, xps);
|
|
} else if (online) {
|
|
xprt_set_online_locked(xprt, xps);
|
|
} else if (remove) {
|
|
if (test_bit(XPRT_OFFLINE, &xprt->state))
|
|
xprt_delete_locked(xprt, xps);
|
|
else
|
|
count = -EINVAL;
|
|
}
|
|
|
|
release_tasks:
|
|
xprt_release_write(xprt, NULL);
|
|
out_put:
|
|
xprt_put(xprt);
|
|
xprt_switch_put(xps);
|
|
return count;
|
|
}
|
|
|
|
static ssize_t rpc_sysfs_xprt_del_xprt(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 rpc_xprt_switch *xps = rpc_sysfs_xprt_kobj_get_xprt_switch(kobj);
|
|
|
|
if (!xprt || !xps) {
|
|
count = 0;
|
|
goto out;
|
|
}
|
|
|
|
if (xprt->main) {
|
|
count = -EINVAL;
|
|
goto release_tasks;
|
|
}
|
|
|
|
if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE)) {
|
|
count = -EINTR;
|
|
goto out_put;
|
|
}
|
|
|
|
xprt_set_offline_locked(xprt, xps);
|
|
xprt_delete_locked(xprt, xps);
|
|
|
|
release_tasks:
|
|
xprt_release_write(xprt, NULL);
|
|
out_put:
|
|
xprt_put(xprt);
|
|
xprt_switch_put(xps);
|
|
out:
|
|
return count;
|
|
}
|
|
|
|
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(const struct kobject *kobj)
|
|
{
|
|
return container_of(kobj, struct rpc_sysfs_client, kobject)->net;
|
|
}
|
|
|
|
static const void *rpc_sysfs_xprt_switch_namespace(const struct kobject *kobj)
|
|
{
|
|
return container_of(kobj, struct rpc_sysfs_xprt_switch, kobject)->net;
|
|
}
|
|
|
|
static const void *rpc_sysfs_xprt_namespace(const struct kobject *kobj)
|
|
{
|
|
return container_of(kobj, struct rpc_sysfs_xprt,
|
|
kobject)->xprt->xprt_net;
|
|
}
|
|
|
|
static struct kobj_attribute rpc_sysfs_clnt_version = __ATTR(rpc_version,
|
|
0444, rpc_sysfs_clnt_version_show, NULL);
|
|
|
|
static struct kobj_attribute rpc_sysfs_clnt_program = __ATTR(program,
|
|
0444, rpc_sysfs_clnt_program_show, NULL);
|
|
|
|
static struct kobj_attribute rpc_sysfs_clnt_max_connect = __ATTR(max_connect,
|
|
0444, rpc_sysfs_clnt_max_connect_show, NULL);
|
|
|
|
static struct attribute *rpc_sysfs_rpc_clnt_attrs[] = {
|
|
&rpc_sysfs_clnt_version.attr,
|
|
&rpc_sysfs_clnt_program.attr,
|
|
&rpc_sysfs_clnt_max_connect.attr,
|
|
NULL,
|
|
};
|
|
ATTRIBUTE_GROUPS(rpc_sysfs_rpc_clnt);
|
|
|
|
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_srcaddr = __ATTR(srcaddr,
|
|
0644, rpc_sysfs_xprt_srcaddr_show, NULL);
|
|
|
|
static struct kobj_attribute rpc_sysfs_xprt_xprtsec = __ATTR(xprtsec,
|
|
0644, rpc_sysfs_xprt_xprtsec_show, NULL);
|
|
|
|
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, rpc_sysfs_xprt_state_change);
|
|
|
|
static struct kobj_attribute rpc_sysfs_xprt_del = __ATTR(del_xprt,
|
|
0644, rpc_sysfs_xprt_del_xprt_show, rpc_sysfs_xprt_del_xprt);
|
|
|
|
static struct attribute *rpc_sysfs_xprt_attrs[] = {
|
|
&rpc_sysfs_xprt_dstaddr.attr,
|
|
&rpc_sysfs_xprt_srcaddr.attr,
|
|
&rpc_sysfs_xprt_xprtsec.attr,
|
|
&rpc_sysfs_xprt_info.attr,
|
|
&rpc_sysfs_xprt_change_state.attr,
|
|
&rpc_sysfs_xprt_del.attr,
|
|
NULL,
|
|
};
|
|
ATTRIBUTE_GROUPS(rpc_sysfs_xprt);
|
|
|
|
static struct kobj_attribute rpc_sysfs_xprt_switch_info =
|
|
__ATTR(xprt_switch_info, 0444, rpc_sysfs_xprt_switch_info_show, NULL);
|
|
|
|
static struct kobj_attribute rpc_sysfs_xprt_switch_add_xprt =
|
|
__ATTR(add_xprt, 0644, rpc_sysfs_xprt_switch_add_xprt_show,
|
|
rpc_sysfs_xprt_switch_add_xprt_store);
|
|
|
|
static struct attribute *rpc_sysfs_xprt_switch_attrs[] = {
|
|
&rpc_sysfs_xprt_switch_info.attr,
|
|
&rpc_sysfs_xprt_switch_add_xprt.attr,
|
|
NULL,
|
|
};
|
|
ATTRIBUTE_GROUPS(rpc_sysfs_xprt_switch);
|
|
|
|
static const struct kobj_type rpc_sysfs_client_type = {
|
|
.release = rpc_sysfs_client_release,
|
|
.default_groups = rpc_sysfs_rpc_clnt_groups,
|
|
.sysfs_ops = &kobj_sysfs_ops,
|
|
.namespace = rpc_sysfs_client_namespace,
|
|
};
|
|
|
|
static const struct kobj_type rpc_sysfs_xprt_switch_type = {
|
|
.release = rpc_sysfs_xprt_switch_release,
|
|
.default_groups = rpc_sysfs_xprt_switch_groups,
|
|
.sysfs_ops = &kobj_sysfs_ops,
|
|
.namespace = rpc_sysfs_xprt_switch_namespace,
|
|
};
|
|
|
|
static const struct kobj_type rpc_sysfs_xprt_type = {
|
|
.release = rpc_sysfs_xprt_release,
|
|
.default_groups = rpc_sysfs_xprt_groups,
|
|
.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_obj(*p);
|
|
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_obj(*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_obj(*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;
|
|
struct rpc_sysfs_xprt_switch *xswitch =
|
|
(struct rpc_sysfs_xprt_switch *)xprt_switch->xps_sysfs;
|
|
|
|
if (!xswitch)
|
|
return;
|
|
|
|
rpc_client = rpc_sysfs_client_alloc(rpc_sunrpc_client_kobj,
|
|
net, clnt->cl_clid);
|
|
if (rpc_client) {
|
|
char name[] = "switch";
|
|
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);
|
|
} else {
|
|
xprt_switch->xps_sysfs = NULL;
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
if (!switch_obj)
|
|
return;
|
|
|
|
rpc_xprt = rpc_sysfs_xprt_alloc(&switch_obj->kobject, xprt, gfp_flags);
|
|
if (rpc_xprt) {
|
|
xprt->xprt_sysfs = rpc_xprt;
|
|
rpc_xprt->xprt = xprt;
|
|
rpc_xprt->xprt_switch = xprt_switch;
|
|
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;
|
|
}
|
|
}
|