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

Joel Becker joel.becker at oracle.com
Fri Mar 14 16:38:48 PDT 2008


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>
---
 include/ocfs2/ocfs2.h     |   17 ++
 libocfs2/feature_string.c |    5 +
 libocfs2/ocfs2_err.et     |    5 +-
 libocfs2/slot_map.c       |  434 +++++++++++++++++++++++++++++++++++++++------
 4 files changed, 403 insertions(+), 58 deletions(-)

diff --git a/include/ocfs2/ocfs2.h b/include/ocfs2/ocfs2.h
index 8a7f585..981a69d 100644
--- a/include/ocfs2/ocfs2.h
+++ b/include/ocfs2/ocfs2.h
@@ -540,14 +540,23 @@ 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,
 			      int num_slots,
 			      struct ocfs2_slot_map **map_ret);
+errcode_t ocfs2_read_slot_map_extended(ocfs2_filesys *fs,
+				       int num_slots,
+				       struct ocfs2_slot_map_extended **map_ret);
 errcode_t ocfs2_write_slot_map(ocfs2_filesys *fs,
 			       int num_slots,
 			       struct ocfs2_slot_map *sm);
+errcode_t ocfs2_write_slot_map_extended(ocfs2_filesys *fs,
+					int num_slots,
+					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,
@@ -746,6 +755,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/feature_string.c b/libocfs2/feature_string.c
index 831edc1..845ace0 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/ocfs2_err.et b/libocfs2/ocfs2_err.et
index 3742976..35dee5a 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"
@@ -165,4 +165,7 @@ ec	OCFS2_ET_NO_IONICE,
 ec	OCFS2_ET_NO_BACKUP_SUPER,
 	"Backup superblock not found"
 
+ec      OCFS2_ET_TOO_MANY_SLOTS,
+        "Too many slots for slot map"
+
 	end
diff --git a/libocfs2/slot_map.c b/libocfs2/slot_map.c
index 397a7d0..944ccc3 100644
--- a/libocfs2/slot_map.c
+++ b/libocfs2/slot_map.c
@@ -6,12 +6,12 @@
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public
  * License, version 2,  as published by the Free Software Foundation.
- * 
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public
  * License along with this program; if not, write to the
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
@@ -24,6 +24,12 @@
 #include "ocfs2/byteorder.h"
 #include "ocfs2/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;
@@ -35,15 +41,30 @@ 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,
-			      int num_slots,
-			      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,
+				       int num_slots,
+				       union ocfs2_slot_map_wrapper *wrap)
 {
 	errcode_t ret;
 	uint64_t blkno;
 	char *slot_map_buf;
 	struct ocfs2_slot_map *sm;
+	struct ocfs2_slot_map_extended *se;
 	int 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);
@@ -54,70 +75,209 @@ errcode_t ocfs2_read_slot_map(ocfs2_filesys *fs,
 	if (ret)
 		return ret;
 
-	bytes_needed = ocfs2_blocks_in_bytes(fs,
-					     num_slots * sizeof(__le16));
+	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, num_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,
+			      int num_slots,
+			      struct ocfs2_slot_map **map_ret)
+{
+	errcode_t ret;
+	union ocfs2_slot_map_wrapper wrap = {
+		.mw_map = NULL,
+	};
+
+	ret = __ocfs2_read_slot_map(fs, num_slots, &wrap);
+	if (ret)
+		return ret;
 
-	*map_ret = sm;
+	*map_ret = wrap.mw_map;
+ 	return 0;
+}
+
+errcode_t ocfs2_read_slot_map_extended(ocfs2_filesys *fs,
+				       int num_slots,
+				       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, num_slots, &wrap);
+	if (ret)
+		return ret;
 
+	*map_ret = wrap.mw_map_extended;
 	return 0;
 }
 
-errcode_t ocfs2_write_slot_map(ocfs2_filesys *fs,
-			       int num_slots,
-			       struct ocfs2_slot_map *sm)
+static errcode_t __ocfs2_write_slot_map(ocfs2_filesys *fs,
+					int num_slots,
+					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 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;
+		goto out;
 
-	ret = ocfs2_read_cached_inode(fs, blkno, &ci);
-	if (ret)
-		return ret;
+	if (extended)
+		size = num_slots * sizeof(struct ocfs2_extended_slot);
+	else
+		size = num_slots * sizeof(__le16);
 
-	bytes = (uint64_t)num_slots * sizeof(__le16);
+	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);
+	}
 
