[Ocfs2-tools-devel] [PATCH 3/7] libocfs2: Add extended slot map
support
Sunil Mushran
Sunil.Mushran at oracle.com
Fri Jan 11 15:31:03 PST 2008
Why are we exposing ocfs2_read_slot_map_extended() and its
write equivalent?
Joel Becker wrote:
> 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;
> }
>
More information about the Ocfs2-tools-devel
mailing list