2017-03-17 09:18:50 +03:00
// SPDX-License-Identifier: GPL-2.0
# include "bcachefs.h"
# include "bkey_methods.h"
# include "btree_update.h"
# include "extents.h"
# include "fs.h"
# include "rebalance.h"
# include "str_hash.h"
# include "xattr.h"
# include <linux/dcache.h>
# include <linux/posix_acl_xattr.h>
# include <linux/xattr.h>
static const struct xattr_handler * bch2_xattr_type_to_handler ( unsigned ) ;
static u64 bch2_xattr_hash ( const struct bch_hash_info * info ,
const struct xattr_search_key * key )
{
struct bch_str_hash_ctx ctx ;
bch2_str_hash_init ( & ctx , info ) ;
bch2_str_hash_update ( & ctx , info , & key - > type , sizeof ( key - > type ) ) ;
bch2_str_hash_update ( & ctx , info , key - > name . name , key - > name . len ) ;
return bch2_str_hash_end ( & ctx , info ) ;
}
static u64 xattr_hash_key ( const struct bch_hash_info * info , const void * key )
{
return bch2_xattr_hash ( info , key ) ;
}
static u64 xattr_hash_bkey ( const struct bch_hash_info * info , struct bkey_s_c k )
{
struct bkey_s_c_xattr x = bkey_s_c_to_xattr ( k ) ;
return bch2_xattr_hash ( info ,
& X_SEARCH ( x . v - > x_type , x . v - > x_name , x . v - > x_name_len ) ) ;
}
static bool xattr_cmp_key ( struct bkey_s_c _l , const void * _r )
{
struct bkey_s_c_xattr l = bkey_s_c_to_xattr ( _l ) ;
const struct xattr_search_key * r = _r ;
return l . v - > x_type ! = r - > type | |
l . v - > x_name_len ! = r - > name . len | |
memcmp ( l . v - > x_name , r - > name . name , r - > name . len ) ;
}
static bool xattr_cmp_bkey ( struct bkey_s_c _l , struct bkey_s_c _r )
{
struct bkey_s_c_xattr l = bkey_s_c_to_xattr ( _l ) ;
struct bkey_s_c_xattr r = bkey_s_c_to_xattr ( _r ) ;
return l . v - > x_type ! = r . v - > x_type | |
l . v - > x_name_len ! = r . v - > x_name_len | |
memcmp ( l . v - > x_name , r . v - > x_name , r . v - > x_name_len ) ;
}
const struct bch_hash_desc bch2_xattr_hash_desc = {
2021-02-21 03:27:37 +03:00
. btree_id = BTREE_ID_xattrs ,
2018-11-01 22:10:01 +03:00
. key_type = KEY_TYPE_xattr ,
2017-03-17 09:18:50 +03:00
. hash_key = xattr_hash_key ,
. hash_bkey = xattr_hash_bkey ,
. cmp_key = xattr_cmp_key ,
. cmp_bkey = xattr_cmp_bkey ,
} ;
2022-04-04 00:50:01 +03:00
int bch2_xattr_invalid ( const struct bch_fs * c , struct bkey_s_c k ,
2022-04-04 04:50:25 +03:00
int rw , struct printbuf * err )
2017-03-17 09:18:50 +03:00
{
const struct xattr_handler * handler ;
2018-11-01 22:10:01 +03:00
struct bkey_s_c_xattr xattr = bkey_s_c_to_xattr ( k ) ;
2017-03-17 09:18:50 +03:00
2022-04-04 00:50:01 +03:00
if ( bkey_val_bytes ( k . k ) < sizeof ( struct bch_xattr ) ) {
2023-02-04 05:01:40 +03:00
prt_printf ( err , " incorrect value size (%zu < %zu) " ,
2022-04-04 00:50:01 +03:00
bkey_val_bytes ( k . k ) , sizeof ( * xattr . v ) ) ;
return - EINVAL ;
}
2017-03-17 09:18:50 +03:00
2018-11-01 22:10:01 +03:00
if ( bkey_val_u64s ( k . k ) <
xattr_val_u64s ( xattr . v - > x_name_len ,
2022-04-04 00:50:01 +03:00
le16_to_cpu ( xattr . v - > x_val_len ) ) ) {
2023-02-04 05:01:40 +03:00
prt_printf ( err , " value too small (%zu < %u) " ,
2022-04-04 00:50:01 +03:00
bkey_val_u64s ( k . k ) ,
xattr_val_u64s ( xattr . v - > x_name_len ,
le16_to_cpu ( xattr . v - > x_val_len ) ) ) ;
return - EINVAL ;
}
/* XXX why +4 ? */
2018-11-01 22:10:01 +03:00
if ( bkey_val_u64s ( k . k ) >
xattr_val_u64s ( xattr . v - > x_name_len ,
2022-04-04 00:50:01 +03:00
le16_to_cpu ( xattr . v - > x_val_len ) + 4 ) ) {
2023-02-04 05:01:40 +03:00
prt_printf ( err , " value too big (%zu > %u) " ,
2022-04-04 00:50:01 +03:00
bkey_val_u64s ( k . k ) ,
xattr_val_u64s ( xattr . v - > x_name_len ,
le16_to_cpu ( xattr . v - > x_val_len ) + 4 ) ) ;
return - EINVAL ;
}
2017-03-17 09:18:50 +03:00
2018-11-01 22:10:01 +03:00
handler = bch2_xattr_type_to_handler ( xattr . v - > x_type ) ;
2022-04-04 00:50:01 +03:00
if ( ! handler ) {
2023-02-04 05:01:40 +03:00
prt_printf ( err , " invalid type (%u) " , xattr . v - > x_type ) ;
2022-04-04 00:50:01 +03:00
return - EINVAL ;
}
2017-03-17 09:18:50 +03:00
2022-04-04 00:50:01 +03:00
if ( memchr ( xattr . v - > x_name , ' \0 ' , xattr . v - > x_name_len ) ) {
2023-02-04 05:01:40 +03:00
prt_printf ( err , " xattr name has invalid characters " ) ;
2022-04-04 00:50:01 +03:00
return - EINVAL ;
}
2017-03-17 09:18:50 +03:00
2022-04-04 00:50:01 +03:00
return 0 ;
2017-03-17 09:18:50 +03:00
}
2018-11-09 09:24:07 +03:00
void bch2_xattr_to_text ( struct printbuf * out , struct bch_fs * c ,
struct bkey_s_c k )
2017-03-17 09:18:50 +03:00
{
const struct xattr_handler * handler ;
2018-11-01 22:10:01 +03:00
struct bkey_s_c_xattr xattr = bkey_s_c_to_xattr ( k ) ;
2017-03-17 09:18:50 +03:00
2018-11-01 22:10:01 +03:00
handler = bch2_xattr_type_to_handler ( xattr . v - > x_type ) ;
if ( handler & & handler - > prefix )
2023-02-04 05:01:40 +03:00
prt_printf ( out , " %s " , handler - > prefix ) ;
2018-11-01 22:10:01 +03:00
else if ( handler )
2023-02-04 05:01:40 +03:00
prt_printf ( out , " (type %u) " , xattr . v - > x_type ) ;
2018-11-01 22:10:01 +03:00
else
2023-02-04 05:01:40 +03:00
prt_printf ( out , " (unknown type %u) " , xattr . v - > x_type ) ;
2017-03-17 09:18:50 +03:00
2023-02-04 05:01:40 +03:00
prt_printf ( out , " %.*s:%.*s " ,
2022-02-20 12:52:44 +03:00
xattr . v - > x_name_len ,
xattr . v - > x_name ,
le16_to_cpu ( xattr . v - > x_val_len ) ,
( char * ) xattr_val ( xattr . v ) ) ;
2017-03-17 09:18:50 +03:00
}
2021-07-21 04:07:21 +03:00
static int bch2_xattr_get_trans ( struct btree_trans * trans , struct bch_inode_info * inode ,
const char * name , void * buffer , size_t size , int type )
2017-03-17 09:18:50 +03:00
{
2021-07-21 04:07:21 +03:00
struct bch_hash_info hash = bch2_hash_info_init ( trans - > c , & inode - > ei_inode ) ;
2021-08-30 22:18:31 +03:00
struct btree_iter iter ;
2017-03-17 09:18:50 +03:00
struct bkey_s_c_xattr xattr ;
2021-07-25 02:50:40 +03:00
struct bkey_s_c k ;
2017-03-17 09:18:50 +03:00
int ret ;
2021-08-30 22:18:31 +03:00
ret = bch2_hash_lookup ( trans , & iter , bch2_xattr_hash_desc , & hash ,
2021-03-16 07:28:17 +03:00
inode_inum ( inode ) ,
2021-08-30 22:18:31 +03:00
& X_SEARCH ( type , name , strlen ( name ) ) ,
0 ) ;
2021-03-20 03:29:11 +03:00
if ( ret )
2021-08-30 22:18:31 +03:00
goto err1 ;
2017-03-17 09:18:50 +03:00
2021-08-30 22:18:31 +03:00
k = bch2_btree_iter_peek_slot ( & iter ) ;
2021-07-25 02:50:40 +03:00
ret = bkey_err ( k ) ;
if ( ret )
2021-08-30 22:18:31 +03:00
goto err2 ;
2021-07-25 02:50:40 +03:00
xattr = bkey_s_c_to_xattr ( k ) ;
2017-03-17 09:18:50 +03:00
ret = le16_to_cpu ( xattr . v - > x_val_len ) ;
if ( buffer ) {
if ( ret > size )
ret = - ERANGE ;
else
memcpy ( buffer , xattr_val ( xattr . v ) , ret ) ;
}
2021-08-30 22:18:31 +03:00
err2 :
bch2_trans_iter_exit ( trans , & iter ) ;
err1 :
2021-03-20 03:29:11 +03:00
return ret = = - ENOENT ? - ENODATA : ret ;
2017-03-17 09:18:50 +03:00
}
2021-07-21 04:07:21 +03:00
int bch2_xattr_get ( struct bch_fs * c , struct bch_inode_info * inode ,
const char * name , void * buffer , size_t size , int type )
{
return bch2_trans_do ( c , NULL , NULL , 0 ,
bch2_xattr_get_trans ( & trans , inode , name , buffer , size , type ) ) ;
}
2021-03-16 07:28:17 +03:00
int bch2_xattr_set ( struct btree_trans * trans , subvol_inum inum ,
2017-03-17 09:18:50 +03:00
const struct bch_hash_info * hash_info ,
const char * name , const void * value , size_t size ,
int type , int flags )
{
2021-11-05 22:17:13 +03:00
struct btree_iter inode_iter = { NULL } ;
struct bch_inode_unpacked inode_u ;
2017-03-17 09:18:50 +03:00
int ret ;
2021-11-05 22:17:13 +03:00
/*
* We need to do an inode update so that bi_journal_sync gets updated
* and fsync works :
*
* Perhaps we should be updating bi_mtime too ?
*/
ret = bch2_inode_peek ( trans , & inode_iter , & inode_u , inum , BTREE_ITER_INTENT ) ? :
bch2_inode_write ( trans , & inode_iter , & inode_u ) ;
bch2_trans_iter_exit ( trans , & inode_iter ) ;
if ( ret )
return ret ;
2017-03-17 09:18:50 +03:00
if ( value ) {
struct bkey_i_xattr * xattr ;
unsigned namelen = strlen ( name ) ;
unsigned u64s = BKEY_U64s +
xattr_val_u64s ( namelen , size ) ;
if ( u64s > U8_MAX )
return - ERANGE ;
xattr = bch2_trans_kmalloc ( trans , u64s * sizeof ( u64 ) ) ;
if ( IS_ERR ( xattr ) )
return PTR_ERR ( xattr ) ;
bkey_xattr_init ( & xattr - > k_i ) ;
xattr - > k . u64s = u64s ;
xattr - > v . x_type = type ;
xattr - > v . x_name_len = namelen ;
xattr - > v . x_val_len = cpu_to_le16 ( size ) ;
memcpy ( xattr - > v . x_name , name , namelen ) ;
memcpy ( xattr_val ( & xattr - > v ) , value , size ) ;
2019-03-14 03:49:16 +03:00
ret = bch2_hash_set ( trans , bch2_xattr_hash_desc , hash_info ,
2017-03-17 09:18:50 +03:00
inum , & xattr - > k_i ,
( flags & XATTR_CREATE ? BCH_HASH_SET_MUST_CREATE : 0 ) |
( flags & XATTR_REPLACE ? BCH_HASH_SET_MUST_REPLACE : 0 ) ) ;
} else {
struct xattr_search_key search =
X_SEARCH ( type , name , strlen ( name ) ) ;
ret = bch2_hash_delete ( trans , bch2_xattr_hash_desc ,
hash_info , inum , & search ) ;
}
if ( ret = = - ENOENT )
ret = flags & XATTR_REPLACE ? - ENODATA : 0 ;
return ret ;
}
2019-04-17 22:49:28 +03:00
struct xattr_buf {
char * buf ;
size_t len ;
size_t used ;
} ;
static int __bch2_xattr_emit ( const char * prefix ,
const char * name , size_t name_len ,
struct xattr_buf * buf )
2018-12-17 13:31:09 +03:00
{
const size_t prefix_len = strlen ( prefix ) ;
const size_t total_len = prefix_len + name_len + 1 ;
2019-04-17 22:49:28 +03:00
if ( buf - > buf ) {
if ( buf - > used + total_len > buf - > len )
return - ERANGE ;
2018-12-17 13:31:09 +03:00
2019-04-17 22:49:28 +03:00
memcpy ( buf - > buf + buf - > used , prefix , prefix_len ) ;
memcpy ( buf - > buf + buf - > used + prefix_len ,
2018-12-17 13:31:09 +03:00
name , name_len ) ;
2019-04-17 22:49:28 +03:00
buf - > buf [ buf - > used + prefix_len + name_len ] = ' \0 ' ;
2018-12-17 13:31:09 +03:00
}
2019-04-17 22:49:28 +03:00
buf - > used + = total_len ;
return 0 ;
2018-12-17 13:31:09 +03:00
}
2019-04-17 22:49:28 +03:00
static int bch2_xattr_emit ( struct dentry * dentry ,
2018-12-17 13:31:09 +03:00
const struct bch_xattr * xattr ,
2019-04-17 22:49:28 +03:00
struct xattr_buf * buf )
2017-03-17 09:18:50 +03:00
{
const struct xattr_handler * handler =
bch2_xattr_type_to_handler ( xattr - > x_type ) ;
2019-04-17 22:49:28 +03:00
return handler & & ( ! handler - > list | | handler - > list ( dentry ) )
? __bch2_xattr_emit ( handler - > prefix ? : handler - > name ,
xattr - > x_name , xattr - > x_name_len , buf )
: 0 ;
2018-12-17 13:31:09 +03:00
}
2017-03-17 09:18:50 +03:00
2019-04-17 22:49:28 +03:00
static int bch2_xattr_list_bcachefs ( struct bch_fs * c ,
2021-03-03 02:35:30 +03:00
struct bch_inode_unpacked * inode ,
2019-04-17 22:49:28 +03:00
struct xattr_buf * buf ,
bool all )
2018-12-17 13:31:09 +03:00
{
const char * prefix = all ? " bcachefs_effective. " : " bcachefs. " ;
unsigned id ;
2019-04-17 22:49:28 +03:00
int ret = 0 ;
2018-12-17 13:31:09 +03:00
u64 v ;
2017-03-17 09:18:50 +03:00
2018-12-17 13:31:09 +03:00
for ( id = 0 ; id < Inode_opt_nr ; id + + ) {
2021-03-03 02:35:30 +03:00
v = bch2_inode_opt_get ( inode , id ) ;
2018-12-17 13:31:09 +03:00
if ( ! v )
continue ;
if ( ! all & &
2021-03-03 02:35:30 +03:00
! ( inode - > bi_fields_set & ( 1 < < id ) ) )
2018-12-17 13:31:09 +03:00
continue ;
2019-04-17 22:49:28 +03:00
ret = __bch2_xattr_emit ( prefix , bch2_inode_opts [ id ] ,
strlen ( bch2_inode_opts [ id ] ) , buf ) ;
if ( ret )
2018-12-17 13:31:09 +03:00
break ;
2017-03-17 09:18:50 +03:00
}
2019-04-17 22:49:28 +03:00
return ret ;
2017-03-17 09:18:50 +03:00
}
ssize_t bch2_xattr_list ( struct dentry * dentry , char * buffer , size_t buffer_size )
{
struct bch_fs * c = dentry - > d_sb - > s_fs_info ;
2018-12-17 13:31:09 +03:00
struct bch_inode_info * inode = to_bch_ei ( dentry - > d_inode ) ;
2019-03-25 22:10:15 +03:00
struct btree_trans trans ;
2021-08-30 22:18:31 +03:00
struct btree_iter iter ;
2017-03-17 09:18:50 +03:00
struct bkey_s_c k ;
2019-04-17 22:49:28 +03:00
struct xattr_buf buf = { . buf = buffer , . len = buffer_size } ;
2021-03-16 07:28:17 +03:00
u64 offset = 0 , inum = inode - > ei_inode . bi_inum ;
u32 snapshot ;
2019-04-17 22:49:28 +03:00
int ret ;
2017-03-17 09:18:50 +03:00
2019-05-15 17:54:43 +03:00
bch2_trans_init ( & trans , c , 0 , 0 ) ;
2021-03-16 07:28:17 +03:00
retry :
bch2_trans_begin ( & trans ) ;
iter = ( struct btree_iter ) { NULL } ;
ret = bch2_subvolume_get_snapshot ( & trans , inode - > ei_subvol , & snapshot ) ;
if ( ret )
goto err ;
2019-03-25 22:10:15 +03:00
2022-03-11 20:31:52 +03:00
for_each_btree_key_upto_norestart ( & trans , iter , BTREE_ID_xattrs ,
SPOS ( inum , offset , snapshot ) ,
POS ( inum , U64_MAX ) , 0 , k , ret ) {
2018-11-01 22:10:01 +03:00
if ( k . k - > type ! = KEY_TYPE_xattr )
2017-03-17 09:18:50 +03:00
continue ;
2019-04-17 22:49:28 +03:00
ret = bch2_xattr_emit ( dentry , bkey_s_c_to_xattr ( k ) . v , & buf ) ;
if ( ret )
2018-12-17 13:31:09 +03:00
break ;
}
2021-03-16 07:28:17 +03:00
offset = iter . pos . offset ;
2021-08-30 22:18:31 +03:00
bch2_trans_iter_exit ( & trans , & iter ) ;
2021-03-16 07:28:17 +03:00
err :
2022-07-18 06:06:38 +03:00
if ( bch2_err_matches ( ret , BCH_ERR_transaction_restart ) )
2021-03-16 07:28:17 +03:00
goto retry ;
2021-03-20 03:29:11 +03:00
2021-10-19 22:08:00 +03:00
bch2_trans_exit ( & trans ) ;
2017-03-17 09:18:50 +03:00
2019-04-17 22:49:28 +03:00
if ( ret )
2022-09-18 22:43:50 +03:00
goto out ;
2017-03-17 09:18:50 +03:00
2021-03-03 02:35:30 +03:00
ret = bch2_xattr_list_bcachefs ( c , & inode - > ei_inode , & buf , false ) ;
2019-04-17 22:49:28 +03:00
if ( ret )
2022-09-18 22:43:50 +03:00
goto out ;
2017-03-17 09:18:50 +03:00
2021-03-03 02:35:30 +03:00
ret = bch2_xattr_list_bcachefs ( c , & inode - > ei_inode , & buf , true ) ;
2019-04-17 22:49:28 +03:00
if ( ret )
2022-09-18 22:43:50 +03:00
goto out ;
2017-03-17 09:18:50 +03:00
2019-04-17 22:49:28 +03:00
return buf . used ;
2022-09-18 22:43:50 +03:00
out :
return bch2_err_class ( ret ) ;
2017-03-17 09:18:50 +03:00
}
static int bch2_xattr_get_handler ( const struct xattr_handler * handler ,
struct dentry * dentry , struct inode * vinode ,
const char * name , void * buffer , size_t size )
{
struct bch_inode_info * inode = to_bch_ei ( vinode ) ;
struct bch_fs * c = inode - > v . i_sb - > s_fs_info ;
2022-09-18 22:43:50 +03:00
int ret ;
2017-03-17 09:18:50 +03:00
2022-09-18 22:43:50 +03:00
ret = bch2_xattr_get ( c , inode , name , buffer , size , handler - > flags ) ;
return bch2_err_class ( ret ) ;
2017-03-17 09:18:50 +03:00
}
static int bch2_xattr_set_handler ( const struct xattr_handler * handler ,
struct mnt_idmap * idmap ,
struct dentry * dentry , struct inode * vinode ,
const char * name , const void * value ,
size_t size , int flags )
{
struct bch_inode_info * inode = to_bch_ei ( vinode ) ;
struct bch_fs * c = inode - > v . i_sb - > s_fs_info ;
2021-03-03 02:35:30 +03:00
struct bch_hash_info hash = bch2_hash_info_init ( c , & inode - > ei_inode ) ;
2022-09-18 22:43:50 +03:00
int ret ;
2017-03-17 09:18:50 +03:00
2022-09-18 22:43:50 +03:00
ret = bch2_trans_do ( c , NULL , NULL , 0 ,
2021-03-16 07:28:17 +03:00
bch2_xattr_set ( & trans , inode_inum ( inode ) , & hash ,
2017-03-17 09:18:50 +03:00
name , value , size ,
handler - > flags , flags ) ) ;
2022-09-18 22:43:50 +03:00
return bch2_err_class ( ret ) ;
2017-03-17 09:18:50 +03:00
}
static const struct xattr_handler bch_xattr_user_handler = {
. prefix = XATTR_USER_PREFIX ,
. get = bch2_xattr_get_handler ,
. set = bch2_xattr_set_handler ,
2018-11-01 22:10:01 +03:00
. flags = KEY_TYPE_XATTR_INDEX_USER ,
2017-03-17 09:18:50 +03:00
} ;
static bool bch2_xattr_trusted_list ( struct dentry * dentry )
{
return capable ( CAP_SYS_ADMIN ) ;
}
static const struct xattr_handler bch_xattr_trusted_handler = {
. prefix = XATTR_TRUSTED_PREFIX ,
. list = bch2_xattr_trusted_list ,
. get = bch2_xattr_get_handler ,
. set = bch2_xattr_set_handler ,
2018-11-01 22:10:01 +03:00
. flags = KEY_TYPE_XATTR_INDEX_TRUSTED ,
2017-03-17 09:18:50 +03:00
} ;
static const struct xattr_handler bch_xattr_security_handler = {
. prefix = XATTR_SECURITY_PREFIX ,
. get = bch2_xattr_get_handler ,
. set = bch2_xattr_set_handler ,
2018-11-01 22:10:01 +03:00
. flags = KEY_TYPE_XATTR_INDEX_SECURITY ,
2017-03-17 09:18:50 +03:00
} ;
# ifndef NO_BCACHEFS_FS
2018-12-17 13:31:09 +03:00
static int opt_to_inode_opt ( int id )
{
switch ( id ) {
# define x(name, ...) \
case Opt_ # # name : return Inode_opt_ # # name ;
BCH_INODE_OPTS ( )
# undef x
default :
return - 1 ;
}
}
static int __bch2_xattr_bcachefs_get ( const struct xattr_handler * handler ,
struct dentry * dentry , struct inode * vinode ,
const char * name , void * buffer , size_t size ,
bool all )
2017-03-17 09:18:50 +03:00
{
struct bch_inode_info * inode = to_bch_ei ( vinode ) ;
struct bch_fs * c = inode - > v . i_sb - > s_fs_info ;
struct bch_opts opts =
bch2_inode_opts_to_opts ( bch2_inode_opts_get ( & inode - > ei_inode ) ) ;
const struct bch_option * opt ;
2018-12-17 13:31:09 +03:00
int id , inode_opt_id ;
2022-02-25 21:18:19 +03:00
struct printbuf out = PRINTBUF ;
int ret ;
2017-03-17 09:18:50 +03:00
u64 v ;
id = bch2_opt_lookup ( name ) ;
if ( id < 0 | | ! bch2_opt_is_inode_opt ( id ) )
return - EINVAL ;
2018-12-17 13:31:09 +03:00
inode_opt_id = opt_to_inode_opt ( id ) ;
if ( inode_opt_id < 0 )
return - EINVAL ;
2017-03-17 09:18:50 +03:00
opt = bch2_opt_table + id ;
if ( ! bch2_opt_defined_by_id ( & opts , id ) )
return - ENODATA ;
2018-12-17 13:31:09 +03:00
if ( ! all & &
! ( inode - > ei_inode . bi_fields_set & ( 1 < < inode_opt_id ) ) )
return - ENODATA ;
2017-03-17 09:18:50 +03:00
v = bch2_opt_get_by_id ( & opts , id ) ;
2022-03-05 20:01:16 +03:00
bch2_opt_to_text ( & out , c , c - > disk_sb . sb , opt , v , 0 ) ;
2017-03-17 09:18:50 +03:00
2022-02-25 21:18:19 +03:00
ret = out . pos ;
2017-03-17 09:18:50 +03:00
2022-02-25 21:18:19 +03:00
if ( out . allocation_failure ) {
ret = - ENOMEM ;
} else if ( buffer ) {
if ( out . pos > size )
ret = - ERANGE ;
else
memcpy ( buffer , out . buf , out . pos ) ;
}
2018-11-09 09:24:07 +03:00
2022-02-25 21:18:19 +03:00
printbuf_exit ( & out ) ;
return ret ;
2017-03-17 09:18:50 +03:00
}
2018-12-17 13:31:09 +03:00
static int bch2_xattr_bcachefs_get ( const struct xattr_handler * handler ,
struct dentry * dentry , struct inode * vinode ,
const char * name , void * buffer , size_t size )
{
return __bch2_xattr_bcachefs_get ( handler , dentry , vinode ,
name , buffer , size , false ) ;
}
2017-03-17 09:18:50 +03:00
struct inode_opt_set {
int id ;
u64 v ;
bool defined ;
} ;
static int inode_opt_set_fn ( struct bch_inode_info * inode ,
struct bch_inode_unpacked * bi ,
void * p )
{
struct inode_opt_set * s = p ;
if ( s - > defined )
2018-12-17 13:31:09 +03:00
bi - > bi_fields_set | = 1U < < s - > id ;
2017-03-17 09:18:50 +03:00
else
2018-12-17 13:31:09 +03:00
bi - > bi_fields_set & = ~ ( 1U < < s - > id ) ;
bch2_inode_opt_set ( bi , s - > id , s - > v ) ;
2017-03-17 09:18:50 +03:00
return 0 ;
}
static int bch2_xattr_bcachefs_set ( const struct xattr_handler * handler ,
struct mnt_idmap * idmap ,
struct dentry * dentry , struct inode * vinode ,
const char * name , const void * value ,
size_t size , int flags )
{
struct bch_inode_info * inode = to_bch_ei ( vinode ) ;
struct bch_fs * c = inode - > v . i_sb - > s_fs_info ;
const struct bch_option * opt ;
char * buf ;
struct inode_opt_set s ;
2018-12-17 13:31:09 +03:00
int opt_id , inode_opt_id , ret ;
opt_id = bch2_opt_lookup ( name ) ;
if ( opt_id < 0 )
return - EINVAL ;
2017-03-17 09:18:50 +03:00
2018-12-17 13:31:09 +03:00
opt = bch2_opt_table + opt_id ;
inode_opt_id = opt_to_inode_opt ( opt_id ) ;
if ( inode_opt_id < 0 )
2017-03-17 09:18:50 +03:00
return - EINVAL ;
2018-12-17 13:31:09 +03:00
s . id = inode_opt_id ;
2017-03-17 09:18:50 +03:00
if ( value ) {
2018-12-17 13:31:09 +03:00
u64 v = 0 ;
2017-03-17 09:18:50 +03:00
buf = kmalloc ( size + 1 , GFP_KERNEL ) ;
if ( ! buf )
return - ENOMEM ;
memcpy ( buf , value , size ) ;
buf [ size ] = ' \0 ' ;
2022-03-21 07:15:38 +03:00
ret = bch2_opt_parse ( c , opt , buf , & v , NULL ) ;
2017-03-17 09:18:50 +03:00
kfree ( buf ) ;
if ( ret < 0 )
return ret ;
2018-12-17 13:31:09 +03:00
ret = bch2_opt_check_may_set ( c , opt_id , v ) ;
2018-11-13 02:30:55 +03:00
if ( ret < 0 )
return ret ;
2017-03-17 09:18:50 +03:00
2018-12-17 13:31:09 +03:00
s . v = v + 1 ;
2017-03-17 09:18:50 +03:00
s . defined = true ;
} else {
2018-12-17 13:31:09 +03:00
if ( ! IS_ROOT ( dentry ) ) {
struct bch_inode_info * dir =
to_bch_ei ( d_inode ( dentry - > d_parent ) ) ;
s . v = bch2_inode_opt_get ( & dir - > ei_inode , inode_opt_id ) ;
} else {
s . v = 0 ;
}
2017-03-17 09:18:50 +03:00
s . defined = false ;
}
mutex_lock ( & inode - > ei_update_lock ) ;
2018-12-19 16:43:01 +03:00
if ( inode_opt_id = = Inode_opt_project ) {
2020-08-24 21:57:48 +03:00
/*
* inode fields accessible via the xattr interface are stored
* with a + 1 bias , so that 0 means unset :
*/
ret = bch2_set_projid ( c , inode , s . v ? s . v - 1 : 0 ) ;
2018-12-19 16:43:01 +03:00
if ( ret )
goto err ;
}
2018-07-17 21:12:42 +03:00
ret = bch2_write_inode ( c , inode , inode_opt_set_fn , & s , 0 ) ;
2018-12-19 16:43:01 +03:00
err :
2017-03-17 09:18:50 +03:00
mutex_unlock ( & inode - > ei_update_lock ) ;
if ( value & &
2018-12-17 13:31:09 +03:00
( opt_id = = Opt_background_compression | |
opt_id = = Opt_background_target ) )
2017-03-17 09:18:50 +03:00
bch2_rebalance_add_work ( c , inode - > v . i_blocks ) ;
return ret ;
}
static const struct xattr_handler bch_xattr_bcachefs_handler = {
. prefix = " bcachefs. " ,
. get = bch2_xattr_bcachefs_get ,
. set = bch2_xattr_bcachefs_set ,
} ;
2018-12-17 13:31:09 +03:00
static int bch2_xattr_bcachefs_get_effective (
const struct xattr_handler * handler ,
struct dentry * dentry , struct inode * vinode ,
const char * name , void * buffer , size_t size )
{
return __bch2_xattr_bcachefs_get ( handler , dentry , vinode ,
name , buffer , size , true ) ;
}
static const struct xattr_handler bch_xattr_bcachefs_effective_handler = {
. prefix = " bcachefs_effective. " ,
. get = bch2_xattr_bcachefs_get_effective ,
. set = bch2_xattr_bcachefs_set ,
} ;
2017-03-17 09:18:50 +03:00
# endif /* NO_BCACHEFS_FS */
const struct xattr_handler * bch2_xattr_handlers [ ] = {
& bch_xattr_user_handler ,
2021-06-06 02:03:16 +03:00
# ifdef CONFIG_BCACHEFS_POSIX_ACL
2017-03-17 09:18:50 +03:00
& nop_posix_acl_access ,
& nop_posix_acl_default ,
2021-06-06 02:03:16 +03:00
# endif
2017-03-17 09:18:50 +03:00
& bch_xattr_trusted_handler ,
& bch_xattr_security_handler ,
# ifndef NO_BCACHEFS_FS
& bch_xattr_bcachefs_handler ,
2018-12-17 13:31:09 +03:00
& bch_xattr_bcachefs_effective_handler ,
2017-03-17 09:18:50 +03:00
# endif
NULL
} ;
static const struct xattr_handler * bch_xattr_handler_map [ ] = {
2018-11-01 22:10:01 +03:00
[ KEY_TYPE_XATTR_INDEX_USER ] = & bch_xattr_user_handler ,
[ KEY_TYPE_XATTR_INDEX_POSIX_ACL_ACCESS ] =
2017-03-17 09:18:50 +03:00
& nop_posix_acl_access ,
2018-11-01 22:10:01 +03:00
[ KEY_TYPE_XATTR_INDEX_POSIX_ACL_DEFAULT ] =
2017-03-17 09:18:50 +03:00
& nop_posix_acl_default ,
2018-11-01 22:10:01 +03:00
[ KEY_TYPE_XATTR_INDEX_TRUSTED ] = & bch_xattr_trusted_handler ,
[ KEY_TYPE_XATTR_INDEX_SECURITY ] = & bch_xattr_security_handler ,
2017-03-17 09:18:50 +03:00
} ;
static const struct xattr_handler * bch2_xattr_type_to_handler ( unsigned type )
{
return type < ARRAY_SIZE ( bch_xattr_handler_map )
? bch_xattr_handler_map [ type ]
: NULL ;
}