[Ocfs2-tools-devel] [PATCH 3/6] libocfs2: Add extended slot map support

Joel Becker joel.becker at oracle.com
Thu Dec 6 21:18:08 PST 2007


Add the code for reading, writing, loading, and storing the extended
format.  Also introduce the ocfs2_format_slot_map() function.

The new format allows for larger node numbers (up to UINT32_MAX), more slots
(it is sized as a regular file), and has extra space for future updates.

Signed-of-by: Joel Becker <joel.becker at oracle.com>
---
 libocfs2/feature_string.c |    5 +
 libocfs2/include/ocfs2.h  |   15 ++
 libocfs2/ocfs2_err.et     |    2 +-
 libocfs2/slot_map.c       |  408 +++++++++++++++++++++++++++++++++++++++------
 4 files changed, 376 insertions(+), 54 deletions(-)

diff --git a/libocfs2/feature_string.c b/libocfs2/feature_string.c
index 40720b8..54674f3 100644
--- a/libocfs2/feature_string.c
+++ b/libocfs2/feature_string.c
@@ -73,6 +73,11 @@ static struct fs_feature_flags ocfs2_supported_features[] = {
 		 OCFS2_FEATURE_RO_COMPAT_UNWRITTEN},
 	},
 	{
+		"extended-slotmap",
+		{0, OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP, 0},
+		{0, OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP, 0},
+	},
+	{
 		NULL,
 		{0, 0, 0},
 		{0, 0, 0}
diff --git a/libocfs2/include/ocfs2.h b/libocfs2/include/ocfs2.h
index 8368f8b..8b24318 100644
--- a/libocfs2/include/ocfs2.h
+++ b/libocfs2/include/ocfs2.h
@@ -557,12 +557,19 @@ errcode_t ocfs2_meta_unlock(ocfs2_filesys *fs, ocfs2_cached_inode *ci);
 
 /* Low level */
 void ocfs2_swap_slot_map(struct ocfs2_slot_map *sm, int num_slots);
+void ocfs2_swap_slot_map_extended(struct ocfs2_slot_map_extended *se,
+				  int num_slots);
 errcode_t ocfs2_read_slot_map(ocfs2_filesys *fs,
 			      struct ocfs2_slot_map **map_ret);
+errcode_t ocfs2_read_slot_map_extended(ocfs2_filesys *fs,
+				       struct ocfs2_slot_map_extended **map_ret);
 errcode_t ocfs2_write_slot_map(ocfs2_filesys *fs,
 			       struct ocfs2_slot_map *sm);
+errcode_t ocfs2_write_slot_map_extended(ocfs2_filesys *fs,
+				       struct ocfs2_slot_map_extended *se);
 
 /* High level */
+errcode_t ocfs2_format_slot_map(ocfs2_filesys *fs);
 errcode_t ocfs2_load_slot_map(ocfs2_filesys *fs,
 			      struct ocfs2_slot_map_data **data_ret);
 errcode_t ocfs2_store_slot_map(ocfs2_filesys *fs,
@@ -761,6 +768,14 @@ static inline int ocfs2_writes_unwritten_extents(struct ocfs2_super_block *osb)
 	return 0;
 }
 
+static inline int ocfs2_uses_extended_slot_map(struct ocfs2_super_block *osb)
+{
+	if (osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP)
+		return 1;
+	return 0;
+}
+
+
 /*
  * shamelessly lifted from the kernel
  *
diff --git a/libocfs2/ocfs2_err.et b/libocfs2/ocfs2_err.et
index c29c925..5e46e13 100644
--- a/libocfs2/ocfs2_err.et
+++ b/libocfs2/ocfs2_err.et
@@ -34,7 +34,7 @@ ec	OCFS2_ET_SHORT_READ,
 	"Attempt to read block from filesystem resulted in short read"
 
 ec	OCFS2_ET_SHORT_WRITE,
-	"Attempt to read block from filesystem resulted in short write"
+	"Attempt to write block to the filesystem resulted in short write"
 
 ec	OCFS2_ET_NO_MEMORY,
 	"Memory allocation failed"
diff --git a/libocfs2/slot_map.c b/libocfs2/slot_map.c
index 8abfd4b..81fc0a5 100644
--- a/libocfs2/slot_map.c
+++ b/libocfs2/slot_map.c
@@ -23,6 +23,12 @@
 
 #include "ocfs2.h"
 
+/* Just so we can pass it about */
+union ocfs2_slot_map_wrapper {
+	struct ocfs2_slot_map *mw_map;
+	struct ocfs2_slot_map_extended *mw_map_extended;
+};
+
 void ocfs2_swap_slot_map(struct ocfs2_slot_map *sm, int num_slots)
 {
 	int i;
@@ -34,14 +40,29 @@ void ocfs2_swap_slot_map(struct ocfs2_slot_map *sm, int num_slots)
 		sm->sm_slots[i] = bswap_16(sm->sm_slots[i]);
 }
 
-errcode_t ocfs2_read_slot_map(ocfs2_filesys *fs,
-			      struct ocfs2_slot_map **map_ret)
+void ocfs2_swap_slot_map_extended(struct ocfs2_slot_map_extended *se,
+				  int num_slots)
+{
+	int i;
+
+	if (!cpu_is_big_endian)
+		return;
+
+	for (i = 0; i < num_slots; i++)
+		se->se_slots[i].es_node_num =
+			bswap_32(se->se_slots[i].es_node_num);
+}
+
+static errcode_t __ocfs2_read_slot_map(ocfs2_filesys *fs,
+				       union ocfs2_slot_map_wrapper *wrap)
 {
 	errcode_t ret;
 	uint64_t blkno;
 	char *slot_map_buf;
 	struct ocfs2_slot_map *sm;
-	int bytes_needed, len;
+	struct ocfs2_slot_map_extended *se;
+	int num_slots, bytes_needed, len;
+	int extended = ocfs2_uses_extended_slot_map(OCFS2_RAW_SB(fs->fs_super));
 
 	ret = ocfs2_lookup_system_inode(fs, SLOT_MAP_SYSTEM_INODE, 0,
 					&blkno);
@@ -52,69 +73,205 @@ errcode_t ocfs2_read_slot_map(ocfs2_filesys *fs,
 	if (ret)
 		return ret;
 
-	bytes_needed = ocfs2_blocks_in_bytes(fs, OCFS2_RAW_SB(fs->fs_super)->s_max_slots * sizeof(__le16));
+	num_slots = OCFS2_RAW_SB(fs->fs_super)->s_max_slots;
+	if (extended)
+		bytes_needed =
+			num_slots * sizeof(struct ocfs2_extended_slot);
+	else
+		bytes_needed = num_slots * sizeof(__le16);
+
 	if (bytes_needed > len) {
 		ocfs2_free(&slot_map_buf);
 		return OCFS2_ET_SHORT_READ;
 	}
 
-	sm = (struct ocfs2_slot_map *)slot_map_buf;
-	ocfs2_swap_slot_map(sm, OCFS2_RAW_SB(fs->fs_super)->s_max_slots);
+	if (extended) {
+		se = (struct ocfs2_slot_map_extended *)slot_map_buf;
+		ocfs2_swap_slot_map_extended(se, num_slots);
+		wrap->mw_map_extended = se;
+	} else {
+		sm = (struct ocfs2_slot_map *)slot_map_buf;
+		ocfs2_swap_slot_map(sm, num_slots);
+		wrap->mw_map = sm;
+	}
+
+	return 0;
+}
+
+errcode_t ocfs2_read_slot_map(ocfs2_filesys *fs,
+			      struct ocfs2_slot_map **map_ret)
+{
+	errcode_t ret;
+	union ocfs2_slot_map_wrapper wrap = {
+		.mw_map = NULL,
+	};
 
-	*map_ret = sm;
+	ret = __ocfs2_read_slot_map(fs, &wrap);
+	if (ret)
+		return ret;
 
+	*map_ret = wrap.mw_map;
 	return 0;
 }
 
-errcode_t ocfs2_write_slot_map(ocfs2_filesys *fs,
-			       struct ocfs2_slot_map *sm)
+errcode_t ocfs2_read_slot_map_extended(ocfs2_filesys *fs,
+				       struct ocfs2_slot_map_extended **map_ret)
+{
+	errcode_t ret;
+	union ocfs2_slot_map_wrapper wrap = {
+		.mw_map_extended = NULL,
+	};
+
+	ret = __ocfs2_read_slot_map(fs, &wrap);
+	if (ret)
+		return ret;
+
+	*map_ret = wrap.mw_map_extended;
+	return 0;
+}
+
+static errcode_t __ocfs2_write_slot_map(ocfs2_filesys *fs,
+					union ocfs2_slot_map_wrapper *wrap)
 {
 	errcode_t ret, tret;
-	ocfs2_cached_inode *ci;
-	uint64_t blkno, bytes;
-	uint32_t wrote;
+	ocfs2_cached_inode *ci = NULL;
+	uint64_t blkno;
+	unsigned int size, bytes, wrote, blocks;
+	void *buf = NULL;
 	int num_slots = OCFS2_RAW_SB(fs->fs_super)->s_max_slots;
+	int extended = ocfs2_uses_extended_slot_map(OCFS2_RAW_SB(fs->fs_super));
 
 	ret = ocfs2_lookup_system_inode(fs, SLOT_MAP_SYSTEM_INODE, 0,
 					&blkno);
 	if (ret)
-		return ret;
-
-	ret = ocfs2_read_cached_inode(fs, blkno, &ci);
-	if (ret)
-		return ret;
+		goto out;
 
-	bytes = (uint64_t)num_slots * sizeof(__le16);
+	if (extended)
+		size = num_slots * sizeof(struct ocfs2_extended_slot);
+	else
+		size = num_slots * sizeof(__le16);
 
-	ocfs2_swap_slot_map(sm, num_slots);
+	blocks = ocfs2_blocks_in_bytes(fs, size);
+	bytes = blocks << OCFS2_RAW_SB(fs->fs_super)->s_blocksize_bits;
+	ret = ocfs2_malloc_blocks(fs->fs_io, blocks, &buf);
+	if (ret)
+		goto out;
+	memset(buf, 0, bytes);
+
+	if (extended) {
+		memcpy(buf, wrap->mw_map_extended, size);
+		ocfs2_swap_slot_map_extended(buf, num_slots);
+	} else {
+		memcpy(buf, wrap->mw_map, size);
+		ocfs2_swap_slot_map(buf, num_slots);
+	}
 
-	ret = ocfs2_file_write(ci, sm, bytes, 0, &wrote);
-	tret = ocfs2_free_cached_inode(fs, ci);
+	ret = ocfs2_read_cached_inode(fs, blkno, &ci);
 	if (ret)
-		return ret;
-	if (wrote != bytes)
-		return OCFS2_ET_SHORT_WRITE;
+		goto out;
 
+	ret = ocfs2_file_write(ci, buf, bytes, 0, &wrote);
+	if (ret)
+		goto out;
 	/*
-	 * The error from free_cached_inode() is only important if
-	 * there were no other problems.
+	 * This is wacky.  We have to write a block (bytes), but &wrote
+	 * might return only i_size (size).  Handle both.
 	 */
-	if (tret)
-		return tret;
+	if ((wrote != bytes) && (wrote != size))
+		ret = OCFS2_ET_SHORT_WRITE;
+
+out:
+	if (ci) {
+		tret = ocfs2_free_cached_inode(fs, ci);
+		/*
+		 * The error from free_cached_inode() is only important if
+		 * there were no other problems.
+		 */
+		if (!ret)
+			ret = tret;
+	}
+	if (buf)
+		ocfs2_free(&buf);
+	return ret;
+}
 
-	return 0;
+errcode_t ocfs2_write_slot_map(ocfs2_filesys *fs,
+			       struct ocfs2_slot_map *sm)
+{
+	union ocfs2_slot_map_wrapper wrap = {
+		.mw_map = sm,
+	};
+
+	return __ocfs2_write_slot_map(fs, &wrap);
 }
 
-errcode_t ocfs2_load_slot_map(ocfs2_filesys *fs,
-			      struct ocfs2_slot_map_data **data_ret)
+errcode_t ocfs2_write_slot_map_extended(ocfs2_filesys *fs,
+				       struct ocfs2_slot_map_extended *se)
+{
+	union ocfs2_slot_map_wrapper wrap = {
+		.mw_map_extended = se,
+	};
+
+	return __ocfs2_write_slot_map(fs, &wrap);
+}
+
+static void ocfs2_slot_map_to_data(ocfs2_filesys *fs,
+				   struct ocfs2_slot_map_data *md,
+				   union ocfs2_slot_map_wrapper *wrap)
+{
+	int i;
+	struct ocfs2_slot_map *sm = wrap->mw_map;
+	struct ocfs2_slot_map_extended *se = wrap->mw_map_extended;
+	int extended = ocfs2_uses_extended_slot_map(OCFS2_RAW_SB(fs->fs_super));
+
+	for (i = 0; i < md->md_num_slots; i++) {
+		if (extended) {
+			if (se->se_slots[i].es_valid) {
+				md->md_slots[i].sd_valid = 1;
+				md->md_slots[i].sd_node_num = se->se_slots[i].es_node_num;
+			} else
+				md->md_slots[i].sd_valid = 0;
+		} else {
+			if (sm->sm_slots[i] != (uint16_t)OCFS2_INVALID_SLOT) {
+				md->md_slots[i].sd_valid = 1;
+				md->md_slots[i].sd_node_num = sm->sm_slots[i];
+			} else
+				md->md_slots[i].sd_valid = 0;
+		}
+	}
+}
+
+static void ocfs2_slot_data_to_map(ocfs2_filesys *fs,
+				   struct ocfs2_slot_map_data *md,
+				   union ocfs2_slot_map_wrapper *wrap)
+{
+	int i;
+	struct ocfs2_slot_map *sm = wrap->mw_map;
+	struct ocfs2_slot_map_extended *se = wrap->mw_map_extended;
+	int extended = ocfs2_uses_extended_slot_map(OCFS2_RAW_SB(fs->fs_super));
+
+	for (i = 0; i < md->md_num_slots; i++) {
+		if (extended) {
+			if (md->md_slots[i].sd_valid) {
+				se->se_slots[i].es_valid = 1;
+				se->se_slots[i].es_node_num = md->md_slots[i].sd_node_num;
+			} else
+				se->se_slots[i].es_valid = 0;
+		} else {
+			if (md->md_slots[i].sd_valid)
+				sm->sm_slots[i] = (uint16_t)md->md_slots[i].sd_node_num;
+			else
+				sm->sm_slots[i] = (uint16_t)OCFS2_INVALID_SLOT;
+		}
+	}
+}
+
+static errcode_t ocfs2_alloc_slot_map_data(int num_slots,
+					   struct ocfs2_slot_map_data **md_ret)
 {
 	errcode_t ret;
-	int i, num_slots;
-	struct ocfs2_slot_map *sm;
 	struct ocfs2_slot_map_data *md;
 
-	num_slots = OCFS2_RAW_SB(fs->fs_super)->s_max_slots;
-
 	ret = ocfs2_malloc0(sizeof(struct ocfs2_slot_map_data) +
 			    (sizeof(struct ocfs2_slot_data) * num_slots),
 			    &md);
@@ -124,18 +281,32 @@ errcode_t ocfs2_load_slot_map(ocfs2_filesys *fs,
 	md->md_num_slots = num_slots;
 	md->md_slots = (struct ocfs2_slot_data *)((char *)md + sizeof(struct ocfs2_slot_map_data));
 
-	ret = ocfs2_read_slot_map(fs, &sm);
+	*md_ret = md;
+	return 0;
+}
+
+errcode_t ocfs2_load_slot_map(ocfs2_filesys *fs,
+			      struct ocfs2_slot_map_data **data_ret)
+{
+	errcode_t ret;
+	int num_slots;
+	struct ocfs2_slot_map_data *md;
+	union ocfs2_slot_map_wrapper wrap = {
+		.mw_map = NULL,
+	};
+
+	num_slots = OCFS2_RAW_SB(fs->fs_super)->s_max_slots;
+	ret = ocfs2_alloc_slot_map_data(num_slots, &md);
+	if (ret)
+		return ret;
+
+	ret = __ocfs2_read_slot_map(fs, &wrap);
 	if (ret) {
 		ocfs2_free(&md);
 		return ret;
 	}
 
-	for (i = 0; i < num_slots; i++) {
-		if (sm->sm_slots[i] != (uint16_t)OCFS2_INVALID_SLOT) {
-			md->md_slots[i].sd_valid = 1;
-			md->md_slots[i].sd_node_num = sm->sm_slots[i];
-		}
-	}
+	ocfs2_slot_map_to_data(fs, md, &wrap);
 
 	*data_ret = md;
 	return 0;
@@ -145,25 +316,156 @@ errcode_t ocfs2_store_slot_map(ocfs2_filesys *fs,
 			       struct ocfs2_slot_map_data *md)
 {
 	errcode_t ret;
-	struct ocfs2_slot_map *sm;
-	int i, num_slots, bytes;
+	char *slot_map_buf;
+	int num_slots, bytes;
+	int extended = ocfs2_uses_extended_slot_map(OCFS2_RAW_SB(fs->fs_super));
+	union ocfs2_slot_map_wrapper wrap;
 
 	num_slots = OCFS2_RAW_SB(fs->fs_super)->s_max_slots;
-	bytes = num_slots * sizeof(__le16);
+	if (extended)
+		bytes = num_slots * sizeof(struct ocfs2_extended_slot);
+	else
+		bytes = num_slots * sizeof(__le16);
 
-	ret = ocfs2_malloc0(bytes, &sm);
+	ret = ocfs2_malloc0(bytes, &slot_map_buf);
 	if (ret)
 		return ret;
+	wrap.mw_map = (struct ocfs2_slot_map *)slot_map_buf;
+
+	ocfs2_slot_data_to_map(fs, md, &wrap);
+	ret = __ocfs2_write_slot_map(fs, &wrap);
+
+	ocfs2_free(&slot_map_buf);
+
+	return ret;
+}
+
+struct slotmap_format {
+	int extended;
+	int num_slots;
+	unsigned int bytes;
+	ocfs2_cached_inode *ci;
+};
 
-	for (i = 0; i < num_slots; i++) {
-		if (md->md_slots[i].sd_valid)
-			sm->sm_slots[i] = md->md_slots[i].sd_node_num;
-		else
-			sm->sm_slots[i] = OCFS2_INVALID_SLOT;
+static errcode_t ocfs2_size_slot_map(ocfs2_filesys *fs,
+				     struct slotmap_format *sf)
+{
+	errcode_t ret ;
+	struct ocfs2_dinode *di;
+	unsigned int clusters;
+	uint64_t new_size;
+
+	di = sf->ci->ci_inode;
+	if (sf->bytes == di->i_size) {
+		ret = 0;
+		goto out;
+	}
+
+	clusters = sf->bytes + fs->fs_clustersize - 1;
+	clusters = clusters >> OCFS2_RAW_SB(fs->fs_super)->s_clustersize_bits;
+	if (!clusters) {
+		ret = OCFS2_ET_INTERNAL_FAILURE;
+		goto out;
 	}
 
-	ret = ocfs2_write_slot_map(fs, sm);
-	ocfs2_free(&sm);
+	if (clusters > di->i_clusters) {
+		ret = ocfs2_extend_allocation(fs, sf->ci->ci_blkno,
+					      (clusters - di->i_clusters));
+		if (ret)
+			goto out;
+
+		/* We don't cache in the library right now, so any
+		 * work done in extend_allocation won't be reflected
+		 * in our now stale copy. */
+		ocfs2_free_cached_inode(fs, sf->ci);
+		ret = ocfs2_read_cached_inode(fs, sf->ci->ci_blkno,
+					      &sf->ci);
+		if (ret) {
+			sf->ci = NULL;
+			goto out;
+		}
+		di = sf->ci->ci_inode;
+	} else if (clusters < di->i_clusters) {
+		new_size = clusters <<
+				OCFS2_RAW_SB(fs->fs_super)->s_clustersize_bits;
+		ret = ocfs2_truncate(fs, sf->ci->ci_blkno, new_size);
+		if (ret)
+			goto out;
+
+		ocfs2_free_cached_inode(fs, sf->ci);
+		ret = ocfs2_read_cached_inode(fs, sf->ci->ci_blkno,
+					      &sf->ci);
+		if (ret) {
+			sf->ci = NULL;
+			goto out;
+		}
+		di = sf->ci->ci_inode;
+	}
+
+	/*
+	 * Now that we've adjusted the allocation, write out the
+	 * correct i_size.
+	 */
+	if (sf->extended)
+		di->i_size = sf->bytes;
+	else
+		di->i_size = di->i_clusters <<
+			OCFS2_RAW_SB(fs->fs_super)->s_clustersize_bits;
+	di->i_mtime = time(NULL);
+
+	ret = ocfs2_write_inode(fs, sf->ci->ci_blkno, (char *)di);
+	if (ret)
+		goto out;
+
+out:
+	return ret;
+}
+
+errcode_t ocfs2_format_slot_map(ocfs2_filesys *fs)
+{
+	errcode_t ret;
+	uint64_t blkno;
+	struct slotmap_format sf;
+	struct ocfs2_slot_map_data *md = NULL;
 
+	ret = ocfs2_lookup_system_inode(fs, SLOT_MAP_SYSTEM_INODE, 0,
+					&blkno);
+	if (ret)
+		goto out;
+
+	ret = ocfs2_read_cached_inode(fs, blkno, &sf.ci);
+	if (ret)
+		goto out;
+
+	/* verify it is a system file */
+	if (!(sf.ci->ci_inode->i_flags & OCFS2_VALID_FL) ||
+	    !(sf.ci->ci_inode->i_flags & OCFS2_SYSTEM_FL)) {
+		ret = OCFS2_ET_INTERNAL_FAILURE;
+		goto out;
+	}
+
+	sf.extended = ocfs2_uses_extended_slot_map(OCFS2_RAW_SB(fs->fs_super));
+	sf.num_slots = OCFS2_RAW_SB(fs->fs_super)->s_max_slots;
+	if (sf.extended)
+		sf.bytes = sf.num_slots * sizeof(struct ocfs2_extended_slot);
+	else
+		sf.bytes = sf.num_slots * sizeof(__le16);
+
+	ret = ocfs2_size_slot_map(fs, &sf);
+	if (ret)
+		goto out;
+
+	/* This returns an empty map */
+	ret = ocfs2_alloc_slot_map_data(sf.num_slots, &md);
+	if (ret)
+		return ret;
+
+	ret = ocfs2_store_slot_map(fs, md);
+
+out:
+	if (sf.ci)
+		ocfs2_free_cached_inode(fs, sf.ci);
+	if (md)
+		ocfs2_free(&md);
 	return ret;
 }
-- 
1.5.2.2




More information about the Ocfs2-tools-devel mailing list