[Ocfs2-tools-devel] [PATCH 03/12] libocfs2: Support directory block trailers.

Sunil Mushran sunil.mushran at oracle.com
Wed Jan 7 19:07:50 PST 2009


I have one qs. Else looks good.

Joel Becker wrote:
> Teach the various parts of libocfs2 to read, skip, and write directory
> block trailers.  These trailers live as a fake dirent at the end of the
> block.
>
> Signed-off-by: Joel Becker <joel.becker at oracle.com>
> ---
>  include/ocfs2/ocfs2.h  |   11 +++++
>  libocfs2/dir_iterate.c |   12 ++++--
>  libocfs2/dir_scan.c    |    4 +-
>  libocfs2/dirblock.c    |  106 ++++++++++++++++++++++++++++++++++++++++++++++-
>  libocfs2/expanddir.c   |   13 +++++-
>  libocfs2/fileio.c      |   10 ++++-
>  libocfs2/link.c        |   69 ++++++++++++++++++-------------
>  libocfs2/ocfs2_err.et  |    3 +
>  8 files changed, 188 insertions(+), 40 deletions(-)
>
> diff --git a/include/ocfs2/ocfs2.h b/include/ocfs2/ocfs2.h
> index 32c4c2a..4b8444f 100644
> --- a/include/ocfs2/ocfs2.h
> +++ b/include/ocfs2/ocfs2.h
> @@ -96,6 +96,7 @@
>  #define OCFS2_DIRENT_FLAG_INCLUDE_EMPTY		0x01
>  #define OCFS2_DIRENT_FLAG_INCLUDE_REMOVED	0x02
>  #define OCFS2_DIRENT_FLAG_EXCLUDE_DOTS		0x04
> +#define OCFS2_DIRENT_FLAG_INCLUDE_TRAILER	0x08
>  
>  /* Return flags for the chain iterator functions */
>  #define OCFS2_CHAIN_CHANGED	0x01
> @@ -305,10 +306,20 @@ errcode_t ocfs2_write_extent_block(ocfs2_filesys *fs, uint64_t blkno,
>         				   char *eb_buf);
>  errcode_t ocfs2_swap_dir_entries_from_cpu(void *buf, uint64_t bytes);
>  errcode_t ocfs2_swap_dir_entries_to_cpu(void *buf, uint64_t bytes);
> +void ocfs2_swap_dir_trailer(struct ocfs2_dir_block_trailer *trailer);
>  errcode_t ocfs2_read_dir_block(ocfs2_filesys *fs, struct ocfs2_dinode *di,
>  			       uint64_t block, void *buf);
>  errcode_t ocfs2_write_dir_block(ocfs2_filesys *fs, struct ocfs2_dinode *di,
>  				uint64_t block, void *buf);
> +unsigned int ocfs2_dir_trailer_blk_off(ocfs2_filesys *fs);
> +struct ocfs2_dir_block_trailer *ocfs2_dir_trailer_from_block(ocfs2_filesys *fs,
> +							     void *data);
> +int ocfs2_supports_dir_trailer(ocfs2_filesys *fs);
> +int ocfs2_dir_has_trailer(ocfs2_filesys *fs, struct ocfs2_dinode *di);
> +int ocfs2_skip_dir_trailer(ocfs2_filesys *fs, struct ocfs2_dinode *di,
> +			   struct ocfs2_dir_entry *de, unsigned long offset);
> +void ocfs2_init_dir_trailer(ocfs2_filesys *fs, struct ocfs2_dinode *di,
> +			    uint64_t blkno, void *buf);
>  
>  errcode_t ocfs2_dir_iterate2(ocfs2_filesys *fs,
>  			     uint64_t dir,
> diff --git a/libocfs2/dir_iterate.c b/libocfs2/dir_iterate.c
> index 83b0b08..00c8d16 100644
> --- a/libocfs2/dir_iterate.c
> +++ b/libocfs2/dir_iterate.c
> @@ -189,12 +189,16 @@ static int ocfs2_process_dir_entry(ocfs2_filesys *fs,
>  			ctx->errcode = OCFS2_ET_DIR_CORRUPTED;
>  			return OCFS2_BLOCK_ABORT;
>  		}
> -		if (!dirent->inode &&
> -		    !(ctx->flags & OCFS2_DIRENT_FLAG_INCLUDE_EMPTY))
> +		if (ocfs2_skip_dir_trailer(fs, ctx->di, dirent, offset)) {
> +			if (!(ctx->flags & OCFS2_DIRENT_FLAG_INCLUDE_TRAILER))
> +				goto next;
> +		} else if (!dirent->inode &&
> +			   !(ctx->flags & OCFS2_DIRENT_FLAG_INCLUDE_EMPTY)) {
>  			goto next;
> -		if ((ctx->flags & OCFS2_DIRENT_FLAG_EXCLUDE_DOTS) &&
> -		    is_dots(dirent->name, dirent->name_len))
> +		} else if ((ctx->flags & OCFS2_DIRENT_FLAG_EXCLUDE_DOTS) &&
> +			   is_dots(dirent->name, dirent->name_len)) {
>  			goto next;
> +		}
>  
>  		ret = (ctx->func)(ctx->dir,
>  				  (next_real_entry > offset) ?
> diff --git a/libocfs2/dir_scan.c b/libocfs2/dir_scan.c
> index ad14120..6b15c06 100644
> --- a/libocfs2/dir_scan.c
> +++ b/libocfs2/dir_scan.c
> @@ -115,7 +115,9 @@ errcode_t ocfs2_get_next_dir_entry(ocfs2_dir_scan *scan,
>  			return OCFS2_ET_DIR_CORRUPTED;
>  
>  		scan->offset += dirent->rec_len;
> -	} while (!valid_dirent(scan, dirent));
> +	} while (!valid_dirent(scan, dirent) ||
> +		 ocfs2_skip_dir_trailer(scan->fs, scan->inode->ci_inode,
> +					dirent, scan->offset));
>  
>  	memcpy(out_dirent, dirent, sizeof(struct ocfs2_dir_entry));
>  
> diff --git a/libocfs2/dirblock.c b/libocfs2/dirblock.c
> index f116fb2..d1a9a45 100644
> --- a/libocfs2/dirblock.c
> +++ b/libocfs2/dirblock.c
> @@ -33,6 +33,61 @@
>  #include "ocfs2/byteorder.h"
>  #include "ocfs2/ocfs2.h"
>  
> +
> +unsigned int ocfs2_dir_trailer_blk_off(ocfs2_filesys *fs)
> +{
> +	return fs->fs_blocksize - sizeof(struct ocfs2_dir_block_trailer);
> +}
> +
> +struct ocfs2_dir_block_trailer *ocfs2_dir_trailer_from_block(ocfs2_filesys *fs,
> +							     void *data)
> +{
> +	char *p = data;
> +
> +	p += ocfs2_dir_trailer_blk_off(fs);
> +	return (struct ocfs2_dir_block_trailer *)p;
> +}
> +
> +int ocfs2_dir_has_trailer(ocfs2_filesys *fs, struct ocfs2_dinode *di)
> +{
> +	if (ocfs2_support_inline_data(OCFS2_RAW_SB(fs->fs_super)) &&
> +	    (di->i_dyn_features & OCFS2_INLINE_DATA_FL))
> +		return 0;
> +
> +	return 0;
> +}
> +
> +int ocfs2_supports_dir_trailer(ocfs2_filesys *fs)
> +{
> +	return 0;
> +}
> +
> +int ocfs2_skip_dir_trailer(ocfs2_filesys *fs, struct ocfs2_dinode *di,
> +			   struct ocfs2_dir_entry *de, unsigned long offset)
> +{
> +	if (!ocfs2_dir_has_trailer(fs, di))
> +		return 0;
> +
> +	if (offset != ocfs2_dir_trailer_blk_off(fs))
> +		return 0;
> +
> +	return 1;
> +}
> +
> +void ocfs2_init_dir_trailer(ocfs2_filesys *fs, struct ocfs2_dinode *di,
> +			    uint64_t blkno, void *buf)
> +{
> +	struct ocfs2_dir_block_trailer *trailer =
> +		ocfs2_dir_trailer_from_block(fs, buf);
> +
> +	memset(trailer, 0, sizeof(struct ocfs2_dir_block_trailer));
> +	memcpy(trailer->db_signature, OCFS2_DIR_TRAILER_SIGNATURE,
> +	       strlen(OCFS2_DIR_TRAILER_SIGNATURE));
> +	trailer->db_compat_rec_len = sizeof(struct ocfs2_dir_block_trailer);
> +	trailer->db_blkno = blkno;
> +	trailer->db_parent_dinode = di->i_blkno;
> +}
> +
>  static void ocfs2_swap_dir_entry(struct ocfs2_dir_entry *dirent)
>  {
>  	if (cpu_is_little_endian)
> @@ -84,16 +139,48 @@ errcode_t ocfs2_swap_dir_entries_to_cpu(void *buf, uint64_t bytes)
>  	return ocfs2_swap_dir_entries_direction(buf, bytes, 1);
>  }
>  
> +void ocfs2_swap_dir_trailer(struct ocfs2_dir_block_trailer *trailer)
> +{
> +	if (cpu_is_little_endian)
> +		return;
> +
> +	bswap_64(trailer->db_compat_inode);
> +	bswap_64(trailer->db_compat_rec_len);
> +	bswap_64(trailer->db_blkno);
> +	bswap_64(trailer->db_parent_dinode);
> +}
> +
>  errcode_t ocfs2_read_dir_block(ocfs2_filesys *fs, struct ocfs2_dinode *di,
>  			       uint64_t block, void *buf)
>  {
>  	errcode_t	retval;
> +	int		end = fs->fs_blocksize;
> +	struct ocfs2_dir_block_trailer *trailer = NULL;
>  
>  	retval = ocfs2_read_blocks(fs, block, 1, buf);
>  	if (retval)
> -		return retval;
> +		goto out;
> +
> +	if (ocfs2_dir_has_trailer(fs, di)) {
> +		end = ocfs2_dir_trailer_blk_off(fs);
> +		trailer = ocfs2_dir_trailer_from_block(fs, buf);
>  
> -	return ocfs2_swap_dir_entries_to_cpu(buf, fs->fs_blocksize);
> +		if (memcmp(trailer->db_signature, OCFS2_DIR_TRAILER_SIGNATURE,
> +			   strlen(OCFS2_DIR_TRAILER_SIGNATURE))) {
> +			retval = OCFS2_ET_BAD_DIR_BLOCK_MAGIC;
> +			goto out;
> +		}
> +	}
> +
> +	retval = ocfs2_swap_dir_entries_to_cpu(buf, end);
> +	if (!retval)
> +		goto out;
> +
> +	if (trailer)
> +		ocfs2_swap_dir_trailer(trailer);
> +
> +out:
> +	return retval;
>  }
>  
>  errcode_t ocfs2_write_dir_block(ocfs2_filesys *fs, struct ocfs2_dinode *di,
> @@ -101,6 +188,8 @@ errcode_t ocfs2_write_dir_block(ocfs2_filesys *fs, struct ocfs2_dinode *di,
>  {
>  	errcode_t	retval;
>  	char		*buf = NULL;
> +	int		end = fs->fs_blocksize;
> +	struct ocfs2_dir_block_trailer *trailer = NULL;
>  
>  	retval = ocfs2_malloc_block(fs->fs_io, &buf);
>  	if (retval)
> @@ -108,10 +197,21 @@ errcode_t ocfs2_write_dir_block(ocfs2_filesys *fs, struct ocfs2_dinode *di,
>  
>  	memcpy(buf, inbuf, fs->fs_blocksize);
>  
> -	retval = ocfs2_swap_dir_entries_from_cpu(buf, fs->fs_blocksize);
> +	if (ocfs2_dir_has_trailer(fs, di))
> +		end = ocfs2_dir_trailer_blk_off(fs);
> +
> +	retval = ocfs2_swap_dir_entries_from_cpu(buf, end);
>  	if (retval)
>  		goto out;
>  	
> +	/*
> +	 * We can always set trailer - Nothing happens if it isn't actually
> +	 * used.
> +	 */
> +	trailer = ocfs2_dir_trailer_from_block(fs, buf);
> +	if (ocfs2_dir_has_trailer(fs, di))
> +		ocfs2_swap_dir_trailer(trailer);
> +
>   	retval = io_write_block(fs->fs_io, block, 1, buf);
>  out:
>  	ocfs2_free(&buf);
> diff --git a/libocfs2/expanddir.c b/libocfs2/expanddir.c
> index fc7e055..6e9a192 100644
> --- a/libocfs2/expanddir.c
> +++ b/libocfs2/expanddir.c
> @@ -104,7 +104,11 @@ errcode_t ocfs2_expand_dir(ocfs2_filesys *fs,
>  
>  	memset(buf, 0, fs->fs_blocksize);
>  	de = (struct ocfs2_dir_entry *)buf;
> -	de->rec_len = fs->fs_blocksize;
> +	if (ocfs2_dir_has_trailer(fs, cinode->ci_inode)) {
> +		de->rec_len = ocfs2_dir_trailer_blk_off(fs);
> +		ocfs2_init_dir_trailer(fs, cinode->ci_inode, new_blk, buf);
> +	} else
> +		de->rec_len = fs->fs_blocksize;
>  
>  	/* write new dir block */
>  	ret = ocfs2_write_dir_block(fs, cinode->ci_inode, new_blk, buf);
> @@ -206,11 +210,18 @@ errcode_t ocfs2_init_dir(ocfs2_filesys *fs,
>  
>  		data = buf;
>  		size = fs->fs_blocksize;
> +		if (ocfs2_supports_dir_trailer(fs))
> +			size = ocfs2_dir_trailer_blk_off(fs);
>  	}
>  
>  	/* set '..' and '.' in dir. */
>  	ocfs2_fill_initial_dirents(dir, parent_dir, data, size);
>  
> +	/* And set the trailer if necessary */
> +	if (!(cinode->ci_inode->i_dyn_features & OCFS2_INLINE_DATA_FL) &&
> +	    ocfs2_supports_dir_trailer(fs))
> +		ocfs2_init_dir_trailer(fs, cinode->ci_inode, blkno, data);
> +
>  	if (!(cinode->ci_inode->i_dyn_features & OCFS2_INLINE_DATA_FL)) {
>  		ret = ocfs2_write_dir_block(fs, cinode->ci_inode, blkno, buf);
>  		if (ret)
> diff --git a/libocfs2/fileio.c b/libocfs2/fileio.c
> index 276a568..7c51e13 100644
> --- a/libocfs2/fileio.c
> +++ b/libocfs2/fileio.c
> @@ -496,6 +496,7 @@ errcode_t ocfs2_convert_inline_data_to_extents(ocfs2_cached_inode *ci)
>  	struct ocfs2_dinode *di = ci->ci_inode;
>  	ocfs2_filesys *fs = ci->ci_fs;
>  	uint64_t bpc = fs->fs_clustersize/fs->fs_blocksize;
> +	unsigned int new_size;
>  
>  	if (di->i_size) {
>  		ret = ocfs2_malloc_block(fs->fs_io, &inline_data);
> @@ -522,8 +523,15 @@ errcode_t ocfs2_convert_inline_data_to_extents(ocfs2_cached_inode *ci)
>  
>  	if (di->i_size) {
>  		if (S_ISDIR(di->i_mode)) {
> +			if (ocfs2_supports_dir_trailer(fs))
> +				new_size = ocfs2_dir_trailer_blk_off(fs);
> +			else
> +				new_size = fs->fs_blocksize;
>  			ocfs2_expand_last_dirent(inline_data, di->i_size,
> -						 fs->fs_blocksize);
> +						 new_size);
> +			if (ocfs2_supports_dir_trailer(fs))
> +				ocfs2_init_dir_trailer(fs, di, p_start,
> +						       inline_data);
>  
>  			di->i_size = fs->fs_blocksize;
>  			ret = ocfs2_write_dir_block(fs, di, p_start,
> diff --git a/libocfs2/link.c b/libocfs2/link.c
> index 4d63230..c89471d 100644
> --- a/libocfs2/link.c
> +++ b/libocfs2/link.c
> @@ -39,6 +39,10 @@ struct link_struct  {
>  	uint64_t		inode;
>  	int			flags;
>  	int			done;
> +	int			blockend;  /* What to consider the end
> +					      of the block.  This handles
> +					      the directory trailer if it
> +					      exists */
>  	struct ocfs2_dinode	*sb;
>  };	
>  
> @@ -60,9 +64,9 @@ static int link_proc(struct ocfs2_dir_entry *dirent,
>  	 * if so, absorb it into this one.
>  	 */
>  	next = (struct ocfs2_dir_entry *) (buf + offset + dirent->rec_len);
> -	if ((offset + dirent->rec_len < blocksize - 8) &&
> +	if ((offset + dirent->rec_len < ls->blockend - 8) &&
>  	    (next->inode == 0) &&
> -	    (offset + dirent->rec_len + next->rec_len <= blocksize)) {
> +	    (offset + dirent->rec_len + next->rec_len <= ls->blockend)) {
>  		dirent->rec_len += next->rec_len;
>  		ret = OCFS2_DIRENT_CHANGED;
>  	}
> @@ -70,7 +74,7 @@ static int link_proc(struct ocfs2_dir_entry *dirent,
>  	/*
>  	 * If the directory entry is used, see if we can split the
>  	 * directory entry to make room for the new name.  If so,
> -	 *e truncate it and return.
> +	 * truncate it and return.
>  	 */
>  	if (dirent->inode) {
>  		min_rec_len = OCFS2_DIR_REC_LEN(dirent->name_len & 0xFF);
> @@ -110,10 +114,8 @@ errcode_t ocfs2_link(ocfs2_filesys *fs, uint64_t dir, const char *name,
>  {
>  	errcode_t		retval;
>  	struct link_struct	ls;
> -#if 0 /* Maybe later */
> -        char *buf;
> -	struct ocfs2_dinode	inode;
> -#endif
> +	char			*buf;
> +	struct ocfs2_dinode	*di;
>  
>  	if (!(fs->fs_flags & OCFS2_FLAG_RW))
>  		return OCFS2_ET_RO_FILESYS;
> @@ -122,50 +124,57 @@ errcode_t ocfs2_link(ocfs2_filesys *fs, uint64_t dir, const char *name,
>  	    (ino > fs->fs_blocks))
>  		return OCFS2_ET_INVALID_ARGUMENT;
>  
> +        retval = ocfs2_malloc_block(fs->fs_io, &buf);
> +        if (retval)
> +            return retval;
> +
> +	retval = ocfs2_read_inode(fs, dir, buf);
> +	if (retval)
> +		goto out_free;
> +
> +        di = (struct ocfs2_dinode *)buf;
> +
>  	ls.name = name;
>  	ls.namelen = name ? strlen(name) : 0;
>  	ls.inode = ino;
>  	ls.flags = flags;
>  	ls.done = 0;
>  	ls.sb = fs->fs_super;
> +	if (ocfs2_dir_has_trailer(fs, di))
> +		ls.blockend = ocfs2_dir_trailer_blk_off(fs);
> +	else
> +		ls.blockend = fs->fs_blocksize;
>  
>  	retval = ocfs2_dir_iterate(fs, dir,
>                                     OCFS2_DIRENT_FLAG_INCLUDE_EMPTY,
>                                     NULL, link_proc, &ls);
>  	if (retval)
> -		return retval;
> +		goto out_free;
>  
>  	if (!ls.done) {
>  		retval = ocfs2_expand_dir(fs, dir);
>  		if (retval)
> -			return retval;
> +			goto out_free;
> +
> +		/* Gotta refresh */
> +		retval = ocfs2_read_inode(fs, dir, buf);
> +		if (retval)
> +			goto out_free;
>   

Unclear as to why we have to read the inode.

>  
> +		if (ocfs2_dir_has_trailer(fs, di))
> +			ls.blockend = ocfs2_dir_trailer_blk_off(fs);
> +		else
> +			ls.blockend = fs->fs_blocksize;
>  		retval = ocfs2_dir_iterate(fs, dir,
>  					   OCFS2_DIRENT_FLAG_INCLUDE_EMPTY,
>  					   NULL, link_proc, &ls);
> -		if (retval)
> -			return retval;
> -		if (!ls.done)
> -			return OCFS2_ET_INTERNAL_FAILURE;
> +		if (!retval && !ls.done)
> +			retval = OCFS2_ET_INTERNAL_FAILURE;
>  	}
>  
> -#if 0 /* Maybe later */
> -        retval = ocfs2_malloc_block(fs->fs_io, &buf);
> -        if (retval)
> -            return retval;
> -
> -	if ((retval = ocfs2_read_inode(fs, dir, buf)) != 0)
> -		return retval;
> -
> -        di = (ocfs2_dinode *)buf;
> -
> -	if (inode->i_flags & OCFS2_INDEX_FL) {
> -		inode->i_flags &= ~OCFS2_INDEX_FL;
> -		if ((retval = ocfs2_write_inode(fs, dir, buf)) != 0)
> -			return retval;
> -	}
> -#endif
> +out_free:
> +	ocfs2_free(&buf);
>  
> -	return 0;
> +	return retval;
>  }
>  
> diff --git a/libocfs2/ocfs2_err.et b/libocfs2/ocfs2_err.et
> index e278876..b169ec7 100644
> --- a/libocfs2/ocfs2_err.et
> +++ b/libocfs2/ocfs2_err.et
> @@ -178,4 +178,7 @@ ec	OCFS2_ET_CANNOT_INLINE_DATA,
>  ec	OCFS2_ET_UNKNOWN_FEATURE,
>  	"Unknown feature"
>  
> +ec	OCFS2_ET_BAD_DIR_BLOCK_MAGIC,
> +	"Bad magic number in directory block"
> +
>  	end
>   




More information about the Ocfs2-tools-devel mailing list