2021-06-08 22:59:10 +03:00
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright ( c ) 2020 Anna Schumaker < Anna . Schumaker @ Netapp . com >
*/
2021-06-08 22:59:11 +03:00
# include <linux/sunrpc/clnt.h>
2021-06-08 22:59:10 +03:00
# include <linux/kobject.h>
2021-06-08 22:59:19 +03:00
# include <linux/sunrpc/addr.h>
2021-06-24 06:28:49 +03:00
# include <linux/sunrpc/xprtsock.h>
2021-06-08 22:59:19 +03:00
2021-06-08 22:59:12 +03:00
# include "sysfs.h"
2021-06-08 22:59:10 +03:00
2021-06-08 22:59:19 +03:00
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 ) ;
}
2021-06-08 22:59:10 +03:00
static struct kset * rpc_sunrpc_kset ;
2021-06-08 22:59:16 +03:00
static struct kobject * rpc_sunrpc_client_kobj , * rpc_sunrpc_xprt_switch_kobj ;
2021-06-08 22:59:11 +03:00
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 ;
}
2021-06-08 22:59:10 +03:00
2021-06-08 22:59:19 +03:00
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 ) ;
}
2021-06-24 06:28:50 +03:00
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 ) ;
}
2021-06-08 22:59:21 +03:00
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 ) ;
}
2021-06-08 22:59:19 +03:00
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 ;
2022-03-25 00:19:59 +03:00
if ( ! xprt ) {
ret = sprintf ( buf , " <closed> \n " ) ;
goto out ;
}
2021-06-08 22:59:19 +03:00
ret = sprintf ( buf , " %s \n " , xprt - > address_strings [ RPC_DISPLAY_ADDR ] ) ;
xprt_put ( xprt ) ;
2022-03-25 00:19:59 +03:00
out :
2022-03-25 17:37:31 +03:00
return ret ;
2021-06-08 22:59:19 +03:00
}
2021-07-29 23:45:23 +03:00
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 ) ;
2022-03-25 17:37:31 +03:00
size_t buflen = PAGE_SIZE ;
2022-03-25 00:19:59 +03:00
ssize_t ret ;
2021-07-29 23:45:23 +03:00
2021-10-28 22:17:41 +03:00
if ( ! xprt | | ! xprt_connected ( xprt ) ) {
2022-03-25 00:19:59 +03:00
ret = sprintf ( buf , " <closed> \n " ) ;
2022-03-25 17:37:31 +03:00
} 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 ' ;
}
2022-03-25 00:19:59 +03:00
} else
ret = sprintf ( buf , " <closed> \n " ) ;
} else
ret = sprintf ( buf , " <not a socket> \n " ) ;
2021-07-29 23:45:23 +03:00
xprt_put ( xprt ) ;
2022-03-25 17:37:31 +03:00
return ret ;
2021-07-29 23:45:23 +03:00
}
sunrpc: provide transport info in the sysfs directory
Allow to query transport's attributes. Currently showing following
fields of the rpc_xprt structure: state, last_used, cong, cwnd,
max_reqs, min_reqs, num_reqs, sizes of queues binding, sending,
pending, backlog.
Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
2021-06-08 22:59:20 +03:00
static ssize_t rpc_sysfs_xprt_info_show ( struct kobject * kobj ,
2022-03-25 17:37:31 +03:00
struct kobj_attribute * attr , char * buf )
sunrpc: provide transport info in the sysfs directory
Allow to query transport's attributes. Currently showing following
fields of the rpc_xprt structure: state, last_used, cong, cwnd,
max_reqs, min_reqs, num_reqs, sizes of queues binding, sending,
pending, backlog.
Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
2021-06-08 22:59:20 +03:00
{
struct rpc_xprt * xprt = rpc_sysfs_xprt_kobj_get_xprt ( kobj ) ;
2022-03-25 17:37:31 +03:00
unsigned short srcport = 0 ;
size_t buflen = PAGE_SIZE ;
sunrpc: provide transport info in the sysfs directory
Allow to query transport's attributes. Currently showing following
fields of the rpc_xprt structure: state, last_used, cong, cwnd,
max_reqs, min_reqs, num_reqs, sizes of queues binding, sending,
pending, backlog.
Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
2021-06-08 22:59:20 +03:00
ssize_t ret ;
2021-10-28 22:17:41 +03:00
if ( ! xprt | | ! xprt_connected ( xprt ) ) {
2022-03-25 00:19:59 +03:00
ret = sprintf ( buf , " <closed> \n " ) ;
goto out ;
2021-10-28 22:17:41 +03:00
}
sunrpc: provide transport info in the sysfs directory
Allow to query transport's attributes. Currently showing following
fields of the rpc_xprt structure: state, last_used, cong, cwnd,
max_reqs, min_reqs, num_reqs, sizes of queues binding, sending,
pending, backlog.
Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
2021-06-08 22:59:20 +03:00
2022-03-25 17:37:31 +03:00
if ( xprt - > ops - > get_srcport )
srcport = xprt - > ops - > get_srcport ( xprt ) ;
ret = snprintf ( buf , buflen ,
" last_used=%lu \n cur_cong=%lu \n cong_win=%lu \n "
sunrpc: provide transport info in the sysfs directory
Allow to query transport's attributes. Currently showing following
fields of the rpc_xprt structure: state, last_used, cong, cwnd,
max_reqs, min_reqs, num_reqs, sizes of queues binding, sending,
pending, backlog.
Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
2021-06-08 22:59:20 +03:00
" max_num_slots=%u \n min_num_slots=%u \n num_reqs=%u \n "
" binding_q_len=%u \n sending_q_len=%u \n pending_q_len=%u \n "
2021-06-24 06:28:52 +03:00
" backlog_q_len=%u \n main_xprt=%d \n src_port=%u \n "
2021-07-29 23:46:05 +03:00
" tasks_queuelen=%ld \n dst_port=%s \n " ,
2021-06-24 06:28:49 +03:00
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 ,
2022-03-25 17:37:31 +03:00
xprt - > backlog . qlen , xprt - > main , srcport ,
2021-07-29 23:46:05 +03:00
atomic_long_read ( & xprt - > queuelen ) ,
2022-03-25 17:37:31 +03:00
xprt - > address_strings [ RPC_DISPLAY_PORT ] ) ;
2022-03-25 00:19:59 +03:00
out :
sunrpc: provide transport info in the sysfs directory
Allow to query transport's attributes. Currently showing following
fields of the rpc_xprt structure: state, last_used, cong, cwnd,
max_reqs, min_reqs, num_reqs, sizes of queues binding, sending,
pending, backlog.
Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
2021-06-08 22:59:20 +03:00
xprt_put ( xprt ) ;
2022-03-25 17:37:31 +03:00
return ret ;
sunrpc: provide transport info in the sysfs directory
Allow to query transport's attributes. Currently showing following
fields of the rpc_xprt structure: state, last_used, cong, cwnd,
max_reqs, min_reqs, num_reqs, sizes of queues binding, sending,
pending, backlog.
Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
2021-06-08 22:59:20 +03:00
}
2021-06-08 22:59:22 +03:00
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 ,
2021-06-24 06:28:53 +03:00
closing , congested , cwnd_wait , write_space , offline , remove ;
2021-06-08 22:59:22 +03:00
2022-03-25 00:19:59 +03:00
if ( ! ( xprt & & xprt - > state ) ) {
2021-06-08 22:59:22 +03:00
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 ) ;
2021-06-24 06:28:50 +03:00
offline = test_bit ( XPRT_OFFLINE , & xprt - > state ) ;
2021-06-24 06:28:53 +03:00
remove = test_bit ( XPRT_REMOVE , & xprt - > state ) ;
2021-06-08 22:59:22 +03:00
2021-06-24 06:28:53 +03:00
ret = sprintf ( buf , " state=%s %s %s %s %s %s %s %s %s %s %s %s \n " ,
2021-06-08 22:59:22 +03:00
locked ? " LOCKED " : " " ,
connected ? " CONNECTED " : " " ,
connecting ? " CONNECTING " : " " ,
close_wait ? " CLOSE_WAIT " : " " ,
bound ? " BOUND " : " " ,
binding ? " BOUNDING " : " " ,
closing ? " CLOSING " : " " ,
congested ? " CONGESTED " : " " ,
cwnd_wait ? " CWND_WAIT " : " " ,
2021-06-24 06:28:50 +03:00
write_space ? " WRITE_SPACE " : " " ,
2021-06-24 06:28:53 +03:00
offline ? " OFFLINE " : " " ,
remove ? " REMOVE " : " " ) ;
2021-06-08 22:59:22 +03:00
}
xprt_put ( xprt ) ;
2022-03-25 17:37:31 +03:00
return ret ;
2021-06-08 22:59:22 +03:00
}
2021-06-08 22:59:21 +03:00
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 ;
2021-08-27 21:37:16 +03:00
ret = sprintf ( buf , " num_xprts=%u \n num_active=%u \n "
" num_unique_destaddr=%u \n queue_len=%ld \n " ,
2021-06-08 22:59:21 +03:00
xprt_switch - > xps_nxprts , xprt_switch - > xps_nactive ,
2021-08-27 21:37:16 +03:00
xprt_switch - > xps_nunique_destaddr_xprts ,
2021-06-08 22:59:21 +03:00
atomic_long_read ( & xprt_switch - > xps_queuelen ) ) ;
xprt_switch_put ( xprt_switch ) ;
2022-03-25 17:37:31 +03:00
return ret ;
2021-06-08 22:59:21 +03:00
}
2021-06-08 22:59:19 +03:00
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 ;
}
2021-06-24 06:28:50 +03:00
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 ) ;
2021-06-24 06:28:53 +03:00
int offline = 0 , online = 0 , remove = 0 ;
2021-06-24 06:28:50 +03:00
struct rpc_xprt_switch * xps = rpc_sysfs_xprt_kobj_get_xprt_switch ( kobj ) ;
if ( ! xprt )
return 0 ;
if ( ! strncmp ( buf , " offline " , 7 ) )
offline = 1 ;
else if ( ! strncmp ( buf , " online " , 6 ) )
online = 1 ;
2021-06-24 06:28:53 +03:00
else if ( ! strncmp ( buf , " remove " , 6 ) )
remove = 1 ;
2021-09-09 07:32:38 +03:00
else {
count = - EINVAL ;
goto out_put ;
}
2021-06-24 06:28:50 +03:00
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 ) {
2021-11-15 19:54:25 +03:00
if ( ! test_and_set_bit ( XPRT_OFFLINE , & xprt - > state ) ) {
spin_lock ( & xps - > xps_lock ) ;
xps - > xps_nactive - - ;
spin_unlock ( & xps - > xps_lock ) ;
}
2021-06-24 06:28:50 +03:00
} else if ( online ) {
2021-11-15 19:54:25 +03:00
if ( test_and_clear_bit ( XPRT_OFFLINE , & xprt - > state ) ) {
spin_lock ( & xps - > xps_lock ) ;
xps - > xps_nactive + + ;
spin_unlock ( & xps - > xps_lock ) ;
}
2021-06-24 06:28:53 +03:00
} else if ( remove ) {
if ( test_bit ( XPRT_OFFLINE , & xprt - > state ) ) {
2021-11-15 19:54:25 +03:00
if ( ! test_and_set_bit ( XPRT_REMOVE , & xprt - > state ) ) {
xprt_force_disconnect ( xprt ) ;
if ( test_bit ( XPRT_CONNECTED , & xprt - > state ) ) {
if ( ! xprt - > sending . qlen & &
! xprt - > pending . qlen & &
! xprt - > backlog . qlen & &
! atomic_long_read ( & xprt - > queuelen ) )
rpc_xprt_switch_remove_xprt ( xps , xprt ) ;
}
2021-06-24 06:28:53 +03:00
}
} else {
count = - EINVAL ;
}
2021-06-24 06:28:50 +03:00
}
release_tasks :
xprt_release_write ( xprt , NULL ) ;
out_put :
xprt_put ( xprt ) ;
xprt_switch_put ( xps ) ;
return count ;
}
2021-06-08 22:59:10 +03:00
int rpc_sysfs_init ( void )
{
rpc_sunrpc_kset = kset_create_and_add ( " sunrpc " , NULL , kernel_kobj ) ;
if ( ! rpc_sunrpc_kset )
return - ENOMEM ;
2021-06-08 22:59:16 +03:00
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 ;
2021-06-08 22:59:10 +03:00
return 0 ;
2021-06-08 22:59:16 +03:00
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 ;
2021-06-08 22:59:10 +03:00
}
2021-06-08 22:59:12 +03:00
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 ) ;
}
2021-06-08 22:59:16 +03:00
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 ) ;
}
2021-06-08 22:59:18 +03:00
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 ) ;
}
2021-06-08 22:59:12 +03:00
static const void * rpc_sysfs_client_namespace ( struct kobject * kobj )
{
return container_of ( kobj , struct rpc_sysfs_client , kobject ) - > net ;
}
2021-06-08 22:59:16 +03:00
static const void * rpc_sysfs_xprt_switch_namespace ( struct kobject * kobj )
{
return container_of ( kobj , struct rpc_sysfs_xprt_switch , kobject ) - > net ;
}
2021-06-08 22:59:18 +03:00
static const void * rpc_sysfs_xprt_namespace ( struct kobject * kobj )
{
return container_of ( kobj , struct rpc_sysfs_xprt ,
kobject ) - > xprt - > xprt_net ;
}
2021-06-08 22:59:19 +03:00
static struct kobj_attribute rpc_sysfs_xprt_dstaddr = __ATTR ( dstaddr ,
0644 , rpc_sysfs_xprt_dstaddr_show , rpc_sysfs_xprt_dstaddr_store ) ;
2021-07-29 23:45:23 +03:00
static struct kobj_attribute rpc_sysfs_xprt_srcaddr = __ATTR ( srcaddr ,
0644 , rpc_sysfs_xprt_srcaddr_show , NULL ) ;
sunrpc: provide transport info in the sysfs directory
Allow to query transport's attributes. Currently showing following
fields of the rpc_xprt structure: state, last_used, cong, cwnd,
max_reqs, min_reqs, num_reqs, sizes of queues binding, sending,
pending, backlog.
Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
2021-06-08 22:59:20 +03:00
static struct kobj_attribute rpc_sysfs_xprt_info = __ATTR ( xprt_info ,
0444 , rpc_sysfs_xprt_info_show , NULL ) ;
2021-06-08 22:59:22 +03:00
static struct kobj_attribute rpc_sysfs_xprt_change_state = __ATTR ( xprt_state ,
2021-06-24 06:28:50 +03:00
0644 , rpc_sysfs_xprt_state_show , rpc_sysfs_xprt_state_change ) ;
2021-06-08 22:59:22 +03:00
2021-06-08 22:59:19 +03:00
static struct attribute * rpc_sysfs_xprt_attrs [ ] = {
& rpc_sysfs_xprt_dstaddr . attr ,
2021-07-29 23:45:23 +03:00
& rpc_sysfs_xprt_srcaddr . attr ,
sunrpc: provide transport info in the sysfs directory
Allow to query transport's attributes. Currently showing following
fields of the rpc_xprt structure: state, last_used, cong, cwnd,
max_reqs, min_reqs, num_reqs, sizes of queues binding, sending,
pending, backlog.
Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
2021-06-08 22:59:20 +03:00
& rpc_sysfs_xprt_info . attr ,
2021-06-08 22:59:22 +03:00
& rpc_sysfs_xprt_change_state . attr ,
2021-06-08 22:59:19 +03:00
NULL ,
} ;
2021-12-28 17:48:23 +03:00
ATTRIBUTE_GROUPS ( rpc_sysfs_xprt ) ;
2021-06-08 22:59:19 +03:00
2021-06-08 22:59:21 +03:00
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 ,
} ;
2021-12-28 17:48:23 +03:00
ATTRIBUTE_GROUPS ( rpc_sysfs_xprt_switch ) ;
2021-06-08 22:59:21 +03:00
2021-06-08 22:59:12 +03:00
static struct kobj_type rpc_sysfs_client_type = {
. release = rpc_sysfs_client_release ,
. sysfs_ops = & kobj_sysfs_ops ,
. namespace = rpc_sysfs_client_namespace ,
} ;
2021-06-08 22:59:16 +03:00
static struct kobj_type rpc_sysfs_xprt_switch_type = {
. release = rpc_sysfs_xprt_switch_release ,
2021-12-28 17:48:23 +03:00
. default_groups = rpc_sysfs_xprt_switch_groups ,
2021-06-08 22:59:16 +03:00
. sysfs_ops = & kobj_sysfs_ops ,
. namespace = rpc_sysfs_xprt_switch_namespace ,
} ;
2021-06-08 22:59:18 +03:00
static struct kobj_type rpc_sysfs_xprt_type = {
. release = rpc_sysfs_xprt_release ,
2021-12-28 17:48:23 +03:00
. default_groups = rpc_sysfs_xprt_groups ,
2021-06-08 22:59:18 +03:00
. sysfs_ops = & kobj_sysfs_ops ,
. namespace = rpc_sysfs_xprt_namespace ,
} ;
2021-06-08 22:59:10 +03:00
void rpc_sysfs_exit ( void )
{
2021-06-08 22:59:11 +03:00
kobject_put ( rpc_sunrpc_client_kobj ) ;
2021-06-08 22:59:16 +03:00
kobject_put ( rpc_sunrpc_xprt_switch_kobj ) ;
2021-06-08 22:59:10 +03:00
kset_unregister ( rpc_sunrpc_kset ) ;
}
2021-06-08 22:59:12 +03:00
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 ;
}
2021-06-08 22:59:16 +03:00
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 ;
}
2021-06-08 22:59:18 +03:00
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 ;
}
2021-06-08 22:59:17 +03:00
void rpc_sysfs_client_setup ( struct rpc_clnt * clnt ,
struct rpc_xprt_switch * xprt_switch ,
struct net * net )
2021-06-08 22:59:12 +03:00
{
struct rpc_sysfs_client * rpc_client ;
2021-06-08 22:59:17 +03:00
rpc_client = rpc_sysfs_client_alloc ( rpc_sunrpc_client_kobj ,
net , clnt - > cl_clid ) ;
2021-06-08 22:59:12 +03:00
if ( rpc_client ) {
2021-06-08 22:59:17 +03:00
char name [ ] = " switch " ;
struct rpc_sysfs_xprt_switch * xswitch =
( struct rpc_sysfs_xprt_switch * ) xprt_switch - > xps_sysfs ;
int ret ;
2021-06-08 22:59:12 +03:00
clnt - > cl_sysfs = rpc_client ;
2021-06-08 22:59:17 +03:00
rpc_client - > clnt = clnt ;
rpc_client - > xprt_switch = xprt_switch ;
2021-06-08 22:59:12 +03:00
kobject_uevent ( & rpc_client - > kobject , KOBJ_ADD ) ;
2021-06-08 22:59:17 +03:00
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 ) ;
2021-06-08 22:59:12 +03:00
}
}
2021-06-08 22:59:16 +03:00
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 ) ;
}
}
2021-06-08 22:59:18 +03:00
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 ;
2021-06-24 06:28:50 +03:00
rpc_xprt - > xprt_switch = xprt_switch ;
2021-06-08 22:59:18 +03:00
kobject_uevent ( & rpc_xprt - > kobject , KOBJ_ADD ) ;
}
}
2021-06-08 22:59:12 +03:00
void rpc_sysfs_client_destroy ( struct rpc_clnt * clnt )
{
struct rpc_sysfs_client * rpc_client = clnt - > cl_sysfs ;
if ( rpc_client ) {
2021-06-08 22:59:17 +03:00
char name [ ] = " switch " ;
sysfs_remove_link ( & rpc_client - > kobject , name ) ;
2021-06-08 22:59:12 +03:00
kobject_uevent ( & rpc_client - > kobject , KOBJ_REMOVE ) ;
kobject_del ( & rpc_client - > kobject ) ;
kobject_put ( & rpc_client - > kobject ) ;
clnt - > cl_sysfs = NULL ;
}
}
2021-06-08 22:59:16 +03:00
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 ;
}
}
2021-06-08 22:59:18 +03:00
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 ;
}
}