[Ocfs2-devel] [PATCH 2/2] ocfs2-tools: Add extended attribute support in fsck.ocfs2

Tao Ma tao.ma at oracle.com
Fri Jul 25 00:52:36 PDT 2008



Tiger Yang wrote:

> +#include <string.h>
> +#include <inttypes.h>
> +
> +#include "ocfs2/byteorder.h"
> +#include "ocfs2/ocfs2.h"
> +
> +#include "xattr.h"
> +#include "extent.h"
> +#include "fsck.h"
> +#include "problem.h"
> +#include "util.h"
> +
> +static const char *whoami = "xattr.c";
> +
> +static inline int ocfs2_xattr_extent_recs_per_inode(int blocksize)
> +{
> +	int size;
> +
> +	size = blocksize - offsetof(struct ocfs2_xattr_block,
> +				    xb_attrs.xb_root.xt_list.l_recs);
> +
> +	return (size / sizeof(struct ocfs2_extent_rec));
> +}
I remember with 512, there is no xattr in inode.
> +
> +static inline uint16_t ocfs2_xattr_buckets_per_cluster(ocfs2_filesys *fs)
> +{
> +	return (fs->fs_clustersize / OCFS2_XATTR_BUCKET_SIZE);
> +}
> +
> +static inline uint16_t ocfs2_blocks_per_xattr_bucket(ocfs2_filesys *fs)
> +{
> +	return (OCFS2_XATTR_BUCKET_SIZE / fs->fs_blocksize);
> +}
> +
> +static errcode_t check_xattr(o2fsck_state *ost,
> +			     struct ocfs2_dinode *di,
> +			     struct ocfs2_xattr_header *xh,
> +			     int *changed)
> +{
> +	struct extent_info ei = {0, };
> +	int i;
> +	errcode_t ret = 0;
> +
> +	for (i = 0 ; i < xh->xh_count; i++) {
> +		int change = 0;
> +		struct ocfs2_xattr_entry *xe = &xh->xh_entries[i];
> +
> +		if (!xe->xe_local) {
> +			struct ocfs2_xattr_value_root *xv =
> +				(struct ocfs2_xattr_value_root *)
> +				((void *)xh + xe->xe_name_offset +
> +				OCFS2_XATTR_SIZE(xe->xe_name_len));
> +			struct ocfs2_extent_list *el = &xv->xr_list;
> +			ret = check_el(ost, &ei, di, el, 1, &change);
> +			if (ret)
> +				break;
> +			if (change) {
> +				*changed = 1;
> +				ocfs2_swap_extent_list_from_cpu(el);
> +			}
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +static errcode_t ocfs2_xattr_get_rec(o2fsck_state *ost,
> +				     struct ocfs2_dinode *di,
> +				     uint32_t name_hash,
> +				     uint64_t *p_blkno,
> +				     uint32_t *e_cpos,
> +				     uint32_t *num_clusters,
> +				     struct ocfs2_extent_list *el)
> +{
> +	int i;
> +	errcode_t ret = 0;
> +	char *eb_buf = NULL;
> +	struct ocfs2_extent_block *eb;
> +	struct ocfs2_extent_rec *rec = NULL;
> +	uint64_t e_blkno = 0;
> +
> +	if (el->l_tree_depth) {
> +		ret = ocfs2_find_leaf(ost->ost_fs, di, el, name_hash, &eb_buf);
> +		if (ret) {
> +			com_err(whoami, ret, "while finding leaf of xattr "
> +				"tree");
> +			goto out;
> +		}
> +
> +		eb = (struct ocfs2_extent_block *) eb_buf;
> +		el = &eb->h_list;
> +
> +		if (el->l_tree_depth) {
> +			ret = -1;
> +			goto out;
> +		}
> +	}
> +
> +	for (i = le16_to_cpu(el->l_next_free_rec) - 1; i >= 0; i--) {
no le16_to_cpu in tools. there are also some below, please remove them.
> +		rec = &el->l_recs[i];
> +
> +		if (le32_to_cpu(rec->e_cpos) <= name_hash) {
> +			e_blkno = le64_to_cpu(rec->e_blkno);
> +			break;
> +		}
> +	}
> +
> +	if (!e_blkno) {
> +		ret = -1;
> +		goto out;
> +	}
> +
> +	*p_blkno = le64_to_cpu(rec->e_blkno);
> +	*num_clusters = le16_to_cpu(rec->e_leaf_clusters);
> +	if (e_cpos)
> +		*e_cpos = le32_to_cpu(rec->e_cpos);
> +out:
> +	if (eb_buf)
> +		ocfs2_free(&eb_buf);
> +	return ret;
> +}
> +
> +static errcode_t ocfs2_iterate_xattr_buckets(o2fsck_state *ost,
> +					     struct ocfs2_dinode *di,
> +					     uint64_t blkno,
> +					     uint32_t clusters)
> +{
> +	int i;
> +	errcode_t ret = 0;
> +	char *bucket = NULL;
> +	struct ocfs2_xattr_header *xh;
> +	int block_num = ocfs2_blocks_per_xattr_bucket(ost->ost_fs);
> +	uint32_t bpc = ocfs2_xattr_buckets_per_cluster(ost->ost_fs);
> +	uint32_t bucket_num = clusters * bpc;
> +	char *bhs = NULL;
> +
> +
> +	ret = ocfs2_malloc_blocks(ost->ost_fs->fs_io, block_num, &bhs);
> +	if (ret) {
> +		com_err(whoami, ret, "while allocating room to read bucket "
> +			"of xattr data");
> +		goto out;
> +	}
> +
> +	for (i = 0; i < bucket_num; i++, blkno += block_num) {
> +		int changed = 0;
> +
> +		ret = io_read_block(ost->ost_fs->fs_io, blkno, block_num, bhs);
bucket size isn't block size. So you can't just read and handle the 
first block for a bucket. the same for the write.

> +		if (ret) {
> +			com_err(whoami, ret, "while reading blocks of xattr "
> +				"bucket");
> +			goto out;
> +		}
> +
> +		bucket = bhs;
> +
> +		xh = (struct ocfs2_xattr_header *)bucket;
> +		ocfs2_swap_xattr_header(xh);
> +		ocfs2_swap_xattr_entries_to_cpu(xh);
> +		/*
> +		 * The real bucket num in this series of blocks is stored
> +		 * in the 1st bucket.
> +		 */
> +		if (i == 0)
> +			bucket_num = le16_to_cpu(xh->xh_reserved1);
> +
> +		ret = check_xattr(ost, di, xh, &changed);
> +		if (ret)
> +			break;
> +		if (changed) {
> +			ocfs2_swap_xattr_entries_from_cpu(xh);
> +			ocfs2_swap_xattr_header(xh);
> +			io_write_block(ost->ost_fs->fs_io, blkno, block_num,
> +				       bhs);
> +		}
> +	}
> +out:
> +	ocfs2_free(&bhs);
> +
> +	return ret;
> +}
> +
> +static errcode_t o2fsck_check_xattr_index_block(
> +					o2fsck_state *ost,
> +					struct ocfs2_dinode *di,
> +					struct ocfs2_xattr_tree_root *xt,
> +					int *changed)
> +{
> +	struct ocfs2_extent_list *el = &xt->xt_list;
> +	errcode_t ret = 0;
> +	uint32_t name_hash = UINT_MAX, e_cpos = 0, num_clusters = 0;
> +	uint64_t p_blkno = 0;
> +	struct extent_info ei = {0, };
> +
> +	if (el->l_next_free_rec == 0)
> +		return 0;
> +
> +	ret = check_el(ost, &ei, di, el,
> +		ocfs2_xattr_extent_recs_per_inode(ost->ost_fs->fs_blocksize),
> +		changed);
> +	if (ret)
> +		return ret;
> +
> +	while (name_hash > 0) {
> +		ret = ocfs2_xattr_get_rec(ost, di, name_hash, &p_blkno,
> +					  &e_cpos, &num_clusters, el);
> +		if (ret) {
> +			com_err(whoami, ret, "while getting bucket record "
> +				"of xattr data.");
> +			goto out;
> +		}
> +
> +		ret = ocfs2_iterate_xattr_buckets(ost, di, p_blkno,
> +						  num_clusters);
> +		if (ret) {
> +			com_err(whoami, ret, "while iterating buckets "
> +				"of xattr data.");
> +			goto out;
> +		}
> +
> +		if (e_cpos == 0)
> +			break;
> +
> +		name_hash = e_cpos - 1;
> +	}
> +	if (*changed)
> +		ocfs2_swap_extent_list_from_cpu(el);
> +
> +out:
> +	return ret;
> +}
> +
> +static errcode_t o2fsck_check_xattr_ibody(o2fsck_state *ost,
> +					  struct ocfs2_dinode *di)
> +{
> +	errcode_t ret;
> +	struct ocfs2_xattr_header *xh = NULL;
> +	int changed = 0;
> +
> +	xh = (struct ocfs2_xattr_header *)
> +		 ((void *)di + ost->ost_fs->fs_blocksize -
> +		  di->i_xattr_inline_size);
> +
> +	ocfs2_swap_xattr_header(xh);
> +	ocfs2_swap_xattr_entries_to_cpu(xh);
> +
> +	ret = check_xattr(ost, di, xh, &changed);
> +
> +	if (changed) {
> +		ocfs2_swap_xattr_entries_from_cpu(xh);
> +		ocfs2_swap_xattr_header(xh);
> +		o2fsck_write_inode(ost, di->i_blkno, di);
> +	}
> +	return ret;
> +}
> +
> +static errcode_t o2fsck_check_xattr_block(o2fsck_state *ost,
> +					  struct ocfs2_dinode *di)
> +{
> +	errcode_t ret;
> +	char *blk = NULL;
> +	struct ocfs2_xattr_block *xb = NULL;
> +	int changed = 0;
> +
> +	o2fsck_mark_cluster_allocated(ost,
> +		ocfs2_blocks_to_clusters(ost->ost_fs, di->i_xattr_loc));
> +
> +	ret = ocfs2_malloc_block(ost->ost_fs->fs_io, &blk);
> +	if (ret) {
> +		com_err(whoami, ret, "while allocating room to read block "
> +			"of xattr.");
> +		return ret;
> +	}
> +
> +	ret = ocfs2_read_xattr_block(ost->ost_fs, di->i_xattr_loc, blk);
> +	if (ret) {
> +		com_err(whoami, ret, "while reading externel block of xattr.");
> +		return ret;
> +	}
> +
> +	xb = (struct ocfs2_xattr_block *)blk;
> +
> +	if (!(xb->xb_flags & OCFS2_XATTR_INDEXED)) {
> +		struct ocfs2_xattr_header *xh = &xb->xb_attrs.xb_header;
> +
> +		ret = check_xattr(ost, di, xh, &changed);
> +	} else {
> +		struct ocfs2_xattr_tree_root *xt = &xb->xb_attrs.xb_root;
> +
> +		ret = o2fsck_check_xattr_index_block(ost, di, xt, &changed);
> +	}
> +
> +	if (changed)
> +		ocfs2_write_xattr_block(ost->ost_fs, di->i_xattr_loc, blk);
> +
> +	if (blk)
> +		ocfs2_free(&blk);
> +
> +	return ret;
> +}
> +
> +/*
> + * o2fsck_check_xattr
> + *
> + * Check extended attribute in inode block or external block.
> + */
> +errcode_t o2fsck_check_xattr(o2fsck_state *ost,
> +			     struct ocfs2_dinode *di)
> +{
> +	errcode_t ret = 0;
> +
> +	if (!(di->i_dyn_features & OCFS2_HAS_XATTR_FL))
> +		return 0;
> +
> +	if (di->i_dyn_features & OCFS2_HAS_XATTR_FL) {
you mean inline_xattr here?
> +		ret = o2fsck_check_xattr_ibody(ost, di);
> +		if (ret)
> +			return ret;
> +	}
> +	if (di->i_xattr_loc)
> +		ret = o2fsck_check_xattr_block(ost, di);
> +
> +	return ret;
> +}
> diff --git a/include/ocfs2-kernel/ocfs2_fs.h b/include/ocfs2-kernel/ocfs2_fs.h
> index ade9ec1..ee44be8 100644
> --- a/include/ocfs2-kernel/ocfs2_fs.h
> +++ b/include/ocfs2-kernel/ocfs2_fs.h
> @@ -728,6 +728,13 @@ struct ocfs2_group_desc
>  /* Inline extended attribute size (in bytes) */
>  #define OCFS2_MIN_XATTR_INLINE_SIZE     256
>  
> +#define OCFS2_XATTR_BUCKET_SIZE		4096
> +
> +#define OCFS2_XATTR_ROUND		3
> +
> +#define OCFS2_XATTR_SIZE(size)  (((size) + OCFS2_XATTR_ROUND) & \
> +				~(OCFS2_XATTR_ROUND))
> +
>  struct ocfs2_xattr_entry {
>  	__le32	xe_name_hash;
>  	__le16	xe_name_offset;
> diff --git a/include/ocfs2/ocfs2.h b/include/ocfs2/ocfs2.h
> index 1f81c47..6aadd46 100644
> --- a/include/ocfs2/ocfs2.h
> +++ b/include/ocfs2/ocfs2.h
> @@ -291,6 +291,7 @@ errcode_t ocfs2_get_clusters(ocfs2_cached_inode *cinode,
>  			     uint32_t *num_clusters,
>  			     uint16_t *extent_flags);
>  int ocfs2_find_leaf(ocfs2_filesys *fs, struct ocfs2_dinode *di,
> +		    struct ocfs2_extent_list *el,
>  		    uint32_t cpos, char **leaf_buf);
>  int ocfs2_search_extent_list(struct ocfs2_extent_list *el, uint32_t v_cluster);
>  void ocfs2_swap_journal_superblock(journal_superblock_t *jsb);
> @@ -942,5 +943,10 @@ errcode_t ocfs2_block_iterate_inode(ocfs2_filesys *fs,
>  				    void *priv_data);
>  
>  uint32_t xattr_uuid_hash(unsigned char *uuid);
> +void ocfs2_swap_xattr_entries_to_cpu(struct ocfs2_xattr_header *xh);
> +void ocfs2_swap_xattr_entries_from_cpu(struct ocfs2_xattr_header *xh);
> +void ocfs2_swap_xattr_header(struct ocfs2_xattr_header *xh);
> +void ocfs2_swap_xattr_block_from_cpu(struct ocfs2_xattr_block *xb);
> +void ocfs2_swap_xattr_block_to_cpu(struct ocfs2_xattr_block *xb);
>  
>  #endif  /* _FILESYS_H */
> diff --git a/libocfs2/extend_file.c b/libocfs2/extend_file.c
> index 1cb4a00..4cc7a94 100644
> --- a/libocfs2/extend_file.c
> +++ b/libocfs2/extend_file.c
> @@ -997,16 +997,16 @@ static int ocfs2_find_path(ocfs2_filesys *fs, struct ocfs2_path *path,
>   * This function doesn't handle non btree extent lists.
>   */
>  int ocfs2_find_leaf(ocfs2_filesys *fs, struct ocfs2_dinode *di,
> +		    struct ocfs2_extent_list *el,
>  		    uint32_t cpos, char **leaf_buf)
>  {
>  	int ret;
>  	char *buf = NULL;
>  	struct ocfs2_path *path = NULL;
> -	struct ocfs2_extent_list *el = &di->id2.i_list;
>  
>  	assert(el->l_tree_depth > 0);
>  
> -	path = ocfs2_new_inode_path(fs, di);
> +	path = ocfs2_new_path(fs, (char *)di, el);
>  	if (!path) {
>  		ret = OCFS2_ET_NO_MEMORY;
>  		goto out;
> diff --git a/libocfs2/extent_map.c b/libocfs2/extent_map.c
> index 7e5f8fe..dd081fc 100644
> --- a/libocfs2/extent_map.c
> +++ b/libocfs2/extent_map.c
> @@ -147,7 +147,7 @@ errcode_t ocfs2_get_clusters(ocfs2_cached_inode *cinode,
>  	el = &di->id2.i_list;
>  
>  	if (el->l_tree_depth) {
> -		ret = ocfs2_find_leaf(fs, di, v_cluster, &eb_buf);
> +		ret = ocfs2_find_leaf(fs, di, el, v_cluster, &eb_buf);
>  		if (ret)
>  			goto out;
>  
> diff --git a/libocfs2/ocfs2_err.et b/libocfs2/ocfs2_err.et
> index 9b33a3b..88b3366 100644
> --- a/libocfs2/ocfs2_err.et
> +++ b/libocfs2/ocfs2_err.et
> @@ -171,4 +171,7 @@ ec	OCFS2_ET_NO_BACKUP_SUPER,
>  ec      OCFS2_ET_TOO_MANY_SLOTS,
>          "Too many slots for slot map"
>  
> +ec	OCFS2_ET_BAD_XATTR_BLOCK_MAGIC,
> +	"Bad magic number in xattr block"
> +
>  	end
> diff --git a/libocfs2/xattr.c b/libocfs2/xattr.c
> index d198743..767b333 100644
> --- a/libocfs2/xattr.c
> +++ b/libocfs2/xattr.c
> @@ -35,3 +35,113 @@ uint32_t xattr_uuid_hash(unsigned char *uuid)
>  	return hash;
>  }
>  
> +static void ocfs2_swap_xattr_tree_root(struct ocfs2_xattr_tree_root *xt)
> +{
> +	xt->xt_clusters		= bswap_16(xt->xt_clusters);
> +	xt->xt_last_eb_blk	= bswap_16(xt->xt_last_eb_blk);
> +}
> +
> +static void ocfs2_swap_xattr_value_root(struct ocfs2_xattr_value_root *xr)
> +{
> +	xr->xr_clusters		= bswap_16(xr->xr_clusters);
> +	xr->xr_last_eb_blk	= bswap_16(xr->xr_last_eb_blk);
> +}
> +
> +static void ocfs2_swap_xattr_block_header(struct ocfs2_xattr_block *xb)
> +{
> +	xb->xb_suballoc_slot	= bswap_16(xb->xb_suballoc_slot);
> +	xb->xb_suballoc_bit	= bswap_16(xb->xb_suballoc_bit);
> +	xb->xb_fs_generation	= bswap_32(xb->xb_fs_generation);
> +	xb->xb_csum 		= bswap_32(xb->xb_csum);
> +	xb->xb_flags		= bswap_16(xb->xb_flags);
> +	xb->xb_blkno		= bswap_64(xb->xb_blkno);
> +}
> +
> +void ocfs2_swap_xattr_entries_to_cpu(struct ocfs2_xattr_header *xh)
> +{
> +	uint16_t i;
> +
> +	if (cpu_is_little_endian)
> +		return;
> +
> +	for (i = 0; i < xh->xh_count; i++) {
> +		struct ocfs2_xattr_entry *xe = &xh->xh_entries[i];
> +
> +		xe->xe_name_offset	= bswap_16(xe->xe_name_offset);
> +		xe->xe_value_size	= bswap_64(xe->xe_value_size);
> +
> +		if (!xe->xe_local) {
> +			struct ocfs2_xattr_value_root *xr =
> +				(struct ocfs2_xattr_value_root *)
> +				((char *)xh + xe->xe_name_offset +
> +				OCFS2_XATTR_SIZE(xe->xe_name_len));
> +
> +			ocfs2_swap_xattr_value_root(xr);
> +			ocfs2_swap_extent_list_to_cpu(&xr->xr_list);
> +		}
> +	}
> +}
> +
> +void ocfs2_swap_xattr_entries_from_cpu(struct ocfs2_xattr_header *xh)
> +{
> +	uint16_t i;
> +
> +	if (cpu_is_little_endian)
> +		return;
> +
> +	for (i = 0; i < xh->xh_count; i++) {
> +		struct ocfs2_xattr_entry *xe = &xh->xh_entries[i];
> +
> +		if (!xe->xe_local) {
> +			struct ocfs2_xattr_value_root *xr =
> +				(struct ocfs2_xattr_value_root *)
> +				((char *)xh + xe->xe_name_offset +
> +				OCFS2_XATTR_SIZE(xe->xe_name_len));
> +
> +			ocfs2_swap_xattr_value_root(xr);
> +		}
> +		xe->xe_name_offset	= bswap_16(xe->xe_name_offset);
> +		xe->xe_value_size	= bswap_64(xe->xe_value_size);
> +	}
> +}
> +
> +void ocfs2_swap_xattr_header(struct ocfs2_xattr_header *xh)
> +{
> +	if (cpu_is_little_endian)
> +		return;
> +
> +	xh->xh_count		= bswap_16(xh->xh_count);
> +	xh->xh_reserved1	= bswap_16(xh->xh_reserved1);
> +	xh->xh_csum		= bswap_32(xh->xh_csum);
> +}
> +
> +void ocfs2_swap_xattr_block_from_cpu(struct ocfs2_xattr_block *xb)
> +{
> +	if (cpu_is_little_endian)
> +		return;
> +
> +	if (!(xb->xb_flags & OCFS2_XATTR_INDEXED)) {
you should handle xb_flags swap first.
> +		ocfs2_swap_xattr_entries_from_cpu(&xb->xb_attrs.xb_header);
> +		ocfs2_swap_xattr_header(&xb->xb_attrs.xb_header);
> +	} else {
> +		ocfs2_swap_xattr_tree_root(&xb->xb_attrs.xb_root);
> +	}
> +
> +	ocfs2_swap_xattr_block_header(xb);
> +}
> +
> +void ocfs2_swap_xattr_block_to_cpu(struct ocfs2_xattr_block *xb)
> +{
> +	if (cpu_is_little_endian)
> +		return;
> +
> +	ocfs2_swap_xattr_block_header(xb);
> +	if (!(xb->xb_flags & OCFS2_XATTR_INDEXED)) {
> +		ocfs2_swap_xattr_header(&xb->xb_attrs.xb_header);
> +		ocfs2_swap_xattr_entries_to_cpu(&xb->xb_attrs.xb_header);
> +	} else {
> +		ocfs2_swap_xattr_tree_root(&xb->xb_attrs.xb_root);
> +		ocfs2_swap_extent_list_to_cpu(&xb->xb_attrs.xb_root.xt_list);
> +	}
> +}
> +



More information about the Ocfs2-devel mailing list