-	ocfs2_swap_slot_map(sm, num_slots);
+	ret = ocfs2_read_cached_inode(fs, blkno, &ci);
+	if (ret)
+		goto out;
 
-	ret = ocfs2_file_write(ci, sm, bytes, 0, &wrote);
-	tret = ocfs2_free_cached_inode(fs, ci);
+	ret = ocfs2_file_write(ci, buf, bytes, 0, &wrote);
 	if (ret)
-		return ret;
-	if (wrote != bytes)
-		return OCFS2_ET_SHORT_WRITE;
+		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,
+			       int num_slots,
+			       struct ocfs2_slot_map *sm)
+{
+	union ocfs2_slot_map_wrapper wrap = {
+		.mw_map = sm,
+	};
+
+	return __ocfs2_write_slot_map(fs, num_slots, &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,
+					int num_slots,
+					struct ocfs2_slot_map_extended *se)
+{
+	union ocfs2_slot_map_wrapper wrap = {
+		.mw_map_extended = se,
+	};
+
+	return __ocfs2_write_slot_map(fs, num_slots, &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);
@@ -127,18 +287,31 @@ 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, num_slots, &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 = OCFS2_RAW_SB(fs->fs_super)->s_max_slots;;
+	struct ocfs2_slot_map_data *md;
+	union ocfs2_slot_map_wrapper wrap = {
+		.mw_map = NULL,
+	};
+
+	ret = ocfs2_alloc_slot_map_data(num_slots, &md);
+	if (ret)
+		return ret;
+
+	ret = __ocfs2_read_slot_map(fs, num_slots, &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;
@@ -148,25 +321,172 @@ 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 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 = md->md_num_slots * sizeof(struct ocfs2_extended_slot);
+	else
+		bytes = md->md_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, md->md_num_slots, &wrap);
+
+	ocfs2_free(&slot_map_buf);
+
+	return ret;
+}
 
-	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;
+struct slotmap_format {
+	int extended;
+	int needed_slots;
+	int actual_slots;
+	unsigned int needed_bytes;
+	ocfs2_cached_inode *ci;
+};
+
+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;
+
+	clusters = sf->needed_bytes + fs->fs_clustersize - 1;
+	clusters = clusters >> OCFS2_RAW_SB(fs->fs_super)->s_clustersize_bits;
+	/* Zero slots not allowed - even local mounts have a slot */
+	if (!clusters) {
+		ret = OCFS2_ET_INTERNAL_FAILURE;
+		goto out;
+	}
+
+	/*
+	 * We ensure that slotmaps are formatted to the end of the
+	 * allocation.  If the allocation hasn't changed, we don't have
+	 * anything to do.
+	 */
+	if (clusters == di->i_clusters) {
+		ret = 0;
+		goto out;
 	}
 
-	ret = ocfs2_write_slot_map(fs, num_slots, 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.  By design, the slot map's i_size encompasses
+	 * the full allocation.
+	 */
+	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.needed_slots = OCFS2_RAW_SB(fs->fs_super)->s_max_slots;
+	if (!sf.extended && (sf.needed_slots > OCFS2_MAX_SLOTS)) {
+		ret = OCFS2_ET_TOO_MANY_SLOTS;
+		goto out;
+	}
+
+	if (sf.extended)
+		sf.needed_bytes = sf.needed_slots * sizeof(struct ocfs2_extended_slot);
+	else
+		sf.needed_bytes = sf.needed_slots * sizeof(__le16);
+
+	ret = ocfs2_size_slot_map(fs, &sf);
+	if (ret)
+		goto out;
+
+	if (sf.extended)
+		sf.actual_slots = sf.ci->ci_inode->i_size / sizeof(struct ocfs2_extended_slot);
+	else
+		sf.actual_slots = sf.ci->ci_inode->i_size / sizeof(__le16);
+
+	/* This returns an empty map that covers the entire allocation */
+	ret = ocfs2_alloc_slot_map_data(sf.actual_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.3.8




More information about the Ocfs2-tools-devel mailing list