[Ocfs2-tools-devel] [PATCH 19/50] libocfs2: Add xattr iteration process.

Tao Ma tao.ma at oracle.com
Mon Jan 11 07:31:05 PST 2010


In some other tools(tunefs.ocfs2 and fsck.ocfs2), we need
to iterate xattr many times, so we'd better have an iteration
process for xattr.

I have taken some reference from Tiger's intial draft.
http://oss.oracle.com/pipermail/ocfs2-tools-devel/2009-October/002282.html
Thank tiger for it.
It has changed a lot in this version.

Signed-off-by: Tao Ma <tao.ma at oracle.com>
---
 include/ocfs2/ocfs2.h |   14 +++
 libocfs2/xattr.c      |  219 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 233 insertions(+), 0 deletions(-)

diff --git a/include/ocfs2/ocfs2.h b/include/ocfs2/ocfs2.h
index 161d6c8..7960aab 100644
--- a/include/ocfs2/ocfs2.h
+++ b/include/ocfs2/ocfs2.h
@@ -1322,6 +1322,20 @@ 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,
+					  char *xe_buf,
+					  uint64_t xe_blkno,
+					  struct ocfs2_xattr_entry *xe,
+					  char *value_buf,
+					  uint64_t value_blkno,
+					  void *value,
+					  int in_bucket,
+					  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 0c1c68e..2eb9ae9 100644
--- a/libocfs2/xattr.c
+++ b/libocfs2/xattr.c
@@ -505,3 +505,222 @@ errcode_t ocfs2_write_xattr_bucket(ocfs2_filesys *fs,
 	ocfs2_free(&bucket);
 	return ret;
 }
