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

Tiger Yang tiger.yang at oracle.com
Tue Oct 20 01:42:16 PDT 2009


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;
+	}
+
+	return ret;
+}
+
+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)
+{
+	struct ocfs2_xattr_header *header = NULL;
+	ocfs2_filesys *fs = ci->ci_fs;
+	struct ocfs2_dinode *di = ci->ci_inode;
+	errcode_t ret = 0;
+
+	if (!(di->i_dyn_features & OCFS2_INLINE_XATTR_FL))
+		return ret;
+
+	header = (struct ocfs2_xattr_header *)
+		 ((char *)di + fs->fs_blocksize - di->i_xattr_inline_size);
+
+	ret = ocfs2_xattr_iterate_entries(ci, header, func, priv_data);
+
+	return ret;
+}
+
+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;
+
+	for (i = 0; i < num_buckets; i++, blkno += blk_per_bucket) {
+		ret = ocfs2_read_xattr_bucket(fs, blkno, bucket);
+		if (ret)
+			goto out;
+
+		xh = (struct ocfs2_xattr_header *)bucket;
+		/*
+		 * The real bucket num in this series of blocks is stored
+		 * in the 1st bucket.
+		 */
+		if (i == 0)
+			num_buckets = xh->xh_num_buckets;
+		ret = ocfs2_xattr_iterate_entries(ci, xh, func, priv_data);
+	}
+
+out:
+	if (bucket)
+		ocfs2_free(&bucket);
+
+	return ret;
+}
+
+static errcode_t ocfs2_xattr_iterate_index_block(ocfs2_cached_inode *ci,
+					struct ocfs2_xattr_block *xb,
+					int (*func)(ocfs2_cached_inode *ci,
+						struct ocfs2_xattr_entry *xe,
+						void *priv_data),
+					void *priv_data)
+{
+	ocfs2_filesys *fs = ci->ci_fs;
+	struct ocfs2_extent_list *el = &xb->xb_attrs.xb_root.xt_list;
+	uint32_t name_hash = UINT_MAX, e_cpos = 0, num_clusters = 0;
+	uint64_t p_blkno = 0;
+	errcode_t ret = 0;
+
+	if (!el->l_next_free_rec)
+		return 0;
+
+	while (name_hash > 0) {
+		ret = ocfs2_xattr_get_rec(fs, xb, name_hash, &p_blkno,
+					  &e_cpos, &num_clusters);
+		if (ret)
+			goto out;
+
+		ret = ocfs2_xattr_iterate_bucket(ci, p_blkno, num_clusters,
+						  func, priv_data);
+		if (ret)
+			goto out;
+
+		if (e_cpos == 0)
+			break;
+
+		name_hash = e_cpos - 1;
+	}
+
+out:
+	return ret;
+}
+
+static errcode_t ocfs2_xattr_iterate_block(ocfs2_cached_inode *ci,
+					   int (*func)(ocfs2_cached_inode *ci,
+						struct ocfs2_xattr_entry *xe,
+						void *priv_data),
+					   void *priv_data)
+{
+	char *blk = NULL;
+	ocfs2_filesys *fs = ci->ci_fs;
+	struct ocfs2_dinode *di = ci->ci_inode;
+	struct ocfs2_xattr_block *xb;
+	int ret = 0;
+
+	if (!di->i_xattr_loc)
+		return ret;
+
+	ret = ocfs2_malloc_block(fs->fs_io, &blk);
+	if (ret < 0)
+		return ret;
+
+	ret = ocfs2_read_xattr_block(fs, di->i_xattr_loc, blk);
+	if (ret < 0)
+		return ret;
+
+	xb = (struct ocfs2_xattr_block *)blk;
+	if (xb->xb_flags & OCFS2_XATTR_INDEXED)
+		ret = ocfs2_xattr_iterate_index_block(ci, xb, func, priv_data);
+	else {
+		struct ocfs2_xattr_header *header = &xb->xb_attrs.xb_header;
+		ret = ocfs2_xattr_iterate_entries(ci, header, func, priv_data);
+	}
+
+	ocfs2_free(&blk);
+
+	return ret;
+}
+
 static int ocfs2_xattr_find_entry(int name_index,
 				  const char *name,
 				  struct ocfs2_xattr_search *xs)
@@ -3150,3 +3309,34 @@ errcode_t ocfs2_xattr_set(ocfs2_cached_inode *ci,
 		return OCFS2_ET_INVALID_ARGUMENT;
 	return ocfs2_xattr_set_generic(ci, name_index, name, buf, count);
 }
+
+/*
+ * Iterate the xattr entries on inode 'ci'.  If 'func' returns
+ * OCFS2_XATTR_ABORT or OCFS2_XATTR_ERROR, stop iteration.
+ * If OCFS2_XATTR_ERROR, return an error from ocfs2_xattr_iterate.
+ *
+ * If you modify an xattr, you must restart your iteration - there is
+ * no guarantee it is in a consistent state.
+ */
+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);
+
+	return ret;
+}
+
-- 
1.5.4.1




More information about the Ocfs2-tools-devel mailing list