[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