+
+struct xattr_iterate_ctxt {
+	ocfs2_cached_inode *ci;
+	int (*func)(ocfs2_cached_inode *ci,
+		    char *xe_buf,
+		    uint64_t xe_blkno,
+		    struct ocfs2_xattr_entry *xe,
+		    char *value_buf,
+		    uint64_t value_blkno,
+		    void *value,
+		    int  in_bucket,
+		    void *priv_data);
+	errcode_t errcode;
+	void *priv_data;
+};
+
+static int ocfs2_xattr_iterate_entries(struct xattr_iterate_ctxt *ctxt,
+				       char *xattr_buf, uint64_t xe_blkno,
+				       struct ocfs2_xattr_header *xh,
+				       int is_bucket)
+{
+	int i, value_offset, block_offset;
+	struct ocfs2_xattr_entry *xe = NULL;
+	int iret = 0;
+	char *value_buf;
+	void *value;
+
+	for (i = 0 ; i < xh->xh_count; i++) {
+		xe = &xh->xh_entries[i];
+		value_offset = xe->xe_name_offset +
+				OCFS2_XATTR_SIZE(xe->xe_name_len);
+		block_offset = value_offset / ctxt->ci->ci_fs->fs_blocksize;
+		value_buf = xattr_buf +
+				block_offset * ctxt->ci->ci_fs->fs_blocksize;
+		value = (char *)xh + value_offset;
+
+		if (ctxt->func) {
+			iret = ctxt->func(ctxt->ci, xattr_buf, xe_blkno, xe,
+					  value_buf, xe_blkno + block_offset,
+					  value, is_bucket,
+					  ctxt->priv_data);
+			if (iret & (OCFS2_XATTR_ABORT | OCFS2_XATTR_ERROR))
+				break;
+		}
+	}
+
+	return iret;
+}
+
+static int ocfs2_xattr_iterate_ibody(struct xattr_iterate_ctxt *ctxt)
+{
+	struct ocfs2_xattr_header *xh = NULL;
+	struct ocfs2_dinode *di = ctxt->ci->ci_inode;
+
+	if (!(di->i_dyn_features & OCFS2_INLINE_XATTR_FL))
+		return 0;
+
+	xh = (struct ocfs2_xattr_header *)((char *)di +
+		ctxt->ci->ci_fs->fs_blocksize - di->i_xattr_inline_size);
+
+	return ocfs2_xattr_iterate_entries(ctxt, (char *)di, di->i_blkno,
+					   xh, 0);
+}
+
+static int ocfs2_xattr_iterate_bucket(struct xattr_iterate_ctxt *ctxt,
+				      uint64_t blkno, uint32_t clusters)
+{
+	int i, iret = 0 ;
+	char *bucket = NULL;
+	struct ocfs2_xattr_header *xh;
+	ocfs2_filesys *fs = ctxt->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;
+
+	ctxt->errcode = ocfs2_malloc_blocks(fs->fs_io, blk_per_bucket, &bucket);
+	if (ctxt->errcode)
+		goto out;
+
+	for (i = 0; i < num_buckets; i++, blkno += blk_per_bucket) {
+		ctxt->errcode = ocfs2_read_xattr_bucket(fs, blkno, bucket);
+		if (ctxt->errcode)
+			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;
+		iret = ocfs2_xattr_iterate_entries(ctxt, bucket, blkno, xh, 1);
+	}
+
+out:
+	if (bucket)
+		ocfs2_free(&bucket);
+
+	if (ctxt->errcode)
+		iret |= OCFS2_XATTR_ERROR;
+
+	return iret;
+}
+
+static int ocfs2_xattr_iterate_index_block(struct xattr_iterate_ctxt *ctxt,
+					   struct ocfs2_xattr_block *xb)
+{
+	ocfs2_filesys *fs = ctxt->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;
+	int iret = 0;
+
+	if (!el->l_next_free_rec)
+		return 0;
+
+	while (name_hash > 0) {
+		ctxt->errcode = ocfs2_xattr_get_rec(fs, xb,
+						    name_hash, &p_blkno,
+						    &e_cpos, &num_clusters);
+		if (ctxt->errcode)
+			break;
+
+		iret = ocfs2_xattr_iterate_bucket(ctxt, p_blkno, num_clusters);
+		if (iret & (OCFS2_XATTR_ERROR | OCFS2_XATTR_ABORT))
+			break;
+
+		if (e_cpos == 0)
+			break;
+
+		name_hash = e_cpos - 1;
+	}
+
+	if (ctxt->errcode)
+		iret |= OCFS2_XATTR_ERROR;
+	return iret;
+}
+
+static int ocfs2_xattr_iterate_block(struct xattr_iterate_ctxt *ctxt)
+{
+	char *blk = NULL;
+	ocfs2_filesys *fs = ctxt->ci->ci_fs;
+	struct ocfs2_dinode *di = ctxt->ci->ci_inode;
+	struct ocfs2_xattr_block *xb;
+	int iret = 0;
+
+	if (!di->i_xattr_loc)
+		return 0;
+
+	ctxt->errcode = ocfs2_malloc_block(fs->fs_io, &blk);
+	if (ctxt->errcode)
+		goto out;
+
+	ctxt->errcode = ocfs2_read_xattr_block(fs, di->i_xattr_loc, blk);
+	if (ctxt->errcode)
+		goto out;
+
+	xb = (struct ocfs2_xattr_block *)blk;
+	if (xb->xb_flags & OCFS2_XATTR_INDEXED)
+		iret = ocfs2_xattr_iterate_index_block(ctxt, xb);
+	else {
+		struct ocfs2_xattr_header *header = &xb->xb_attrs.xb_header;
+		iret = ocfs2_xattr_iterate_entries(ctxt, blk,
+						   di->i_xattr_loc, header, 0);
+	}
+
+out:
+	if (blk)
+		ocfs2_free(&blk);
+
+	if (ctxt->errcode)
+		iret |= OCFS2_XATTR_ERROR;
+
+	return iret;
+}
+
+
+/*
+ * 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,
+					  char *xe_buf,
+					  uint64_t xe_blkno,
+					  struct ocfs2_xattr_entry *xe,
+					  char *value_buf,
+					  uint64_t value_blkno,
+					  void *value,
+					  int in_bucket,
+					  void *priv_data),
+			      void *priv_data)
+{
+	errcode_t ret = 0;
+	int iret = 0;
+	struct xattr_iterate_ctxt ctxt;
+
+	if (!ocfs2_support_xattr(OCFS2_RAW_SB(ci->ci_fs->fs_super)) ||
+	    (!(ci->ci_inode->i_dyn_features & OCFS2_HAS_XATTR_FL)))
+		return 0;
+
+	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;
+}
-- 
1.5.5




More information about the Ocfs2-tools-devel mailing list