[Ocfs2-tools-devel] [PATCH 6/7] libocfs2: iterate all xattr entries of a file

Joel Becker Joel.Becker at oracle.com
Tue Nov 24 17:14:30 PST 2009


On Tue, Oct 20, 2009 at 04:42:16PM +0800, Tiger Yang wrote:
> This patch add iteration function for all xattr entries
> related of a file. ocfs2_xattr_iterate will call the callback
> function on each xattr entry.
> 
> Signed-off-by: Tiger Yang <tiger.yang at oracle.com>
> ---
>  include/ocfs2/ocfs2.h |    8 ++
>  libocfs2/xattr.c      |  190 +++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 198 insertions(+), 0 deletions(-)
> 
> diff --git a/include/ocfs2/ocfs2.h b/include/ocfs2/ocfs2.h
> index 20d391e..f9e5c5a 100644
> --- a/include/ocfs2/ocfs2.h
> +++ b/include/ocfs2/ocfs2.h
> @@ -1264,6 +1264,14 @@ errcode_t ocfs2_block_iterate_inode(ocfs2_filesys *fs,
>  						void *priv_data),
>  				    void *priv_data);
>  
> +#define OCFS2_XATTR_ABORT	0x01
> +#define OCFS2_XATTR_ERROR	0x02
> +errcode_t ocfs2_xattr_iterate(ocfs2_cached_inode *ci,
> +			      int (*func)(ocfs2_cached_inode *ci,
> +					struct ocfs2_xattr_entry *xe,
> +					void *priv_data),
> +			      void *priv_data);
> +
>  uint32_t ocfs2_xattr_uuid_hash(unsigned char *uuid);
>  uint32_t ocfs2_xattr_name_hash(uint32_t uuid_hash, const char *name,
>  			       int name_len);
> diff --git a/libocfs2/xattr.c b/libocfs2/xattr.c
> index d3285c8..dfc3c99 100644
> --- a/libocfs2/xattr.c
> +++ b/libocfs2/xattr.c
> @@ -611,6 +611,165 @@ static int ocfs2_xattr_has_space_inline(ocfs2_cached_inode *ci,
>  	return 0;
>  }
>  
> +static errcode_t ocfs2_xattr_iterate_entries(ocfs2_cached_inode *ci,
> +					struct ocfs2_xattr_header *header,
> +					int (*func)(ocfs2_cached_inode *ci,
> +						struct ocfs2_xattr_entry *xe,
> +						void *priv_data),
> +					void *priv_data)
> +{
> +	int i;
> +	struct ocfs2_xattr_entry *entry = NULL;
> +	errcode_t ret = 0;
> +
> +	for (i = 0 ; i < header->xh_count; i++) {
> +		entry = &header->xh_entries[i];
> +		ret = func(ci, entry, priv_data);
> +		if (ret == OCFS2_XATTR_ABORT || ret == OCFS2_XATTR_ERROR)
> +			return ret;

	This return code should be iret and like extent_iterate it can
be the bitwise orr of the flags.  So:
static int ocfs2_xattr_iterate_entries(...)
{
	...

		iret = func(ci, entry, priv_data);
		if (iret & (OCFS2_XATTR_ABORT | OCFS2_XATTR_ERROR))
			break;
	}

	return iret;
}

> +static errcode_t ocfs2_xattr_iterate_ibody(ocfs2_cached_inode *ci,
> +					   int (*func)(ocfs2_cached_inode *ci,
> +						struct ocfs2_xattr_entry *xe,
> +						void *priv_data),
> +					   void *priv_data)

	Again returning iret here.

> +static errcode_t ocfs2_xattr_iterate_bucket(ocfs2_cached_inode *ci,
> +					    uint64_t blkno,
> +					    uint32_t clusters,
> +					    int (*func)(ocfs2_cached_inode *ci,
> +						struct ocfs2_xattr_entry *xe,
> +						void *priv_data),
> +					    void *priv_data)
> +{
> +	int i;
> +	errcode_t ret = 0;
> +	char *bucket = NULL;
> +	struct ocfs2_xattr_header *xh;
> +	ocfs2_filesys *fs = ci->ci_fs;
> +	int blk_per_bucket = ocfs2_blocks_per_xattr_bucket(fs);
> +	uint32_t bpc = ocfs2_xattr_buckets_per_cluster(fs);
> +	uint32_t num_buckets = clusters * bpc;
> +
> +	ret = ocfs2_malloc_blocks(fs->fs_io, blk_per_bucket, &bucket);
> +	if (ret)
> +		goto out;

	This also needs to return iret.
	You need to be passing a context in here.  If you get an
errcode_t off a subfunction (ocfs2_malloc_blocks,
ocfs2_read_xattr_bucket(), etc) you store it on the context and then
set ire |= OCFS2_XATTR_ERROR.  See extents.c/extent_iterate_eb() for an
example of this.
	The same goes for all of these subfunctions.

> +errcode_t ocfs2_xattr_iterate(ocfs2_cached_inode *ci,
> +			      int (*func)(ocfs2_cached_inode *ci,
> +					struct ocfs2_xattr_entry *xe,
> +					void *priv_data),
> +			      void *priv_data)
> +{
> +	errcode_t ret = 0;
> +	struct ocfs2_super_block *sb = OCFS2_RAW_SB(ci->ci_fs->fs_super);
> +	struct ocfs2_dinode *di = ci->ci_inode;
> +
> +	if (!(sb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_XATTR))
> +		return OCFS2_ET_UNSUPP_FEATURE;
> +	if (!(di->i_dyn_features & OCFS2_HAS_XATTR_FL))
> +		return OCFS2_ET_XATTR_NODATA;
> +
> +	ret = ocfs2_xattr_iterate_ibody(ci, func, priv_data);
> +	if (ret)
> +		ret = ocfs2_xattr_iterate_block(ci, func, priv_data);

	This is totally incorrect.  "If there is an error, go look at
the block"?  What you want is:

	...
	ctxt.ci = ci;
	ctxt.func = func;
	ctxt.priv_data = priv_data;
	ctxt.errcode = 0;
	iret = ocfs2_xattr_iterate_ibody(&ctxt);
	if (!(iret & (OCFS2_XATTR_ABORT | OCFS2_XATTR_ERROR)))
		iret = ocfs2_xattr_iterate_block(&ctxt);

	if (iret & OCFS2_XATTR_ERROR)
		ret = ctxt.errcode;

	return ret;

Joel

-- 

"What does it say about a society's priorities when the time you
 spend in meetings on Monday is greater than the total number of
 hours you spent sleeping over the weekend?"
	- Nat Friedman

Joel Becker
Principal Software Developer
Oracle
E-mail: joel.becker at oracle.com
Phone: (650) 506-8127



More information about the Ocfs2-tools-devel mailing list