2018-06-05 07:48:08 +03:00
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2018-01-28 12:17:20 +03:00
/*
* Copyright ( c ) 2017 - 2018 Mellanox Technologies . All rights reserved .
*/
2018-03-02 00:57:44 +03:00
# include <rdma/rdma_cm.h>
2018-01-28 12:17:20 +03:00
# include <rdma/ib_verbs.h>
# include <rdma/restrack.h>
2019-07-02 13:02:31 +03:00
# include <rdma/rdma_counter.h>
2018-01-28 12:17:20 +03:00
# include <linux/mutex.h>
# include <linux/sched/task.h>
# include <linux/pid_namespace.h>
2018-03-02 00:57:44 +03:00
# include "cma_priv.h"
2019-02-18 23:25:47 +03:00
# include "restrack.h"
2018-03-02 00:57:44 +03:00
2019-01-30 13:48:58 +03:00
/**
2019-02-18 23:25:47 +03:00
* rdma_restrack_init ( ) - initialize and allocate resource tracking
2019-01-30 13:48:58 +03:00
* @ dev : IB device
2019-02-18 23:25:47 +03:00
*
* Return : 0 on success
2019-01-30 13:48:58 +03:00
*/
2019-02-18 23:25:47 +03:00
int rdma_restrack_init ( struct ib_device * dev )
2018-01-28 12:17:20 +03:00
{
2019-02-18 23:25:47 +03:00
struct rdma_restrack_root * rt ;
2019-02-18 23:25:43 +03:00
int i ;
2019-02-18 23:25:48 +03:00
dev - > res = kcalloc ( RDMA_RESTRACK_MAX , sizeof ( * rt ) , GFP_KERNEL ) ;
2019-02-18 23:25:47 +03:00
if ( ! dev - > res )
return - ENOMEM ;
rt = dev - > res ;
2019-02-18 23:25:48 +03:00
for ( i = 0 ; i < RDMA_RESTRACK_MAX ; i + + )
xa_init_flags ( & rt [ i ] . xa , XA_FLAGS_ALLOC ) ;
2019-01-30 13:48:58 +03:00
2019-02-18 23:25:47 +03:00
return 0 ;
2018-01-28 12:17:20 +03:00
}
2018-03-21 18:12:42 +03:00
static const char * type2str ( enum rdma_restrack_type type )
{
static const char * const names [ RDMA_RESTRACK_MAX ] = {
[ RDMA_RESTRACK_PD ] = " PD " ,
[ RDMA_RESTRACK_CQ ] = " CQ " ,
[ RDMA_RESTRACK_QP ] = " QP " ,
[ RDMA_RESTRACK_CM_ID ] = " CM_ID " ,
[ RDMA_RESTRACK_MR ] = " MR " ,
2018-11-28 14:16:43 +03:00
[ RDMA_RESTRACK_CTX ] = " CTX " ,
2019-07-02 13:02:31 +03:00
[ RDMA_RESTRACK_COUNTER ] = " COUNTER " ,
2021-04-18 16:41:24 +03:00
[ RDMA_RESTRACK_SRQ ] = " SRQ " ,
2018-03-21 18:12:42 +03:00
} ;
return names [ type ] ;
} ;
2019-01-30 13:48:58 +03:00
/**
* rdma_restrack_clean ( ) - clean resource tracking
* @ dev : IB device
*/
void rdma_restrack_clean ( struct ib_device * dev )
2018-01-28 12:17:20 +03:00
{
2019-02-18 23:25:47 +03:00
struct rdma_restrack_root * rt = dev - > res ;
2018-03-21 18:12:42 +03:00
struct rdma_restrack_entry * e ;
char buf [ TASK_COMM_LEN ] ;
2019-02-18 23:25:43 +03:00
bool found = false ;
2018-03-21 18:12:42 +03:00
const char * owner ;
2019-02-18 23:25:43 +03:00
int i ;
for ( i = 0 ; i < RDMA_RESTRACK_MAX ; i + + ) {
2019-02-18 23:25:48 +03:00
struct xarray * xa = & dev - > res [ i ] . xa ;
2019-02-18 23:25:47 +03:00
if ( ! xa_empty ( xa ) ) {
2019-02-18 23:25:43 +03:00
unsigned long index ;
if ( ! found ) {
pr_err ( " restrack: %s " , CUT_HERE ) ;
dev_err ( & dev - > dev , " BUG: RESTRACK detected leak of resources \n " ) ;
}
2019-02-18 23:25:47 +03:00
xa_for_each ( xa , index , e ) {
2019-02-18 23:25:43 +03:00
if ( rdma_is_kernel_res ( e ) ) {
owner = e - > kern_name ;
} else {
/*
* There is no need to call get_task_struct here ,
* because we can be here only if there are more
* get_task_struct ( ) call than put_task_struct ( ) .
*/
get_task_comm ( buf , e - > task ) ;
owner = buf ;
}
pr_err ( " restrack: %s %s object allocated by %s is not freed \n " ,
rdma_is_kernel_res ( e ) ? " Kernel " :
" User " ,
type2str ( e - > type ) , owner ) ;
}
found = true ;
2018-03-21 18:12:42 +03:00
}
2019-02-18 23:25:47 +03:00
xa_destroy ( xa ) ;
2018-03-21 18:12:42 +03:00
}
2019-02-18 23:25:43 +03:00
if ( found )
pr_err ( " restrack: %s " , CUT_HERE ) ;
2019-02-18 23:25:47 +03:00
kfree ( rt ) ;
2018-01-28 12:17:20 +03:00
}
2019-01-30 13:48:58 +03:00
/**
* rdma_restrack_count ( ) - the current usage of specific object
* @ dev : IB device
* @ type : actual type of object to operate
*/
2019-08-15 11:38:29 +03:00
int rdma_restrack_count ( struct ib_device * dev , enum rdma_restrack_type type )
2018-01-28 12:17:20 +03:00
{
2019-02-18 23:25:48 +03:00
struct rdma_restrack_root * rt = & dev - > res [ type ] ;
2018-01-28 12:17:20 +03:00
struct rdma_restrack_entry * e ;
2019-02-18 23:25:48 +03:00
XA_STATE ( xas , & rt - > xa , 0 ) ;
2018-01-28 12:17:20 +03:00
u32 cnt = 0 ;
2019-02-18 23:25:48 +03:00
xa_lock ( & rt - > xa ) ;
2019-10-10 10:11:04 +03:00
xas_for_each ( & xas , e , U32_MAX )
2019-08-15 11:38:29 +03:00
cnt + + ;
2019-02-18 23:25:48 +03:00
xa_unlock ( & rt - > xa ) ;
2018-01-28 12:17:20 +03:00
return cnt ;
}
EXPORT_SYMBOL ( rdma_restrack_count ) ;
static struct ib_device * res_to_dev ( struct rdma_restrack_entry * res )
{
2018-03-02 00:57:22 +03:00
switch ( res - > type ) {
2018-01-28 12:17:20 +03:00
case RDMA_RESTRACK_PD :
2018-03-02 00:57:22 +03:00
return container_of ( res , struct ib_pd , res ) - > device ;
2018-01-28 12:17:20 +03:00
case RDMA_RESTRACK_CQ :
2018-03-02 00:57:22 +03:00
return container_of ( res , struct ib_cq , res ) - > device ;
2018-01-28 12:17:20 +03:00
case RDMA_RESTRACK_QP :
2018-03-02 00:57:22 +03:00
return container_of ( res , struct ib_qp , res ) - > device ;
2018-03-02 00:57:44 +03:00
case RDMA_RESTRACK_CM_ID :
return container_of ( res , struct rdma_id_private ,
res ) - > id . device ;
2018-03-02 00:58:13 +03:00
case RDMA_RESTRACK_MR :
return container_of ( res , struct ib_mr , res ) - > device ;
2018-11-28 14:16:43 +03:00
case RDMA_RESTRACK_CTX :
return container_of ( res , struct ib_ucontext , res ) - > device ;
2019-07-02 13:02:31 +03:00
case RDMA_RESTRACK_COUNTER :
return container_of ( res , struct rdma_counter , res ) - > device ;
2021-04-18 16:41:24 +03:00
case RDMA_RESTRACK_SRQ :
return container_of ( res , struct ib_srq , res ) - > device ;
2018-01-28 12:17:20 +03:00
default :
2018-03-02 00:57:22 +03:00
WARN_ONCE ( true , " Wrong resource tracking type %u \n " , res - > type ) ;
2018-01-28 12:17:20 +03:00
return NULL ;
}
}
2020-09-22 12:11:06 +03:00
/**
* rdma_restrack_attach_task ( ) - attach the task onto this resource ,
* valid for user space restrack entries .
* @ res : resource entry
* @ task : the task to attach
*/
static void rdma_restrack_attach_task ( struct rdma_restrack_entry * res ,
struct task_struct * task )
2018-10-02 11:48:01 +03:00
{
2020-09-22 12:11:06 +03:00
if ( WARN_ON_ONCE ( ! task ) )
2018-10-02 11:48:02 +03:00
return ;
2018-10-02 11:48:01 +03:00
if ( res - > task )
put_task_struct ( res - > task ) ;
2020-09-22 12:11:06 +03:00
get_task_struct ( task ) ;
res - > task = task ;
res - > user = true ;
2018-10-02 11:48:01 +03:00
}
2019-07-02 13:02:32 +03:00
/**
2020-09-22 12:11:06 +03:00
* rdma_restrack_set_name ( ) - set the task for this resource
2019-07-02 13:02:32 +03:00
* @ res : resource entry
2020-09-22 12:11:06 +03:00
* @ caller : kernel name , the current task will be used if the caller is NULL .
2019-07-02 13:02:32 +03:00
*/
2020-09-22 12:11:06 +03:00
void rdma_restrack_set_name ( struct rdma_restrack_entry * res , const char * caller )
2019-07-02 13:02:32 +03:00
{
2020-09-22 12:11:06 +03:00
if ( caller ) {
res - > kern_name = caller ;
return ;
}
rdma_restrack_attach_task ( res , current ) ;
}
EXPORT_SYMBOL ( rdma_restrack_set_name ) ;
/**
* rdma_restrack_parent_name ( ) - set the restrack name properties based
* on parent restrack
* @ dst : destination resource entry
* @ parent : parent resource entry
*/
void rdma_restrack_parent_name ( struct rdma_restrack_entry * dst ,
const struct rdma_restrack_entry * parent )
{
if ( rdma_is_kernel_res ( parent ) )
dst - > kern_name = parent - > kern_name ;
else
rdma_restrack_attach_task ( dst , parent - > task ) ;
2019-07-02 13:02:32 +03:00
}
2020-09-22 12:11:06 +03:00
EXPORT_SYMBOL ( rdma_restrack_parent_name ) ;
2019-07-02 13:02:32 +03:00
2020-09-22 12:11:04 +03:00
/**
* rdma_restrack_new ( ) - Initializes new restrack entry to allow _put ( ) interface
* to release memory in fully automatic way .
2021-01-19 01:39:25 +03:00
* @ res : Entry to initialize
* @ type : REstrack type
2020-09-22 12:11:04 +03:00
*/
void rdma_restrack_new ( struct rdma_restrack_entry * res ,
enum rdma_restrack_type type )
{
kref_init ( & res - > kref ) ;
init_completion ( & res - > comp ) ;
res - > type = type ;
}
EXPORT_SYMBOL ( rdma_restrack_new ) ;
2020-09-22 12:11:05 +03:00
/**
* rdma_restrack_add ( ) - add object to the reource tracking database
* @ res : resource entry
*/
void rdma_restrack_add ( struct rdma_restrack_entry * res )
2018-01-28 12:17:20 +03:00
{
struct ib_device * dev = res_to_dev ( res ) ;
2019-02-18 23:25:47 +03:00
struct rdma_restrack_root * rt ;
2020-11-17 10:01:47 +03:00
int ret = 0 ;
2018-01-28 12:17:20 +03:00
if ( ! dev )
return ;
2020-11-17 10:01:47 +03:00
if ( res - > no_track )
goto out ;
2019-02-18 23:25:48 +03:00
rt = & dev - > res [ res - > type ] ;
2019-02-18 23:25:47 +03:00
2019-07-02 13:02:31 +03:00
if ( res - > type = = RDMA_RESTRACK_QP ) {
2019-02-18 23:25:51 +03:00
/* Special case to ensure that LQPN points to right QP */
struct ib_qp * qp = container_of ( res , struct ib_qp , res ) ;
2020-11-04 17:40:06 +03:00
WARN_ONCE ( qp - > qp_num > > 24 | | qp - > port > > 8 ,
" QP number 0x%0X and port 0x%0X " , qp - > qp_num ,
qp - > port ) ;
res - > id = qp - > qp_num ;
if ( qp - > qp_type = = IB_QPT_SMI | | qp - > qp_type = = IB_QPT_GSI )
res - > id | = qp - > port < < 24 ;
ret = xa_insert ( & rt - > xa , res - > id , res , GFP_KERNEL ) ;
if ( ret )
res - > id = 0 ;
2019-07-02 13:02:31 +03:00
} else if ( res - > type = = RDMA_RESTRACK_COUNTER ) {
/* Special case to ensure that cntn points to right counter */
struct rdma_counter * counter ;
counter = container_of ( res , struct rdma_counter , res ) ;
ret = xa_insert ( & rt - > xa , counter - > id , res , GFP_KERNEL ) ;
res - > id = ret ? 0 : counter - > id ;
} else {
ret = xa_alloc_cyclic ( & rt - > xa , & res - > id , res , xa_limit_32b ,
& rt - > next_id , GFP_KERNEL ) ;
2020-12-16 13:07:53 +03:00
ret = ( ret < 0 ) ? ret : 0 ;
2019-02-18 23:25:51 +03:00
}
2020-11-17 10:01:47 +03:00
out :
2019-02-18 23:25:43 +03:00
if ( ! ret )
res - > valid = true ;
2018-01-28 12:17:20 +03:00
}
2020-09-22 12:11:05 +03:00
EXPORT_SYMBOL ( rdma_restrack_add ) ;
2018-12-17 18:15:16 +03:00
2018-01-28 12:17:20 +03:00
int __must_check rdma_restrack_get ( struct rdma_restrack_entry * res )
{
return kref_get_unless_zero ( & res - > kref ) ;
}
EXPORT_SYMBOL ( rdma_restrack_get ) ;
2019-02-18 23:25:44 +03:00
/**
* rdma_restrack_get_byid ( ) - translate from ID to restrack object
* @ dev : IB device
* @ type : resource track type
* @ id : ID to take a look
*
* Return : Pointer to restrack entry or - ENOENT in case of error .
*/
struct rdma_restrack_entry *
rdma_restrack_get_byid ( struct ib_device * dev ,
enum rdma_restrack_type type , u32 id )
{
2019-02-18 23:25:48 +03:00
struct rdma_restrack_root * rt = & dev - > res [ type ] ;
2019-02-18 23:25:44 +03:00
struct rdma_restrack_entry * res ;
2019-02-18 23:25:48 +03:00
xa_lock ( & rt - > xa ) ;
res = xa_load ( & rt - > xa , id ) ;
2019-02-18 23:25:44 +03:00
if ( ! res | | ! rdma_restrack_get ( res ) )
res = ERR_PTR ( - ENOENT ) ;
2019-02-18 23:25:48 +03:00
xa_unlock ( & rt - > xa ) ;
2019-02-18 23:25:44 +03:00
return res ;
}
EXPORT_SYMBOL ( rdma_restrack_get_byid ) ;
2018-01-28 12:17:20 +03:00
static void restrack_release ( struct kref * kref )
{
struct rdma_restrack_entry * res ;
res = container_of ( kref , struct rdma_restrack_entry , kref ) ;
2020-09-22 12:11:04 +03:00
if ( res - > task ) {
put_task_struct ( res - > task ) ;
res - > task = NULL ;
}
2018-01-28 12:17:20 +03:00
complete ( & res - > comp ) ;
}
int rdma_restrack_put ( struct rdma_restrack_entry * res )
{
return kref_put ( & res - > kref , restrack_release ) ;
}
EXPORT_SYMBOL ( rdma_restrack_put ) ;
2020-09-22 12:11:04 +03:00
/**
* rdma_restrack_del ( ) - delete object from the reource tracking database
* @ res : resource entry
*/
2018-01-28 12:17:20 +03:00
void rdma_restrack_del ( struct rdma_restrack_entry * res )
{
2019-02-18 23:25:48 +03:00
struct rdma_restrack_entry * old ;
struct rdma_restrack_root * rt ;
struct ib_device * dev ;
2018-01-28 12:17:20 +03:00
2020-09-22 12:11:04 +03:00
if ( ! res - > valid ) {
if ( res - > task ) {
put_task_struct ( res - > task ) ;
res - > task = NULL ;
}
return ;
}
2018-01-28 12:17:20 +03:00
2020-11-17 10:01:47 +03:00
if ( res - > no_track )
goto out ;
2019-02-18 23:25:48 +03:00
dev = res_to_dev ( res ) ;
if ( WARN_ON ( ! dev ) )
2018-01-28 12:17:20 +03:00
return ;
2019-02-18 23:25:48 +03:00
rt = & dev - > res [ res - > type ] ;
old = xa_erase ( & rt - > xa , res - > id ) ;
2021-07-23 14:39:50 +03:00
if ( res - > type = = RDMA_RESTRACK_MR )
2020-09-22 12:11:04 +03:00
return ;
2019-02-18 23:25:48 +03:00
WARN_ON ( old ! = res ) ;
2018-10-02 11:48:03 +03:00
2020-11-17 10:01:47 +03:00
out :
res - > valid = false ;
2019-02-18 23:25:43 +03:00
rdma_restrack_put ( res ) ;
wait_for_completion ( & res - > comp ) ;
2018-01-28 12:17:20 +03:00
}
EXPORT_SYMBOL ( rdma_restrack_del ) ;