[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