[Ocfs2-tools-devel] [PATCH 07/15] dx_dirs v11: more library support for directory indexing

Tao Ma tao.ma at oracle.com
Fri Apr 23 07:26:28 PDT 2010


Hi coly,
	the 2nd part of review for this really large patch. ;)

Coly Li wrote:
> This patch adds more library support for indexed dirs,
> - dx_root alloc/delete
> - dx_leaf alloc/delete
> - dx_root read/write
> - dx_leaf read/write
> - indexed tree insert/truncate
> - dx_root extent tree operations
> - indexed dir support in ocfs2_lookup_system_inode(),
>   ocfs2_init_dir(), ocfs2_link(), ocfs2_unlink(),
>   ocfs2_lookup().
> With this patch, indexed dirs support in fsck.ocfs2 is possible.
> 
> Signed-off-by: Coly Li <coly.li at suse.de>
> Cc: Mark Fasheh <mfasheh at suse.com>
> +static int dir_trailer_func(ocfs2_filesys *fs,
> +				uint64_t blkno,
> +				uint64_t bcount,
> +				uint16_t ext_flags,
> +				void *priv_data)
> +{
> +	struct trailer_ctxt *ctxt = (struct trailer_ctxt *)priv_data;
> +	struct ocfs2_dinode *di = ctxt->di;
> +	struct ocfs2_dx_root_block *dx_root = ctxt->dx_root;
> +	struct ocfs2_dir_block_trailer *trailer;
> +	int max_rec_len = 0;
> +	errcode_t ret = 0;
> +	char *blk = NULL;
> +
> +	ret = ocfs2_malloc_block(fs->fs_io, &blk);
> +	if (ret)
> +		goto out;
This function has the same problem for extent_iterate_el. We may need a 
errcode_t member in trailer_ctxt. And in case of any error in this 
function, we just need to set OCFS2_EXTENT_ERROR. And the iteration 
caller, ocfs2_init_dir_trailers in this case, should check the errcode 
by itself.
> +
> +	/* here we don't trust trailer, cannot use
> +	 * ocfs2_read_dir_block() */
> +	ret = ocfs2_read_blocks(fs, blkno, 1, blk);
> +	if (ret)
> +		goto out;
> +	ret = ocfs2_check_dir_trailer_space(fs, di, blkno, blk);
> +	if (ret)
> +		goto out;
> +	ocfs2_init_dir_trailer(fs, di, blkno, blk);
> +	max_rec_len = ocfs2_find_max_rec_len(fs, blk);
> +	trailer = ocfs2_dir_trailer_from_block(fs, blk);
> +	trailer->db_free_rec_len = max_rec_len;
> +
> +	if (max_rec_len) {
> +		trailer->db_free_next = dx_root->dr_free_blk;
> +		dx_root->dr_free_blk = blkno;
> +	}
> +
> +	/* comput trailer->db_check here, after writes out,
> +	 * trailer is trustable */
> +	ret = ocfs2_write_dir_block(fs, di, blkno, blk);
> +out:
> +	if (blk)
> +		ocfs2_free(&blk);
> +	return ret;
> +}
<snip>
> +/*
> + * This function overwite the indexed dir attribute of
> + * the given inode. The caller should make sure the dir's
> + * indexed tree is truncated.
> + * Currently tunefs.ocfs2 is the only user, before calling
> + * this function, tunefs.ocfs2 makes sure there is space
> + * for directory trailer. So directory entry moves here.
> + */
> +errcode_t ocfs2_dx_dir_build(ocfs2_filesys *fs,
> +			uint64_t dir)
> +{
> +	errcode_t ret = 0, err;
> +	uint64_t dr_blkno;
> +	char *dx_buf = NULL, *di_buf = NULL;
> +	struct ocfs2_dinode *di;
> +	struct ocfs2_dx_root_block *dx_root;
> +	struct dx_insert_ctxt ctxt;
> +	ocfs2_quota_hash *usrhash = NULL, *grphash = NULL;
> +	uint32_t uid, gid;
> +	long long change;
> +
> +	ret = ocfs2_load_fs_quota_info(fs);
> +	if (ret)
> +		goto out;
> +
> +	ret = ocfs2_init_quota_change(fs, &usrhash, &grphash);
> +	if (ret)
> +		goto out;
> +
> +	ret = ocfs2_malloc_block(fs->fs_io, &di_buf);
> +	if (ret)
> +		goto out;
> +
> +	ret = ocfs2_read_inode(fs, dir, di_buf);
> +	if (ret)
> +		goto out;
> +	di = (struct ocfs2_dinode *)di_buf;
> +
> +	if ((ocfs2_dir_indexed(di)) ||
> +	    (di->i_dyn_features & OCFS2_INLINE_DATA_FL))
> +		goto out;
> +
> +	ret = ocfs2_new_dx_root(fs, di, &dr_blkno);
> +	if (ret)
> +		goto out;
> +
> +	ret = ocfs2_malloc_block(fs->fs_io, &dx_buf);
> +	if (ret)
> +		goto out;
> +
> +	ret = ocfs2_read_dx_root(fs, dr_blkno, dx_buf);
> +	if (ret)
> +		goto out;
> +	dx_root = (struct ocfs2_dx_root_block *)dx_buf;
> +
> +	ret = ocfs2_init_dir_trailers(fs, di, dx_root);
> +	if (ret)
> +		goto out;
> +
> +	dx_root->dr_dir_blkno = di->i_blkno;
> +	dx_root->dr_num_entries = 0;
> +	dx_root->dr_entries.de_count = ocfs2_dx_entries_per_root(fs->fs_blocksize);
> +
> +	di->i_dx_root = dr_blkno;
> +	di->i_dyn_features |= OCFS2_INDEXED_DIR_FL;
> +
> +	ret = ocfs2_write_dx_root(fs, dr_blkno, dx_buf);
> +	if (ret)
> +		goto out;
> +	ret = ocfs2_write_inode(fs, dir, di_buf);
> +	if (ret)
> +		goto out;
Can we really update the inode information so earlier? If we set the 
indexed dir flag, we will search indexed dir first in ocfs2_lookup. But 
now we only update the trailer actually. So if the following 
ocfs2_dx_dir_insert has some error, the dir entries will be lost from 
the user's perspective.
> +
> +	ctxt.dir_blkno = dir;
> +	ctxt.dx_root_blkno = dr_blkno;
> +	ctxt.fs = fs;
> +	ret = ocfs2_dir_iterate(fs, dir, 0, NULL,
> +				ocfs2_dx_dir_insert,  &ctxt);
> +
> +	/* check quota for dx_leaf */
> +	ret = ocfs2_read_dx_root(fs, dr_blkno, dx_buf);
> +	if (ret)
> +		goto out;
> +	ret = ocfs2_read_inode(fs, dir, di_buf);
> +	if (ret)
> +		goto out;
> +
> +	change = ocfs2_clusters_to_bytes(fs,
> +				dx_root->dr_clusters);
> +	uid = di->i_uid;
> +	gid = di->i_gid;
> +
> +	ret = ocfs2_apply_quota_change(fs, usrhash, grphash,
> +					uid, gid, change, 0);
> +	if (ret) {
> +		/* exceed quota, truncate the indexed tree */
> +		ret = ocfs2_dx_dir_truncate(fs, dir);
> +	}
> +
> +out:
> +	err = ocfs2_finish_quota_change(fs, usrhash, grphash);
> +	if (!ret)
> +		ret = err;
> +
> +	if (di_buf)
> +		ocfs2_free(&di_buf);
> +	if (dx_buf)
> +		ocfs2_free(&dx_buf);
> +
> +	return ret;
> +}
<snip>
> -static void ocfs2_swap_dx_entry_to_cpu(struct ocfs2_dx_entry *dx_entry)
> +static void ocfs2_swap_dx_entry(struct ocfs2_dx_entry *dx_entry)
>  {
> -	if (cpu_is_little_endian)
> -		return;
> -
>  	dx_entry->dx_major_hash		= bswap_32(dx_entry->dx_major_hash);
>  	dx_entry->dx_minor_hash		= bswap_32(dx_entry->dx_minor_hash);
>  	dx_entry->dx_dirent_blk		= bswap_64(dx_entry->dx_dirent_blk);
>  }
>  
> -static void ocfs2_swap_dx_entry_list_to_cpu(struct ocfs2_dx_entry_list *dl_list)
> +static void ocfs2_swap_dx_entry_list(struct ocfs2_dx_entry_list *dl_list)
>  {
>  	int i;
>  
> -	if (cpu_is_little_endian)
> -		return;
> -
>  	dl_list->de_count	= bswap_16(dl_list->de_count);
>  	dl_list->de_num_used	= bswap_16(dl_list->de_num_used);
>  
>  	for (i = 0; i < dl_list->de_count; i++)
> -		ocfs2_swap_dx_entry_to_cpu(&dl_list->de_entries[i]);
> +		ocfs2_swap_dx_entry(&dl_list->de_entries[i]);
> +}
> +
> +static void ocfs2_swap_dx_entry_list_to_cpu(struct ocfs2_dx_entry_list *dl_list)
> +{
> +	if (cpu_is_little_endian)
> +		return;
> +	ocfs2_swap_dx_entry_list(dl_list);
> +}
> +
> +static void ocfs2_swap_dx_entry_list_from_cpu(struct ocfs2_dx_entry_list *dl_list)
> +{
> +	if (cpu_is_little_endian)
> +		return;
> +	ocfs2_swap_dx_entry_list(dl_list);
>  }
Hey, why do you change the original one? Your code is buggy now. When 
swap_entry_list_to_cpu you need to swap de_count/de_num_used first. 
While if we want to swap_entry_list_from_cpu we neet to swap the 
dx_entry first.
>  
>  static void ocfs2_swap_dx_root_to_cpu(ocfs2_filesys *fs,

Regards,
Tao



More information about the Ocfs2-tools-devel mailing list