[Ocfs2-tools-devel] [PATCH 03/12] libocfs2: Support directory block trailers.
Joel Becker
joel.becker at oracle.com
Mon Dec 29 19:23:39 PST 2008
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;
+ 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
--
1.5.6.5
More information about the Ocfs2-tools-devel
mailing list