[PATCH 3/3] erofs-utils: support long xattr name prefixes for erofsfuse

Gao Xiang hsiangkao at linux.alibaba.com
Wed Aug 16 01:29:28 AEST 2023



On 2023/8/15 17:15, Jingbo Xu wrote:
> Make erofs_listxattr() and erofs_getxattr() routine support long xattr
> name prefixes.
> 
> Although the on-disk format allows long xattr name prefixes to be placed
> in the meta inode or packed inode, currently mkfs.erofs will place them
> in packed inode by default.  Thus let's also read long xattr name prefixes
> from packed inode by default.
> 
> Since we need to read the content of the packed inode from disk when
> loading long xattr name prefixes, add dependency on zlib_LIBS for
> mkfs.erofs to resolve the compiling dependency.
> 
> Signed-off-by: Jingbo Xu <jefflexu at linux.alibaba.com>
> ---
>   include/erofs/internal.h |   6 ++
>   include/erofs/xattr.h    |   2 +
>   lib/super.c              |  14 +++-
>   lib/xattr.c              | 139 ++++++++++++++++++++++++++++++++++++---
>   mkfs/Makefile.am         |   3 +-
>   5 files changed, 152 insertions(+), 12 deletions(-)
> 
> diff --git a/include/erofs/internal.h b/include/erofs/internal.h
> index a04e6a6..df8cd51 100644
> --- a/include/erofs/internal.h
> +++ b/include/erofs/internal.h
> @@ -57,6 +57,11 @@ struct erofs_device_info {
>   	u32 mapped_blkaddr;
>   };
>   
> +struct erofs_xattr_prefix_item {
> +	struct erofs_xattr_long_prefix *prefix;
> +	u8 infix_len;
> +};
> +
>   #define EROFS_PACKED_NID_UNALLOCATED	-1
>   
>   struct erofs_sb_info {
> @@ -99,6 +104,7 @@ struct erofs_sb_info {
>   
>   	u32 xattr_prefix_start;
>   	u8 xattr_prefix_count;
> +	struct erofs_xattr_prefix_item *xattr_prefixes;
>   
>   	int devfd;
>   	u64 devsz;
> diff --git a/include/erofs/xattr.h b/include/erofs/xattr.h
> index dc27cf6..748442a 100644
> --- a/include/erofs/xattr.h
> +++ b/include/erofs/xattr.h
> @@ -82,6 +82,8 @@ int erofs_build_shared_xattrs_from_path(struct erofs_sb_info *sbi, const char *p
>   int erofs_xattr_insert_name_prefix(const char *prefix);
>   void erofs_xattr_cleanup_name_prefixes(void);
>   int erofs_xattr_write_name_prefixes(struct erofs_sb_info *sbi, FILE *f);
> +void erofs_xattr_prefixes_cleanup(struct erofs_sb_info *sbi);
> +int erofs_xattr_prefixes_init(struct erofs_sb_info *sbi);
>   
>   int erofs_setxattr(struct erofs_inode *inode, char *key,
>   		   const void *value, size_t size);
> diff --git a/lib/super.c b/lib/super.c
> index e8e84aa..21dc51f 100644
> --- a/lib/super.c
> +++ b/lib/super.c
> @@ -6,6 +6,7 @@
>   #include <stdlib.h>
>   #include "erofs/io.h"
>   #include "erofs/print.h"
> +#include "erofs/xattr.h"
>   
>   static bool check_layout_compatibility(struct erofs_sb_info *sbi,
>   				       struct erofs_super_block *dsb)
> @@ -101,6 +102,8 @@ int erofs_read_superblock(struct erofs_sb_info *sbi)
>   	sbi->primarydevice_blocks = le32_to_cpu(dsb->blocks);
>   	sbi->meta_blkaddr = le32_to_cpu(dsb->meta_blkaddr);
>   	sbi->xattr_blkaddr = le32_to_cpu(dsb->xattr_blkaddr);
> +	sbi->xattr_prefix_start = le32_to_cpu(dsb->xattr_prefix_start);
> +	sbi->xattr_prefix_count = dsb->xattr_prefix_count;
>   	sbi->islotbits = EROFS_ISLOTBITS;
>   	sbi->root_nid = le16_to_cpu(dsb->root_nid);
>   	sbi->packed_nid = le64_to_cpu(dsb->packed_nid);
> @@ -117,11 +120,20 @@ int erofs_read_superblock(struct erofs_sb_info *sbi)
>   		sbi->available_compr_algs = le16_to_cpu(dsb->u1.available_compr_algs);
>   	else
>   		sbi->lz4_max_distance = le16_to_cpu(dsb->u1.lz4_max_distance);
> -	return erofs_init_devices(sbi, dsb);
> +
> +	ret = erofs_init_devices(sbi, dsb);
> +	if (ret)
> +		return ret;
> +
> +	ret = erofs_xattr_prefixes_init(sbi);
> +	if (ret)
> +		free(sbi->devs);
> +	return ret;
>   }
>   
>   void erofs_put_super(struct erofs_sb_info *sbi)
>   {
>   	if (sbi->devs)
>   		free(sbi->devs);
> +	erofs_xattr_prefixes_cleanup(sbi);
>   }
> diff --git a/lib/xattr.c b/lib/xattr.c
> index 4091fe6..074be52 100644
> --- a/lib/xattr.c
> +++ b/lib/xattr.c
> @@ -1093,19 +1093,47 @@ out:
>   struct getxattr_iter {
>   	struct xattr_iter it;
>   
> -	int buffer_size, index;
> +	int buffer_size, index, infix_len;
>   	char *buffer;
>   	const char *name;
>   	size_t len;
>   };
>   
> +static int erofs_xattr_long_entrymatch(struct getxattr_iter *it,
> +				       struct erofs_xattr_entry *entry)
> +{
> +	struct erofs_sb_info *sbi = it->it.sbi;
> +	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->len != entry->e_name_len + pf->infix_len)
> +		return -ENOATTR;
> +
> +	if (memcmp(it->name, pf->prefix->infix, pf->infix_len))
> +		return -ENOATTR;
> +
> +	it->infix_len = pf->infix_len;
> +	return 0;
> +}
> +
>   static int xattr_entrymatch(struct xattr_iter *_it,
>   			    struct erofs_xattr_entry *entry)
>   {
>   	struct getxattr_iter *it = container_of(_it, struct getxattr_iter, it);
>   
> -	return (it->index != entry->e_name_index ||
> -		it->len != entry->e_name_len) ? -ENOATTR : 0;
> +	/* should also match the infix for long name prefixes */
> +	if (entry->e_name_index & EROFS_XATTR_LONG_PREFIX)
> +		return erofs_xattr_long_entrymatch(it, entry);
> +
> +	if (it->index != entry->e_name_index ||
> +	    it->len != entry->e_name_len)
> +		return -ENOATTR;
> +	it->infix_len = 0;
> +	return 0;
>   }
>   
>   static int xattr_namematch(struct xattr_iter *_it,
> @@ -1113,8 +1141,9 @@ static int xattr_namematch(struct xattr_iter *_it,
>   {
>   	struct getxattr_iter *it = container_of(_it, struct getxattr_iter, it);
>   
> -
> -	return memcmp(buf, it->name + processed, len) ? -ENOATTR : 0;
> +	if (memcmp(buf, it->name + it->infix_len + processed, len))
> +		return -ENOATTR;
> +	return 0;
>   }
>   
>   static int xattr_checkbuffer(struct xattr_iter *_it,
> @@ -1237,8 +1266,20 @@ static int xattr_entrylist(struct xattr_iter *_it,
>   	struct listxattr_iter *it =
>   		container_of(_it, struct listxattr_iter, it);
>   	unsigned int base_index = entry->e_name_index;
> -	unsigned int prefix_len;
> -	const char *prefix;
> +	unsigned int prefix_len, infix_len = 0;
> +	const char *prefix, *infix = NULL;
> +
> +	if (entry->e_name_index & EROFS_XATTR_LONG_PREFIX) {
> +		struct erofs_sb_info *sbi = _it->sbi;
> +		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 1;
> +		infix = pf->prefix->infix;
> +		infix_len = pf->infix_len;
> +		base_index = pf->prefix->base_index;
> +	}
>   
>   	if (base_index >= ARRAY_SIZE(xattr_types))
>   		return 1;
> @@ -1246,16 +1287,18 @@ static int xattr_entrylist(struct xattr_iter *_it,
>   	prefix_len = xattr_types[base_index].prefix_len;
>   
>   	if (!it->buffer) {
> -		it->buffer_ofs += prefix_len + entry->e_name_len + 1;
> +		it->buffer_ofs += prefix_len + infix_len +
> +					entry->e_name_len + 1;
>   		return 1;
>   	}
>   
> -	if (it->buffer_ofs + prefix_len
> +	if (it->buffer_ofs + prefix_len + infix_len
>   		+ entry->e_name_len + 1 > it->buffer_size)
>   		return -ERANGE;
>   
>   	memcpy(it->buffer + it->buffer_ofs, prefix, prefix_len);
> -	it->buffer_ofs += prefix_len;
> +	memcpy(it->buffer + it->buffer_ofs + prefix_len, infix, infix_len);
> +	it->buffer_ofs += prefix_len + infix_len;
>   	return 0;
>   }
>   
> @@ -1404,3 +1447,79 @@ void erofs_xattr_cleanup_name_prefixes(void)
>   		free(tnode);
>   	}
>   }
> +
> +void erofs_xattr_prefixes_cleanup(struct erofs_sb_info *sbi)
> +{
> +	int i;
> +
> +	if (sbi->xattr_prefixes) {
> +		for (i = 0; i < sbi->xattr_prefix_count; i++)
> +			free(sbi->xattr_prefixes[i].prefix);
> +		free(sbi->xattr_prefixes);
> +		sbi->xattr_prefixes = NULL;
> +	}
> +}
> +
> +int erofs_xattr_prefixes_init(struct erofs_sb_info *sbi)
> +{
> +	erofs_off_t pos = (erofs_off_t)sbi->xattr_prefix_start << 2;
> +	struct erofs_inode vi;
> +	struct erofs_xattr_prefix_item *pfs;
> +	int ret = 0, i, len;
> +	__le16 __len;
> +
> +	if (!sbi->xattr_prefix_count)
> +		return 0;
> +
> +	if (!sbi->packed_nid) {
> +		erofs_err("doesn't support xattr prefixes in meta inode yet");
> +		return -EOPNOTSUPP;

Why not supporting this as well?

I think it can be easily implemented by using blk_read() (or
we could introduce a pseudo meta inode).

Thanks,
Gao Xiang


More information about the Linux-erofs mailing list