2019-07-31 18:57:31 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2018-07-26 15:21:52 +03:00
/*
* Copyright ( C ) 2017 - 2018 HUAWEI , Inc .
2020-07-13 16:09:44 +03:00
* https : //www.huawei.com/
2022-01-02 07:00:16 +03:00
* Copyright ( C ) 2021 - 2022 , Alibaba Cloud
2018-07-26 15:21:52 +03:00
*/
# include <linux/security.h>
2023-07-22 12:45:38 +03:00
# include <linux/xxhash.h>
2018-07-26 15:21:52 +03:00
# include "xattr.h"
2023-06-13 10:41:11 +03:00
struct erofs_xattr_iter {
2018-07-26 15:21:52 +03:00
struct super_block * sb ;
2022-01-02 07:00:16 +03:00
struct erofs_buf buf ;
2023-06-13 10:41:10 +03:00
erofs_off_t pos ;
2018-07-26 15:21:52 +03:00
void * kaddr ;
2023-06-13 10:41:11 +03:00
char * buffer ;
int buffer_size , buffer_ofs ;
/* getxattr */
int index , infix_len ;
struct qstr name ;
/* listxattr */
struct dentry * dentry ;
2018-07-26 15:21:52 +03:00
} ;
2023-03-30 11:29:04 +03:00
static int erofs_init_inode_xattrs ( struct inode * inode )
2018-07-26 15:21:52 +03:00
{
2019-09-04 05:08:56 +03:00
struct erofs_inode * const vi = EROFS_I ( inode ) ;
2023-06-13 10:41:11 +03:00
struct erofs_xattr_iter it ;
2018-09-10 22:41:14 +03:00
unsigned int i ;
2018-07-26 15:21:52 +03:00
struct erofs_xattr_ibody_header * ih ;
2023-01-14 18:08:23 +03:00
struct super_block * sb = inode - > i_sb ;
2019-02-18 10:19:04 +03:00
int ret = 0 ;
2018-07-26 15:21:52 +03:00
2019-02-18 10:19:04 +03:00
/* the most case is that xattrs of this inode are initialized. */
2021-02-09 16:06:18 +03:00
if ( test_bit ( EROFS_I_EA_INITED_BIT , & vi - > flags ) ) {
/*
* paired with smp_mb ( ) at the end of the function to ensure
* fields will only be observed after the bit is set .
*/
smp_mb ( ) ;
2018-08-21 17:49:31 +03:00
return 0 ;
2021-02-09 16:06:18 +03:00
}
2018-07-26 15:21:52 +03:00
2019-09-04 05:08:56 +03:00
if ( wait_on_bit_lock ( & vi - > flags , EROFS_I_BL_XATTR_BIT , TASK_KILLABLE ) )
2019-02-18 10:19:04 +03:00
return - ERESTARTSYS ;
/* someone has initialized xattrs for us? */
2019-09-04 05:08:56 +03:00
if ( test_bit ( EROFS_I_EA_INITED_BIT , & vi - > flags ) )
2019-02-18 10:19:04 +03:00
goto out_unlock ;
2019-01-14 14:40:23 +03:00
/*
* bypass all xattr operations if - > xattr_isize is not greater than
* sizeof ( struct erofs_xattr_ibody_header ) , in detail :
* 1 ) it is not enough to contain erofs_xattr_ibody_header then
* - > xattr_isize should be 0 ( it means no xattr ) ;
* 2 ) it is just to contain erofs_xattr_ibody_header , which is on - disk
* undefined right now ( maybe use later with some new sb feature ) .
*/
if ( vi - > xattr_isize = = sizeof ( struct erofs_xattr_ibody_header ) ) {
2023-01-14 18:08:23 +03:00
erofs_err ( sb ,
2019-09-04 05:09:09 +03:00
" xattr_isize %d of nid %llu is not supported yet " ,
vi - > xattr_isize , vi - > nid ) ;
2019-08-14 13:37:05 +03:00
ret = - EOPNOTSUPP ;
2019-02-18 10:19:04 +03:00
goto out_unlock ;
2019-01-14 14:40:23 +03:00
} else if ( vi - > xattr_isize < sizeof ( struct erofs_xattr_ibody_header ) ) {
2019-08-29 19:38:27 +03:00
if ( vi - > xattr_isize ) {
2023-01-14 18:08:23 +03:00
erofs_err ( sb , " bogus xattr ibody @ nid %llu " , vi - > nid ) ;
2019-01-14 14:40:23 +03:00
DBG_BUGON ( 1 ) ;
2019-08-14 13:37:03 +03:00
ret = - EFSCORRUPTED ;
2019-02-18 10:19:04 +03:00
goto out_unlock ; /* xattr ondisk layout error */
2019-01-14 14:40:23 +03:00
}
2019-02-18 10:19:04 +03:00
ret = - ENOATTR ;
goto out_unlock ;
2019-01-14 14:40:23 +03:00
}
2018-07-26 15:21:52 +03:00
2022-01-02 07:00:16 +03:00
it . buf = __EROFS_BUF_INITIALIZER ;
2023-06-01 05:43:42 +03:00
erofs_init_metabuf ( & it . buf , sb ) ;
2023-06-13 10:41:10 +03:00
it . pos = erofs_iloc ( inode ) + vi - > inode_isize ;
2018-07-26 15:21:52 +03:00
2022-01-02 07:00:16 +03:00
/* read in shared xattr array (non-atomic, see kmalloc below) */
2023-06-13 10:41:10 +03:00
it . kaddr = erofs_bread ( & it . buf , erofs_blknr ( sb , it . pos ) , EROFS_KMAP ) ;
2022-01-02 07:00:16 +03:00
if ( IS_ERR ( it . kaddr ) ) {
ret = PTR_ERR ( it . kaddr ) ;
2019-02-18 10:19:04 +03:00
goto out_unlock ;
}
2018-07-26 15:21:52 +03:00
2023-06-13 10:41:10 +03:00
ih = it . kaddr + erofs_blkoff ( sb , it . pos ) ;
2023-07-22 12:45:38 +03:00
vi - > xattr_name_filter = le32_to_cpu ( ih - > h_name_filter ) ;
2018-07-26 15:21:52 +03:00
vi - > xattr_shared_count = ih - > h_shared_count ;
2018-08-21 17:49:31 +03:00
vi - > xattr_shared_xattrs = kmalloc_array ( vi - > xattr_shared_count ,
sizeof ( uint ) , GFP_KERNEL ) ;
2019-03-22 05:38:16 +03:00
if ( ! vi - > xattr_shared_xattrs ) {
2022-01-02 07:00:16 +03:00
erofs_put_metabuf ( & it . buf ) ;
2019-02-18 10:19:04 +03:00
ret = - ENOMEM ;
goto out_unlock ;
2018-08-21 17:49:31 +03:00
}
2018-07-26 15:21:52 +03:00
/* let's skip ibody header */
2023-06-13 10:41:10 +03:00
it . pos + = sizeof ( struct erofs_xattr_ibody_header ) ;
2018-07-26 15:21:52 +03:00
for ( i = 0 ; i < vi - > xattr_shared_count ; + + i ) {
2023-06-13 10:41:10 +03:00
it . kaddr = erofs_bread ( & it . buf , erofs_blknr ( sb , it . pos ) ,
EROFS_KMAP ) ;
if ( IS_ERR ( it . kaddr ) ) {
kfree ( vi - > xattr_shared_xattrs ) ;
vi - > xattr_shared_xattrs = NULL ;
ret = PTR_ERR ( it . kaddr ) ;
goto out_unlock ;
2018-07-26 15:21:52 +03:00
}
2023-06-13 10:41:10 +03:00
vi - > xattr_shared_xattrs [ i ] = le32_to_cpu ( * ( __le32 * )
( it . kaddr + erofs_blkoff ( sb , it . pos ) ) ) ;
it . pos + = sizeof ( __le32 ) ;
2018-07-26 15:21:52 +03:00
}
2022-01-02 07:00:16 +03:00
erofs_put_metabuf ( & it . buf ) ;
2018-07-26 15:21:52 +03:00
2021-02-09 16:06:18 +03:00
/* paired with smp_mb() at the beginning of the function. */
smp_mb ( ) ;
2019-09-04 05:08:56 +03:00
set_bit ( EROFS_I_EA_INITED_BIT , & vi - > flags ) ;
2019-02-18 10:19:04 +03:00
out_unlock :
2019-09-04 05:08:56 +03:00
clear_and_wake_up_bit ( EROFS_I_BL_XATTR_BIT , & vi - > flags ) ;
2019-02-18 10:19:04 +03:00
return ret ;
2018-07-26 15:21:52 +03:00
}
static bool erofs_xattr_user_list ( struct dentry * dentry )
{
2021-10-07 10:02:23 +03:00
return test_opt ( & EROFS_SB ( dentry - > d_sb ) - > opt , XATTR_USER ) ;
2018-07-26 15:21:52 +03:00
}
static bool erofs_xattr_trusted_list ( struct dentry * dentry )
{
return capable ( CAP_SYS_ADMIN ) ;
}
static int erofs_xattr_generic_get ( const struct xattr_handler * handler ,
2019-03-19 02:58:41 +03:00
struct dentry * unused , struct inode * inode ,
const char * name , void * buffer , size_t size )
2018-07-26 15:21:52 +03:00
{
2023-03-30 11:29:05 +03:00
if ( handler - > flags = = EROFS_XATTR_INDEX_USER & &
! test_opt ( & EROFS_I_SB ( inode ) - > opt , XATTR_USER ) )
return - EOPNOTSUPP ;
2018-07-26 15:21:52 +03:00
return erofs_getxattr ( inode , handler - > flags , name , buffer , size ) ;
}
const struct xattr_handler erofs_xattr_user_handler = {
. prefix = XATTR_USER_PREFIX ,
. flags = EROFS_XATTR_INDEX_USER ,
. list = erofs_xattr_user_list ,
. get = erofs_xattr_generic_get ,
} ;
const struct xattr_handler erofs_xattr_trusted_handler = {
. prefix = XATTR_TRUSTED_PREFIX ,
. flags = EROFS_XATTR_INDEX_TRUSTED ,
. list = erofs_xattr_trusted_list ,
. get = erofs_xattr_generic_get ,
} ;
# ifdef CONFIG_EROFS_FS_SECURITY
const struct xattr_handler __maybe_unused erofs_xattr_security_handler = {
. prefix = XATTR_SECURITY_PREFIX ,
. flags = EROFS_XATTR_INDEX_SECURITY ,
. get = erofs_xattr_generic_get ,
} ;
# endif
2023-09-30 08:00:12 +03:00
const struct xattr_handler * const erofs_xattr_handlers [ ] = {
2018-07-26 15:21:52 +03:00
& erofs_xattr_user_handler ,
& erofs_xattr_trusted_handler ,
# ifdef CONFIG_EROFS_FS_SECURITY
& erofs_xattr_security_handler ,
# endif
NULL ,
} ;
2023-06-13 10:41:14 +03:00
static int erofs_xattr_copy_to_buffer ( struct erofs_xattr_iter * it ,
unsigned int len )
{
unsigned int slice , processed ;
struct super_block * sb = it - > sb ;
void * src ;
for ( processed = 0 ; processed < len ; processed + = slice ) {
it - > kaddr = erofs_bread ( & it - > buf , erofs_blknr ( sb , it - > pos ) ,
EROFS_KMAP ) ;
if ( IS_ERR ( it - > kaddr ) )
return PTR_ERR ( it - > kaddr ) ;
src = it - > kaddr + erofs_blkoff ( sb , it - > pos ) ;
slice = min_t ( unsigned int , sb - > s_blocksize -
erofs_blkoff ( sb , it - > pos ) , len - processed ) ;
memcpy ( it - > buffer + it - > buffer_ofs , src , slice ) ;
it - > buffer_ofs + = slice ;
it - > pos + = slice ;
}
return 0 ;
}
static int erofs_listxattr_foreach ( struct erofs_xattr_iter * it )
2018-07-26 15:21:52 +03:00
{
2023-06-13 10:41:14 +03:00
struct erofs_xattr_entry entry ;
unsigned int base_index , name_total , prefix_len , infix_len = 0 ;
2023-04-11 12:35:37 +03:00
const char * prefix , * infix = NULL ;
2023-06-13 10:41:14 +03:00
int err ;
2023-04-11 12:35:37 +03:00
2023-06-13 10:41:14 +03:00
/* 1. handle xattr entry */
entry = * ( struct erofs_xattr_entry * )
( it - > kaddr + erofs_blkoff ( it - > sb , it - > pos ) ) ;
it - > pos + = sizeof ( struct erofs_xattr_entry ) ;
base_index = entry . e_name_index ;
if ( entry . e_name_index & EROFS_XATTR_LONG_PREFIX ) {
2023-06-13 10:41:11 +03:00
struct erofs_sb_info * sbi = EROFS_SB ( it - > sb ) ;
2023-04-11 12:35:37 +03:00
struct erofs_xattr_prefix_item * pf = sbi - > xattr_prefixes +
2023-06-13 10:41:14 +03:00
( entry . e_name_index & EROFS_XATTR_LONG_PREFIX_MASK ) ;
2023-04-11 12:35:37 +03:00
if ( pf > = sbi - > xattr_prefixes + sbi - > xattr_prefix_count )
2023-06-13 10:41:14 +03:00
return 0 ;
2023-04-11 12:35:37 +03:00
infix = pf - > prefix - > infix ;
infix_len = pf - > infix_len ;
base_index = pf - > prefix - > base_index ;
}
2018-07-26 15:21:52 +03:00
2023-04-25 00:25:39 +03:00
prefix = erofs_xattr_prefix ( base_index , it - > dentry ) ;
2023-02-01 16:14:56 +03:00
if ( ! prefix )
2023-06-13 10:41:14 +03:00
return 0 ;
2018-07-26 15:21:52 +03:00
prefix_len = strlen ( prefix ) ;
2023-06-13 10:41:14 +03:00
name_total = prefix_len + infix_len + entry . e_name_len + 1 ;
2018-07-26 15:21:52 +03:00
2019-03-22 05:38:16 +03:00
if ( ! it - > buffer ) {
2023-06-13 10:41:14 +03:00
it - > buffer_ofs + = name_total ;
return 0 ;
2018-07-26 15:21:52 +03:00
}
2023-06-13 10:41:14 +03:00
if ( it - > buffer_ofs + name_total > it - > buffer_size )
2018-07-26 15:21:52 +03:00
return - ERANGE ;
memcpy ( it - > buffer + it - > buffer_ofs , prefix , prefix_len ) ;
2023-04-11 12:35:37 +03:00
memcpy ( it - > buffer + it - > buffer_ofs + prefix_len , infix , infix_len ) ;
it - > buffer_ofs + = prefix_len + infix_len ;
2018-07-26 15:21:52 +03:00
2023-06-13 10:41:14 +03:00
/* 2. handle xattr name */
err = erofs_xattr_copy_to_buffer ( it , entry . e_name_len ) ;
if ( err )
return err ;
it - > buffer [ it - > buffer_ofs + + ] = ' \0 ' ;
2018-07-26 15:21:52 +03:00
return 0 ;
}
2023-06-13 10:41:14 +03:00
static int erofs_getxattr_foreach ( struct erofs_xattr_iter * it )
2018-07-26 15:21:52 +03:00
{
2023-06-13 10:41:14 +03:00
struct super_block * sb = it - > sb ;
struct erofs_xattr_entry entry ;
unsigned int slice , processed , value_sz ;
2018-07-26 15:21:52 +03:00
2023-06-13 10:41:14 +03:00
/* 1. handle xattr entry */
entry = * ( struct erofs_xattr_entry * )
( it - > kaddr + erofs_blkoff ( sb , it - > pos ) ) ;
it - > pos + = sizeof ( struct erofs_xattr_entry ) ;
value_sz = le16_to_cpu ( entry . e_value_size ) ;
/* should also match the infix for long name prefixes */
if ( entry . e_name_index & EROFS_XATTR_LONG_PREFIX ) {
struct erofs_sb_info * sbi = EROFS_SB ( sb ) ;
struct erofs_xattr_prefix_item * pf = sbi - > xattr_prefixes +
( entry . e_name_index & EROFS_XATTR_LONG_PREFIX_MASK ) ;
if ( pf > = sbi - > xattr_prefixes + sbi - > xattr_prefix_count )
return - ENOATTR ;
if ( it - > index ! = pf - > prefix - > base_index | |
it - > name . len ! = entry . e_name_len + pf - > infix_len )
return - ENOATTR ;
if ( memcmp ( it - > name . name , pf - > prefix - > infix , pf - > infix_len ) )
return - ENOATTR ;
it - > infix_len = pf - > infix_len ;
} else {
if ( it - > index ! = entry . e_name_index | |
it - > name . len ! = entry . e_name_len )
return - ENOATTR ;
it - > infix_len = 0 ;
}
/* 2. handle xattr name */
for ( processed = 0 ; processed < entry . e_name_len ; processed + = slice ) {
it - > kaddr = erofs_bread ( & it - > buf , erofs_blknr ( sb , it - > pos ) ,
EROFS_KMAP ) ;
if ( IS_ERR ( it - > kaddr ) )
return PTR_ERR ( it - > kaddr ) ;
slice = min_t ( unsigned int ,
sb - > s_blocksize - erofs_blkoff ( sb , it - > pos ) ,
entry . e_name_len - processed ) ;
if ( memcmp ( it - > name . name + it - > infix_len + processed ,
it - > kaddr + erofs_blkoff ( sb , it - > pos ) , slice ) )
return - ENOATTR ;
it - > pos + = slice ;
}
/* 3. handle xattr value */
if ( ! it - > buffer ) {
it - > buffer_ofs = value_sz ;
return 0 ;
}
if ( it - > buffer_size < value_sz )
return - ERANGE ;
return erofs_xattr_copy_to_buffer ( it , value_sz ) ;
}
2018-07-26 15:21:52 +03:00
erofs: unify inline/shared xattr iterators for listxattr/getxattr
Make inline_{list,get}xattr() as well as inline_xattr_iter_begin()
unified as erofs_xattr_iter_inline(), and shared_{list,get}xattr()
unified as erofs_xattr_iter_shared().
After these changes, both erofs_xattr_iter_{inline,shared}() return 0 on
success, and negative error on failure.
One thing worth noting is that, the logic of returning it->buffer_ofs
when there's no shared xattrs in shared_listxattr() is moved to
erofs_listxattr() to make the unification possible. The only difference
is that, semantically the old behavior will return ENOATTR rather than
it->buffer_ofs if ENOATTR encountered when listxattr is parsing upon a
specific shared xattr, while now the new behavior will return
it->buffer_ofs in this case. This is not an issue, as listxattr upon a
specific xattr won't return ENOATTR.
Signed-off-by: Jingbo Xu <jefflexu@linux.alibaba.com>
Reviewed-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Link: https://lore.kernel.org/r/20230613074114.120115-5-jefflexu@linux.alibaba.com
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
2023-06-13 10:41:13 +03:00
static int erofs_xattr_iter_inline ( struct erofs_xattr_iter * it ,
struct inode * inode , bool getxattr )
2018-07-26 15:21:52 +03:00
{
erofs: unify inline/shared xattr iterators for listxattr/getxattr
Make inline_{list,get}xattr() as well as inline_xattr_iter_begin()
unified as erofs_xattr_iter_inline(), and shared_{list,get}xattr()
unified as erofs_xattr_iter_shared().
After these changes, both erofs_xattr_iter_{inline,shared}() return 0 on
success, and negative error on failure.
One thing worth noting is that, the logic of returning it->buffer_ofs
when there's no shared xattrs in shared_listxattr() is moved to
erofs_listxattr() to make the unification possible. The only difference
is that, semantically the old behavior will return ENOATTR rather than
it->buffer_ofs if ENOATTR encountered when listxattr is parsing upon a
specific shared xattr, while now the new behavior will return
it->buffer_ofs in this case. This is not an issue, as listxattr upon a
specific xattr won't return ENOATTR.
Signed-off-by: Jingbo Xu <jefflexu@linux.alibaba.com>
Reviewed-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Link: https://lore.kernel.org/r/20230613074114.120115-5-jefflexu@linux.alibaba.com
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
2023-06-13 10:41:13 +03:00
struct erofs_inode * const vi = EROFS_I ( inode ) ;
2023-06-13 10:41:14 +03:00
unsigned int xattr_header_sz , remaining , entry_sz ;
erofs_off_t next_pos ;
2018-07-26 15:21:52 +03:00
int ret ;
erofs: unify inline/shared xattr iterators for listxattr/getxattr
Make inline_{list,get}xattr() as well as inline_xattr_iter_begin()
unified as erofs_xattr_iter_inline(), and shared_{list,get}xattr()
unified as erofs_xattr_iter_shared().
After these changes, both erofs_xattr_iter_{inline,shared}() return 0 on
success, and negative error on failure.
One thing worth noting is that, the logic of returning it->buffer_ofs
when there's no shared xattrs in shared_listxattr() is moved to
erofs_listxattr() to make the unification possible. The only difference
is that, semantically the old behavior will return ENOATTR rather than
it->buffer_ofs if ENOATTR encountered when listxattr is parsing upon a
specific shared xattr, while now the new behavior will return
it->buffer_ofs in this case. This is not an issue, as listxattr upon a
specific xattr won't return ENOATTR.
Signed-off-by: Jingbo Xu <jefflexu@linux.alibaba.com>
Reviewed-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Link: https://lore.kernel.org/r/20230613074114.120115-5-jefflexu@linux.alibaba.com
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
2023-06-13 10:41:13 +03:00
xattr_header_sz = sizeof ( struct erofs_xattr_ibody_header ) +
sizeof ( u32 ) * vi - > xattr_shared_count ;
if ( xattr_header_sz > = vi - > xattr_isize ) {
DBG_BUGON ( xattr_header_sz > vi - > xattr_isize ) ;
return - ENOATTR ;
}
remaining = vi - > xattr_isize - xattr_header_sz ;
2023-06-13 10:41:14 +03:00
it - > pos = erofs_iloc ( inode ) + vi - > inode_isize + xattr_header_sz ;
2018-07-26 15:21:52 +03:00
while ( remaining ) {
2023-06-13 10:41:14 +03:00
it - > kaddr = erofs_bread ( & it - > buf , erofs_blknr ( it - > sb , it - > pos ) ,
EROFS_KMAP ) ;
if ( IS_ERR ( it - > kaddr ) )
return PTR_ERR ( it - > kaddr ) ;
entry_sz = erofs_xattr_entry_size ( it - > kaddr +
erofs_blkoff ( it - > sb , it - > pos ) ) ;
/* xattr on-disk corruption: xattr entry beyond xattr_isize */
if ( remaining < entry_sz ) {
DBG_BUGON ( 1 ) ;
return - EFSCORRUPTED ;
}
remaining - = entry_sz ;
next_pos = it - > pos + entry_sz ;
if ( getxattr )
ret = erofs_getxattr_foreach ( it ) ;
else
ret = erofs_listxattr_foreach ( it ) ;
erofs: unify inline/shared xattr iterators for listxattr/getxattr
Make inline_{list,get}xattr() as well as inline_xattr_iter_begin()
unified as erofs_xattr_iter_inline(), and shared_{list,get}xattr()
unified as erofs_xattr_iter_shared().
After these changes, both erofs_xattr_iter_{inline,shared}() return 0 on
success, and negative error on failure.
One thing worth noting is that, the logic of returning it->buffer_ofs
when there's no shared xattrs in shared_listxattr() is moved to
erofs_listxattr() to make the unification possible. The only difference
is that, semantically the old behavior will return ENOATTR rather than
it->buffer_ofs if ENOATTR encountered when listxattr is parsing upon a
specific shared xattr, while now the new behavior will return
it->buffer_ofs in this case. This is not an issue, as listxattr upon a
specific xattr won't return ENOATTR.
Signed-off-by: Jingbo Xu <jefflexu@linux.alibaba.com>
Reviewed-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Link: https://lore.kernel.org/r/20230613074114.120115-5-jefflexu@linux.alibaba.com
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
2023-06-13 10:41:13 +03:00
if ( ( getxattr & & ret ! = - ENOATTR ) | | ( ! getxattr & & ret ) )
2018-07-26 15:21:52 +03:00
break ;
2023-06-13 10:41:14 +03:00
it - > pos = next_pos ;
2018-07-26 15:21:52 +03:00
}
erofs: unify inline/shared xattr iterators for listxattr/getxattr
Make inline_{list,get}xattr() as well as inline_xattr_iter_begin()
unified as erofs_xattr_iter_inline(), and shared_{list,get}xattr()
unified as erofs_xattr_iter_shared().
After these changes, both erofs_xattr_iter_{inline,shared}() return 0 on
success, and negative error on failure.
One thing worth noting is that, the logic of returning it->buffer_ofs
when there's no shared xattrs in shared_listxattr() is moved to
erofs_listxattr() to make the unification possible. The only difference
is that, semantically the old behavior will return ENOATTR rather than
it->buffer_ofs if ENOATTR encountered when listxattr is parsing upon a
specific shared xattr, while now the new behavior will return
it->buffer_ofs in this case. This is not an issue, as listxattr upon a
specific xattr won't return ENOATTR.
Signed-off-by: Jingbo Xu <jefflexu@linux.alibaba.com>
Reviewed-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Link: https://lore.kernel.org/r/20230613074114.120115-5-jefflexu@linux.alibaba.com
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
2023-06-13 10:41:13 +03:00
return ret ;
2018-07-26 15:21:52 +03:00
}
erofs: unify inline/shared xattr iterators for listxattr/getxattr
Make inline_{list,get}xattr() as well as inline_xattr_iter_begin()
unified as erofs_xattr_iter_inline(), and shared_{list,get}xattr()
unified as erofs_xattr_iter_shared().
After these changes, both erofs_xattr_iter_{inline,shared}() return 0 on
success, and negative error on failure.
One thing worth noting is that, the logic of returning it->buffer_ofs
when there's no shared xattrs in shared_listxattr() is moved to
erofs_listxattr() to make the unification possible. The only difference
is that, semantically the old behavior will return ENOATTR rather than
it->buffer_ofs if ENOATTR encountered when listxattr is parsing upon a
specific shared xattr, while now the new behavior will return
it->buffer_ofs in this case. This is not an issue, as listxattr upon a
specific xattr won't return ENOATTR.
Signed-off-by: Jingbo Xu <jefflexu@linux.alibaba.com>
Reviewed-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Link: https://lore.kernel.org/r/20230613074114.120115-5-jefflexu@linux.alibaba.com
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
2023-06-13 10:41:13 +03:00
static int erofs_xattr_iter_shared ( struct erofs_xattr_iter * it ,
struct inode * inode , bool getxattr )
2018-07-26 15:21:52 +03:00
{
2019-09-04 05:08:56 +03:00
struct erofs_inode * const vi = EROFS_I ( inode ) ;
2023-06-13 10:41:11 +03:00
struct super_block * const sb = it - > sb ;
2023-06-13 10:41:10 +03:00
struct erofs_sb_info * sbi = EROFS_SB ( sb ) ;
unsigned int i ;
erofs: unify inline/shared xattr iterators for listxattr/getxattr
Make inline_{list,get}xattr() as well as inline_xattr_iter_begin()
unified as erofs_xattr_iter_inline(), and shared_{list,get}xattr()
unified as erofs_xattr_iter_shared().
After these changes, both erofs_xattr_iter_{inline,shared}() return 0 on
success, and negative error on failure.
One thing worth noting is that, the logic of returning it->buffer_ofs
when there's no shared xattrs in shared_listxattr() is moved to
erofs_listxattr() to make the unification possible. The only difference
is that, semantically the old behavior will return ENOATTR rather than
it->buffer_ofs if ENOATTR encountered when listxattr is parsing upon a
specific shared xattr, while now the new behavior will return
it->buffer_ofs in this case. This is not an issue, as listxattr upon a
specific xattr won't return ENOATTR.
Signed-off-by: Jingbo Xu <jefflexu@linux.alibaba.com>
Reviewed-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Link: https://lore.kernel.org/r/20230613074114.120115-5-jefflexu@linux.alibaba.com
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
2023-06-13 10:41:13 +03:00
int ret = - ENOATTR ;
2018-07-26 15:21:52 +03:00
for ( i = 0 ; i < vi - > xattr_shared_count ; + + i ) {
2023-06-13 10:41:11 +03:00
it - > pos = erofs_pos ( sb , sbi - > xattr_blkaddr ) +
2023-06-13 10:41:10 +03:00
vi - > xattr_shared_xattrs [ i ] * sizeof ( __le32 ) ;
2023-06-13 10:41:11 +03:00
it - > kaddr = erofs_bread ( & it - > buf , erofs_blknr ( sb , it - > pos ) ,
EROFS_KMAP ) ;
if ( IS_ERR ( it - > kaddr ) )
return PTR_ERR ( it - > kaddr ) ;
2018-07-26 15:21:52 +03:00
2023-06-13 10:41:14 +03:00
if ( getxattr )
ret = erofs_getxattr_foreach ( it ) ;
else
ret = erofs_listxattr_foreach ( it ) ;
erofs: unify inline/shared xattr iterators for listxattr/getxattr
Make inline_{list,get}xattr() as well as inline_xattr_iter_begin()
unified as erofs_xattr_iter_inline(), and shared_{list,get}xattr()
unified as erofs_xattr_iter_shared().
After these changes, both erofs_xattr_iter_{inline,shared}() return 0 on
success, and negative error on failure.
One thing worth noting is that, the logic of returning it->buffer_ofs
when there's no shared xattrs in shared_listxattr() is moved to
erofs_listxattr() to make the unification possible. The only difference
is that, semantically the old behavior will return ENOATTR rather than
it->buffer_ofs if ENOATTR encountered when listxattr is parsing upon a
specific shared xattr, while now the new behavior will return
it->buffer_ofs in this case. This is not an issue, as listxattr upon a
specific xattr won't return ENOATTR.
Signed-off-by: Jingbo Xu <jefflexu@linux.alibaba.com>
Reviewed-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Link: https://lore.kernel.org/r/20230613074114.120115-5-jefflexu@linux.alibaba.com
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
2023-06-13 10:41:13 +03:00
if ( ( getxattr & & ret ! = - ENOATTR ) | | ( ! getxattr & & ret ) )
2018-07-26 15:21:52 +03:00
break ;
}
erofs: unify inline/shared xattr iterators for listxattr/getxattr
Make inline_{list,get}xattr() as well as inline_xattr_iter_begin()
unified as erofs_xattr_iter_inline(), and shared_{list,get}xattr()
unified as erofs_xattr_iter_shared().
After these changes, both erofs_xattr_iter_{inline,shared}() return 0 on
success, and negative error on failure.
One thing worth noting is that, the logic of returning it->buffer_ofs
when there's no shared xattrs in shared_listxattr() is moved to
erofs_listxattr() to make the unification possible. The only difference
is that, semantically the old behavior will return ENOATTR rather than
it->buffer_ofs if ENOATTR encountered when listxattr is parsing upon a
specific shared xattr, while now the new behavior will return
it->buffer_ofs in this case. This is not an issue, as listxattr upon a
specific xattr won't return ENOATTR.
Signed-off-by: Jingbo Xu <jefflexu@linux.alibaba.com>
Reviewed-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Link: https://lore.kernel.org/r/20230613074114.120115-5-jefflexu@linux.alibaba.com
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
2023-06-13 10:41:13 +03:00
return ret ;
2018-07-26 15:21:52 +03:00
}
erofs: unify inline/shared xattr iterators for listxattr/getxattr
Make inline_{list,get}xattr() as well as inline_xattr_iter_begin()
unified as erofs_xattr_iter_inline(), and shared_{list,get}xattr()
unified as erofs_xattr_iter_shared().
After these changes, both erofs_xattr_iter_{inline,shared}() return 0 on
success, and negative error on failure.
One thing worth noting is that, the logic of returning it->buffer_ofs
when there's no shared xattrs in shared_listxattr() is moved to
erofs_listxattr() to make the unification possible. The only difference
is that, semantically the old behavior will return ENOATTR rather than
it->buffer_ofs if ENOATTR encountered when listxattr is parsing upon a
specific shared xattr, while now the new behavior will return
it->buffer_ofs in this case. This is not an issue, as listxattr upon a
specific xattr won't return ENOATTR.
Signed-off-by: Jingbo Xu <jefflexu@linux.alibaba.com>
Reviewed-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Link: https://lore.kernel.org/r/20230613074114.120115-5-jefflexu@linux.alibaba.com
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
2023-06-13 10:41:13 +03:00
int erofs_getxattr ( struct inode * inode , int index , const char * name ,
void * buffer , size_t buffer_size )
2018-07-26 15:21:52 +03:00
{
int ret ;
2023-07-22 12:45:38 +03:00
unsigned int hashbit ;
2023-06-13 10:41:11 +03:00
struct erofs_xattr_iter it ;
2023-07-22 12:45:38 +03:00
struct erofs_inode * vi = EROFS_I ( inode ) ;
struct erofs_sb_info * sbi = EROFS_SB ( inode - > i_sb ) ;
2018-07-26 15:21:52 +03:00
erofs: unify inline/shared xattr iterators for listxattr/getxattr
Make inline_{list,get}xattr() as well as inline_xattr_iter_begin()
unified as erofs_xattr_iter_inline(), and shared_{list,get}xattr()
unified as erofs_xattr_iter_shared().
After these changes, both erofs_xattr_iter_{inline,shared}() return 0 on
success, and negative error on failure.
One thing worth noting is that, the logic of returning it->buffer_ofs
when there's no shared xattrs in shared_listxattr() is moved to
erofs_listxattr() to make the unification possible. The only difference
is that, semantically the old behavior will return ENOATTR rather than
it->buffer_ofs if ENOATTR encountered when listxattr is parsing upon a
specific shared xattr, while now the new behavior will return
it->buffer_ofs in this case. This is not an issue, as listxattr upon a
specific xattr won't return ENOATTR.
Signed-off-by: Jingbo Xu <jefflexu@linux.alibaba.com>
Reviewed-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Link: https://lore.kernel.org/r/20230613074114.120115-5-jefflexu@linux.alibaba.com
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
2023-06-13 10:41:13 +03:00
if ( ! name )
return - EINVAL ;
ret = erofs_init_inode_xattrs ( inode ) ;
if ( ret )
return ret ;
2023-07-22 12:45:38 +03:00
/* reserved flag is non-zero if there's any change of on-disk format */
if ( erofs_sb_has_xattr_filter ( sbi ) & & ! sbi - > xattr_filter_reserved ) {
hashbit = xxh32 ( name , strlen ( name ) ,
EROFS_XATTR_FILTER_SEED + index ) ;
hashbit & = EROFS_XATTR_FILTER_BITS - 1 ;
if ( vi - > xattr_name_filter & ( 1U < < hashbit ) )
return - ENOATTR ;
}
erofs: unify inline/shared xattr iterators for listxattr/getxattr
Make inline_{list,get}xattr() as well as inline_xattr_iter_begin()
unified as erofs_xattr_iter_inline(), and shared_{list,get}xattr()
unified as erofs_xattr_iter_shared().
After these changes, both erofs_xattr_iter_{inline,shared}() return 0 on
success, and negative error on failure.
One thing worth noting is that, the logic of returning it->buffer_ofs
when there's no shared xattrs in shared_listxattr() is moved to
erofs_listxattr() to make the unification possible. The only difference
is that, semantically the old behavior will return ENOATTR rather than
it->buffer_ofs if ENOATTR encountered when listxattr is parsing upon a
specific shared xattr, while now the new behavior will return
it->buffer_ofs in this case. This is not an issue, as listxattr upon a
specific xattr won't return ENOATTR.
Signed-off-by: Jingbo Xu <jefflexu@linux.alibaba.com>
Reviewed-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Link: https://lore.kernel.org/r/20230613074114.120115-5-jefflexu@linux.alibaba.com
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
2023-06-13 10:41:13 +03:00
it . index = index ;
it . name = ( struct qstr ) QSTR_INIT ( name , strlen ( name ) ) ;
if ( it . name . len > EROFS_NAME_LEN )
return - ERANGE ;
it . sb = inode - > i_sb ;
it . buf = __EROFS_BUF_INITIALIZER ;
erofs_init_metabuf ( & it . buf , it . sb ) ;
it . buffer = buffer ;
it . buffer_size = buffer_size ;
it . buffer_ofs = 0 ;
ret = erofs_xattr_iter_inline ( & it , inode , true ) ;
if ( ret = = - ENOATTR )
ret = erofs_xattr_iter_shared ( & it , inode , true ) ;
erofs_put_metabuf ( & it . buf ) ;
return ret ? ret : it . buffer_ofs ;
}
ssize_t erofs_listxattr ( struct dentry * dentry , char * buffer , size_t buffer_size )
{
int ret ;
struct erofs_xattr_iter it ;
struct inode * inode = d_inode ( dentry ) ;
ret = erofs_init_inode_xattrs ( inode ) ;
2019-12-01 11:01:09 +03:00
if ( ret = = - ENOATTR )
return 0 ;
2018-08-21 17:49:31 +03:00
if ( ret )
return ret ;
2018-07-26 15:21:52 +03:00
2023-06-13 10:41:11 +03:00
it . sb = dentry - > d_sb ;
it . buf = __EROFS_BUF_INITIALIZER ;
erofs_init_metabuf ( & it . buf , it . sb ) ;
2018-07-26 15:21:52 +03:00
it . dentry = dentry ;
it . buffer = buffer ;
it . buffer_size = buffer_size ;
it . buffer_ofs = 0 ;
erofs: unify inline/shared xattr iterators for listxattr/getxattr
Make inline_{list,get}xattr() as well as inline_xattr_iter_begin()
unified as erofs_xattr_iter_inline(), and shared_{list,get}xattr()
unified as erofs_xattr_iter_shared().
After these changes, both erofs_xattr_iter_{inline,shared}() return 0 on
success, and negative error on failure.
One thing worth noting is that, the logic of returning it->buffer_ofs
when there's no shared xattrs in shared_listxattr() is moved to
erofs_listxattr() to make the unification possible. The only difference
is that, semantically the old behavior will return ENOATTR rather than
it->buffer_ofs if ENOATTR encountered when listxattr is parsing upon a
specific shared xattr, while now the new behavior will return
it->buffer_ofs in this case. This is not an issue, as listxattr upon a
specific xattr won't return ENOATTR.
Signed-off-by: Jingbo Xu <jefflexu@linux.alibaba.com>
Reviewed-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Link: https://lore.kernel.org/r/20230613074114.120115-5-jefflexu@linux.alibaba.com
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
2023-06-13 10:41:13 +03:00
ret = erofs_xattr_iter_inline ( & it , inode , false ) ;
if ( ! ret | | ret = = - ENOATTR )
ret = erofs_xattr_iter_shared ( & it , inode , false ) ;
if ( ret = = - ENOATTR )
ret = 0 ;
2023-06-13 10:41:11 +03:00
erofs_put_metabuf ( & it . buf ) ;
erofs: unify inline/shared xattr iterators for listxattr/getxattr
Make inline_{list,get}xattr() as well as inline_xattr_iter_begin()
unified as erofs_xattr_iter_inline(), and shared_{list,get}xattr()
unified as erofs_xattr_iter_shared().
After these changes, both erofs_xattr_iter_{inline,shared}() return 0 on
success, and negative error on failure.
One thing worth noting is that, the logic of returning it->buffer_ofs
when there's no shared xattrs in shared_listxattr() is moved to
erofs_listxattr() to make the unification possible. The only difference
is that, semantically the old behavior will return ENOATTR rather than
it->buffer_ofs if ENOATTR encountered when listxattr is parsing upon a
specific shared xattr, while now the new behavior will return
it->buffer_ofs in this case. This is not an issue, as listxattr upon a
specific xattr won't return ENOATTR.
Signed-off-by: Jingbo Xu <jefflexu@linux.alibaba.com>
Reviewed-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Link: https://lore.kernel.org/r/20230613074114.120115-5-jefflexu@linux.alibaba.com
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
2023-06-13 10:41:13 +03:00
return ret ? ret : it . buffer_ofs ;
2018-07-26 15:21:52 +03:00
}
2023-04-07 17:17:08 +03:00
void erofs_xattr_prefixes_cleanup ( struct super_block * sb )
{
struct erofs_sb_info * sbi = EROFS_SB ( sb ) ;
int i ;
if ( sbi - > xattr_prefixes ) {
for ( i = 0 ; i < sbi - > xattr_prefix_count ; i + + )
kfree ( sbi - > xattr_prefixes [ i ] . prefix ) ;
kfree ( sbi - > xattr_prefixes ) ;
sbi - > xattr_prefixes = NULL ;
}
}
int erofs_xattr_prefixes_init ( struct super_block * sb )
{
struct erofs_sb_info * sbi = EROFS_SB ( sb ) ;
struct erofs_buf buf = __EROFS_BUF_INITIALIZER ;
erofs_off_t pos = ( erofs_off_t ) sbi - > xattr_prefix_start < < 2 ;
struct erofs_xattr_prefix_item * pfs ;
int ret = 0 , i , len ;
if ( ! sbi - > xattr_prefix_count )
return 0 ;
pfs = kzalloc ( sbi - > xattr_prefix_count * sizeof ( * pfs ) , GFP_KERNEL ) ;
if ( ! pfs )
return - ENOMEM ;
2023-05-15 13:39:41 +03:00
if ( sbi - > packed_inode )
2023-04-07 17:17:08 +03:00
buf . inode = sbi - > packed_inode ;
else
erofs_init_metabuf ( & buf , sb ) ;
for ( i = 0 ; i < sbi - > xattr_prefix_count ; i + + ) {
void * ptr = erofs_read_metadata ( sb , & buf , & pos , & len ) ;
if ( IS_ERR ( ptr ) ) {
ret = PTR_ERR ( ptr ) ;
break ;
} else if ( len < sizeof ( * pfs - > prefix ) | |
len > EROFS_NAME_LEN + sizeof ( * pfs - > prefix ) ) {
kfree ( ptr ) ;
ret = - EFSCORRUPTED ;
break ;
}
pfs [ i ] . prefix = ptr ;
pfs [ i ] . infix_len = len - sizeof ( struct erofs_xattr_long_prefix ) ;
}
erofs_put_metabuf ( & buf ) ;
sbi - > xattr_prefixes = pfs ;
if ( ret )
erofs_xattr_prefixes_cleanup ( sb ) ;
return ret ;
}
2019-01-29 11:35:20 +03:00
# ifdef CONFIG_EROFS_FS_POSIX_ACL
2021-08-18 23:08:24 +03:00
struct posix_acl * erofs_get_acl ( struct inode * inode , int type , bool rcu )
2019-01-29 11:35:20 +03:00
{
struct posix_acl * acl ;
int prefix , rc ;
char * value = NULL ;
2021-08-18 23:08:24 +03:00
if ( rcu )
return ERR_PTR ( - ECHILD ) ;
2019-01-29 11:35:20 +03:00
switch ( type ) {
case ACL_TYPE_ACCESS :
prefix = EROFS_XATTR_INDEX_POSIX_ACL_ACCESS ;
break ;
case ACL_TYPE_DEFAULT :
prefix = EROFS_XATTR_INDEX_POSIX_ACL_DEFAULT ;
break ;
default :
return ERR_PTR ( - EINVAL ) ;
}
rc = erofs_getxattr ( inode , prefix , " " , NULL , 0 ) ;
if ( rc > 0 ) {
value = kmalloc ( rc , GFP_KERNEL ) ;
if ( ! value )
return ERR_PTR ( - ENOMEM ) ;
rc = erofs_getxattr ( inode , prefix , " " , value , rc ) ;
}
if ( rc = = - ENOATTR )
acl = NULL ;
else if ( rc < 0 )
acl = ERR_PTR ( rc ) ;
else
acl = posix_acl_from_xattr ( & init_user_ns , value , rc ) ;
kfree ( value ) ;
return acl ;
}
# endif