[Ocfs2-devel] [PATCH 07/15] Add extent tree operation for xattr value.v3

Joel Becker Joel.Becker at oracle.com
Fri Aug 15 19:18:54 PDT 2008


On Thu, Aug 07, 2008 at 06:31:29AM +0800, Tao Ma wrote:
> --- a/fs/ocfs2/alloc.c
> +++ b/fs/ocfs2/alloc.c
> @@ -78,6 +78,7 @@ struct ocfs2_extent_tree {
>  	struct ocfs2_extent_tree_operations *eops;
>  	struct buffer_head *root_bh;
>  	struct ocfs2_extent_list *root_el;
> +	void *private;
>  };

	Why 'private'?  Why not 'object'?  I don't like this if block:

>  static struct ocfs2_extent_tree*
>  	 ocfs2_new_extent_tree(struct buffer_head *bh,
> -			       enum ocfs2_extent_tree_type et_type)
> +			       enum ocfs2_extent_tree_type et_type,
> +			       void *private)
>  {
>  	struct ocfs2_extent_tree *et;
>  
> @@ -149,12 +191,16 @@ static struct ocfs2_extent_tree*
>  	et->type = et_type;
>  	get_bh(bh);
>  	et->root_bh = bh;
> +	et->private = private;
>  
> -	/* current we only support dinode extent. */
> -	BUG_ON(et->type != OCFS2_DINODE_EXTENT);
>  	if (et_type == OCFS2_DINODE_EXTENT) {
>  		et->root_el = &((struct ocfs2_dinode *)bh->b_data)->id2.i_list;
>  		et->eops = &ocfs2_dinode_et_ops;
> +	} else if (et_type == OCFS2_XATTR_VALUE_EXTENT) {
> +		struct ocfs2_xattr_value_root *xv =
> +			(struct ocfs2_xattr_value_root *) private;
> +		et->root_el = &xv->xr_list;
> +		et->eops = &ocfs2_xattr_et_ops;
>  	}

	Why don't you have an operation for getting the el?  Really, the
way I see it, you should have:

    void ocfs2_fill_extent_tree(*et, *bh, void *object, type)
    {
            et->et_type = type;
            et->et_ops = extent_tree_ops[type];
            get_bh(bh);
            et->et_root_bh = bh;
            et->et_object = object ? object : (void *)bh->b_data;
            et->et_root_el = et->et_ops->et_get_root_el(et);
    }

If you pass NULL for *object, it knows to use the start of the bh.  This
works for dinode, etc.  But you can pass a non-NULL object for the
xattr_value_root.  The get_root_el operations know how to take et_object
and return the el:

    ocfs2_dinode_get_root_el(*et)
    {
            struct ocfs2_dinode *di = et->et_object;
            return &di->id2.i_list;
    }
    ocfs2_xattr_value_root_get_el(*et)
    {
            struct ocfs2_xattr_value_root *xv = et->et_object;
            return &xv->xr_list;
    }

> @@ -495,7 +541,8 @@ struct ocfs2_merge_ctxt {
>  int ocfs2_num_free_extents(struct ocfs2_super *osb,
>  			   struct inode *inode,
>  			   struct buffer_head *root_bh,
> -			   enum ocfs2_extent_tree_type type)
> +			   enum ocfs2_extent_tree_type type,
> +			   void *private)
>  {
>  	int retval;
>  	struct ocfs2_extent_list *el = NULL;
> @@ -517,6 +564,12 @@ int ocfs2_num_free_extents(struct ocfs2_super *osb,
>  		if (fe->i_last_eb_blk)
>  			last_eb_blk = le64_to_cpu(fe->i_last_eb_blk);
>  		el = &fe->id2.i_list;
> +	} else if (type == OCFS2_XATTR_VALUE_EXTENT) {
> +		struct ocfs2_xattr_value_root *xv =
> +			(struct ocfs2_xattr_value_root *) private;
> +
> +		last_eb_blk = le64_to_cpu(xv->xr_last_eb_blk);
> +		el = &xv->xr_list;

	Again, just to avoid the extent_tree object, you are
hand-accessing the last_eb_block and el entries.  I really think you
should be passing an *et into this function.

> -int ocfs2_insert_extent(struct ocfs2_super *osb,
> -			handle_t *handle,
> -			struct inode *inode,
> -			struct buffer_head *root_bh,
> -			u32 cpos,
> -			u64 start_blk,
> -			u32 new_clusters,
> -			u8 flags,
> -			struct ocfs2_alloc_context *meta_ac,
> -			enum ocfs2_extent_tree_type et_type)
> +static int ocfs2_insert_extent(struct ocfs2_super *osb,
> +			       handle_t *handle,
> +			       struct inode *inode,
> +			       struct buffer_head *root_bh,
> +			       u32 cpos,
> +			       u64 start_blk,
> +			       u32 new_clusters,
> +			       u8 flags,
> +			       struct ocfs2_alloc_context *meta_ac,
> +			       struct ocfs2_extent_tree *et)

	Here you are passing in the et, so you don't need root_bh
anymore, right

> @@ -4554,7 +4658,8 @@ int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *root_bh,
>  			      handle_t *handle, u32 cpos, u32 len, u32 phys,
>  			      struct ocfs2_alloc_context *meta_ac,
>  			      struct ocfs2_cached_dealloc_ctxt *dealloc,
> -			      enum ocfs2_extent_tree_type et_type)
> +			      enum ocfs2_extent_tree_type et_type,
> +			      void *private)

	Here again you're passing root_bh, et_type, and private.  Why
not just pass in the et?

> +int ocfs2_xattr_get_clusters(struct inode *inode, u32 v_cluster,
> +			     u32 *p_cluster, u32 *num_clusters,
> +			     struct ocfs2_extent_list *el)
> +{
> +	int ret = 0, i;
> +	struct buffer_head *eb_bh = NULL;
> +	struct ocfs2_extent_block *eb;
> +	struct ocfs2_extent_rec *rec;
> +	u32 coff;
> +
> +	if (el->l_tree_depth) {
> +		ret = ocfs2_find_leaf(inode, el, v_cluster, &eb_bh);
> +		if (ret) {
> +			mlog_errno(ret);
> +			goto out;
> +		}
> +
> +		eb = (struct ocfs2_extent_block *) eb_bh->b_data;
> +		el = &eb->h_list;
> +
> +		if (el->l_tree_depth) {
> +			ocfs2_error(inode->i_sb,
> +				    "Inode %lu has non zero tree depth in "
> +				    "xattr leaf block %llu\n", inode->i_ino,
> +				    (unsigned long long)eb_bh->b_blocknr);
> +			ret = -EROFS;
> +			goto out;
> +		}
> +	}
> +
> +	i = ocfs2_search_extent_list(el, v_cluster);
> +	if (i == -1) {
> +		ret = -EROFS;
> +		mlog_errno(ret);
> +		goto out;
> +	} else {
> +		rec = &el->l_recs[i];
> +		BUG_ON(v_cluster < le32_to_cpu(rec->e_cpos));
> +
> +		if (!rec->e_blkno) {
> +			ocfs2_error(inode->i_sb, "Inode %lu has bad extent "
> +				    "record (%u, %u, 0) in xattr", inode->i_ino,
> +				    le32_to_cpu(rec->e_cpos),
> +				    ocfs2_rec_clusters(el, rec));
> +			ret = -EROFS;
> +			goto out;
> +		}
> +		coff = v_cluster - le32_to_cpu(rec->e_cpos);
> +		*p_cluster = ocfs2_blocks_to_clusters(inode->i_sb,
> +						    le64_to_cpu(rec->e_blkno));
> +		*p_cluster = *p_cluster + coff;
> +		if (num_clusters)
> +			*num_clusters = ocfs2_rec_clusters(el, rec) - coff;
> +	}
> +out:
> +	if (eb_bh)
> +		brelse(eb_bh);
> +	return ret;
> +}

	Part of me wonders if you could have refactored
ocfs2_get_clusters to share most of this duplicated code.  But I do see
the difference, and we can always come back to it.

> diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c
> index d82a9a0..00d0fff 100644
> --- a/fs/ocfs2/suballoc.c
> +++ b/fs/ocfs2/suballoc.c
> @@ -1906,7 +1906,8 @@ int ocfs2_lock_allocators(struct inode *inode, struct buffer_head *root_bh,
>  			  struct ocfs2_extent_list *root_el,
>  			  u32 clusters_to_add, u32 extents_to_split,
>  			  struct ocfs2_alloc_context **data_ac,
> -			  struct ocfs2_alloc_context **meta_ac)
> +			  struct ocfs2_alloc_context **meta_ac,
> +			  enum ocfs2_extent_tree_type type, void *private)

	Pass in a struct ocfs2_extent_list and you don't have to pass
root_bh. root_el, type, or private.

> @@ -1992,7 +1993,8 @@ int ocfs2_add_clusters_in_btree(struct ocfs2_super *osb,
>  				struct ocfs2_alloc_context *data_ac,
>  				struct ocfs2_alloc_context *meta_ac,
>  				enum ocfs2_alloc_restarted *reason_ret,
> -				enum ocfs2_extent_tree_type type)
> +				enum ocfs2_extent_tree_type type,
> +				void *private)

	Same here.  I'll stop repeating this.

> diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c
> new file mode 100644
> index 0000000..9604a4c
> --- /dev/null
> +++ b/fs/ocfs2/xattr.c

	This file I like :-)  Pretty straightforward and clean.

Joel

-- 

"Too much walking shoes worn thin.
 Too much trippin' and my soul's worn thin.
 Time to catch a ride it leaves today
 Her name is what it means.
 Too much walking shoes worn thin."

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



More information about the Ocfs2-devel mailing list