2021-10-21 11:55:21 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
/* Volume handling.
*
* Copyright ( C ) 2021 Red Hat , Inc . All Rights Reserved .
* Written by David Howells ( dhowells @ redhat . com )
*/
# include <linux/fs.h>
# include <linux/slab.h>
# include "internal.h"
# include <trace/events/fscache.h>
/*
* Allocate and set up a volume representation . We make sure all the fanout
* directories are created and pinned .
*/
void cachefiles_acquire_volume ( struct fscache_volume * vcookie )
{
struct cachefiles_volume * volume ;
struct cachefiles_cache * cache = vcookie - > cache - > cache_priv ;
const struct cred * saved_cred ;
struct dentry * vdentry , * fan ;
size_t len ;
char * name ;
2021-12-14 12:51:43 +03:00
bool is_new = false ;
int ret , n_accesses , i ;
2021-10-21 11:55:21 +03:00
_enter ( " " ) ;
volume = kzalloc ( sizeof ( struct cachefiles_volume ) , GFP_KERNEL ) ;
if ( ! volume )
return ;
volume - > vcookie = vcookie ;
volume - > cache = cache ;
INIT_LIST_HEAD ( & volume - > cache_link ) ;
cachefiles_begin_secure ( cache , & saved_cred ) ;
len = vcookie - > key [ 0 ] ;
name = kmalloc ( len + 3 , GFP_NOFS ) ;
if ( ! name )
goto error_vol ;
name [ 0 ] = ' I ' ;
memcpy ( name + 1 , vcookie - > key + 1 , len ) ;
name [ len + 1 ] = 0 ;
2021-12-14 12:51:43 +03:00
retry :
vdentry = cachefiles_get_directory ( cache , cache - > store , name , & is_new ) ;
2021-10-21 11:55:21 +03:00
if ( IS_ERR ( vdentry ) )
goto error_name ;
volume - > dentry = vdentry ;
2021-12-14 12:51:43 +03:00
if ( is_new ) {
if ( ! cachefiles_set_volume_xattr ( volume ) )
goto error_dir ;
} else {
ret = cachefiles_check_volume_xattr ( volume ) ;
if ( ret < 0 ) {
if ( ret ! = - ESTALE )
goto error_dir ;
inode_lock_nested ( d_inode ( cache - > store ) , I_MUTEX_PARENT ) ;
cachefiles_bury_object ( cache , NULL , cache - > store , vdentry ,
FSCACHE_VOLUME_IS_WEIRD ) ;
cachefiles_put_directory ( volume - > dentry ) ;
cond_resched ( ) ;
goto retry ;
}
}
2021-10-21 11:55:21 +03:00
for ( i = 0 ; i < 256 ; i + + ) {
sprintf ( name , " @%02x " , i ) ;
fan = cachefiles_get_directory ( cache , vdentry , name , NULL ) ;
if ( IS_ERR ( fan ) )
goto error_fan ;
volume - > fanout [ i ] = fan ;
}
cachefiles_end_secure ( cache , saved_cred ) ;
vcookie - > cache_priv = volume ;
n_accesses = atomic_inc_return ( & vcookie - > n_accesses ) ; /* Stop wakeups on dec-to-0 */
trace_fscache_access_volume ( vcookie - > debug_id , 0 ,
refcount_read ( & vcookie - > ref ) ,
n_accesses , fscache_access_cache_pin ) ;
spin_lock ( & cache - > object_list_lock ) ;
list_add ( & volume - > cache_link , & volume - > cache - > volumes ) ;
spin_unlock ( & cache - > object_list_lock ) ;
kfree ( name ) ;
return ;
error_fan :
for ( i = 0 ; i < 256 ; i + + )
cachefiles_put_directory ( volume - > fanout [ i ] ) ;
2021-12-14 12:51:43 +03:00
error_dir :
2021-10-21 11:55:21 +03:00
cachefiles_put_directory ( volume - > dentry ) ;
error_name :
kfree ( name ) ;
error_vol :
kfree ( volume ) ;
cachefiles_end_secure ( cache , saved_cred ) ;
}
/*
* Release a volume representation .
*/
static void __cachefiles_free_volume ( struct cachefiles_volume * volume )
{
int i ;
_enter ( " " ) ;
volume - > vcookie - > cache_priv = NULL ;
for ( i = 0 ; i < 256 ; i + + )
cachefiles_put_directory ( volume - > fanout [ i ] ) ;
cachefiles_put_directory ( volume - > dentry ) ;
kfree ( volume ) ;
}
void cachefiles_free_volume ( struct fscache_volume * vcookie )
{
struct cachefiles_volume * volume = vcookie - > cache_priv ;
if ( volume ) {
spin_lock ( & volume - > cache - > object_list_lock ) ;
list_del_init ( & volume - > cache_link ) ;
spin_unlock ( & volume - > cache - > object_list_lock ) ;
__cachefiles_free_volume ( volume ) ;
}
}
void cachefiles_withdraw_volume ( struct cachefiles_volume * volume )
{
fscache_withdraw_volume ( volume - > vcookie ) ;
2021-12-14 12:51:43 +03:00
cachefiles_set_volume_xattr ( volume ) ;
2021-10-21 11:55:21 +03:00
__cachefiles_free_volume ( volume ) ;
}