[Ocfs2-tools-devel] [PATCH 3/7] libocfs2: Add extended slot map
support
Joel Becker
joel.becker at oracle.com
Thu Jan 3 15:47:25 PST 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>
---
libocfs2/feature_string.c | 5 +
libocfs2/include/ocfs2.h | 17 ++
libocfs2/ocfs2_err.et | 2 +-
libocfs2/slot_map.c | 422 +++++++++++++++++++++++++++++++++++++++------
4 files changed, 388 insertions(+), 58 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 21e9452..3074504 100644
--- a/libocfs2/include/ocfs2.h
+++ b/libocfs2/include/ocfs2.h
@@ -557,14 +557,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,
@@ -763,6 +772,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 8349c6a..daaf97e 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,
@@ -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,15 +40,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);
@@ -53,70 +74,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;
+ }
- *map_ret = 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 = 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);
@@ -126,18 +286,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;
@@ -147,25 +320,160 @@ 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);
- 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;
+ ocfs2_free(&slot_map_buf);
+
+ return ret;
+}
+
+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;
+ if (sf->needed_bytes == di->i_size) {
+ ret = 0;
+ goto out;
}
- ret = ocfs2_write_slot_map(fs, num_slots, sm);
- ocfs2_free(&sm);
+ clusters = sf->needed_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;
+ }
+
+ 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_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.2.2
More information about the Ocfs2-tools-devel
mailing list