[Ocfs2-devel] [PATCH 12/15] Add xattr find process for xattr index btree.v2
Mark Fasheh
mfasheh at suse.com
Fri Jul 11 16:59:14 PDT 2008
On Fri, Jun 27, 2008 at 03:02:35PM +0800, Tao Ma wrote:
> +static int ocfs2_cp_xattr_bucket_to_buffer(struct inode *inode,
> + u64 blkno,
> + char *buffer)
> +{
> + int i, ret, block_num = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
> + int blocksize = inode->i_sb->s_blocksize;
> + struct buffer_head **bhs = NULL;
> + char *target;
> +
> + bhs = kzalloc(sizeof(struct buffer_head *) * block_num, GFP_NOFS);
> + ret = ocfs2_read_xattr_bucket(inode, blkno, bhs, 0);
> + if (ret)
> + goto out;
> +
> + target = buffer;
> + for (i = 0; i < block_num; i++, target += blocksize)
> + memcpy(target, bhs[i]->b_data, blocksize);
> +
> +out:
> + if (bhs) {
> + for (i = 0; i < block_num; i++)
> + brelse(bhs[i]);
> + kfree(bhs);
> + }
> + return ret;
> +}
> +
> +/*
> + * Find the specided xattr entry in a series of buckets.
> + * This series start from p_blkno and last for num_clusters.
> + * The ocfs2_xattr_header.xh_reserved1 of the first bucket contains
> + * the num of the valid buckets.
> + *
> + * Return the buffer_head this xattr should reside in. And if the xattr's
> + * hash is in the gap of 2 buckets, return the lower bucket.
> + */
> +static int ocfs2_xattr_bucket_find(struct inode *inode,
> + int name_index,
> + const char *name,
> + u32 name_hash,
> + u64 p_blkno,
> + u32 first_hash,
> + u32 num_clusters,
> + struct ocfs2_xattr_search *xs)
> +{
> + int ret, found = 0;
> + struct buffer_head *bh = NULL;
> + struct buffer_head *last_bh = NULL;
> + struct buffer_head *lower_bh = NULL;
> + struct ocfs2_xattr_header *xh = NULL;
> + struct ocfs2_xattr_entry *xe = NULL;
> + u16 xh_count, xe_index = 0;
> + u16 block_in_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
> + int low_bucket = 0, bucket, high_bucket;
> + int blocksize = inode->i_sb->s_blocksize;
> + u32 last_hash;
> + u64 blkno;
> +
> + ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), p_blkno,
> + &bh, OCFS2_BH_CACHED, inode);
> + if (ret)
> + goto out;
> + xh = (struct ocfs2_xattr_header *)bh->b_data;
> + high_bucket = le16_to_cpu(xh->xh_reserved1) - 1;
> +
> + while (low_bucket <= high_bucket) {
> + brelse(bh);
> + bh = last_bh = NULL;
> + bucket = (low_bucket + high_bucket) / 2;
> +
> + blkno = p_blkno + bucket * block_in_bucket;
> +
> + ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), blkno,
> + &bh, OCFS2_BH_CACHED, inode);
> + if (ret) {
> + mlog_errno(ret);
> + goto out;
> + }
> +
> + xh = (struct ocfs2_xattr_header *)bh->b_data;
> + xe = &xh->xh_entries[0];
> + if (name_hash < le32_to_cpu(xe->xe_name_hash)) {
> + high_bucket = bucket - 1;
> + continue;
> + }
This function looks like it's doing a lot of random I/O. What about sucking
up some large numbers of (contiguous) blocks with a readahead request before
going into this function? The beauty of how our readhead works is that you
wouldn't have to change a single line of code here...
--
Mark Fasheh
More information about the Ocfs2-devel
mailing list