text: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
   * Copyright by The HDF Group.                                               *
   * Copyright by the Board of Trustees of the University of Illinois.         *
   * All rights reserved.                                                      *
   *                                                                           *
   * This file is part of HDF5.  The full HDF5 copyright notice, including     *
   * terms governing use, modification, and redistribution, is contained in    *
   * the COPYING file, which can be found at the root of the source code       *
   * distribution tree, or in https://www.hdfgroup.org/licenses.               *
   * If you do not have access to either file, you may request a copy from     *
   * help@hdfgroup.org.                                                        *
   * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  
  /*-------------------------------------------------------------------------
   *
   * Created:             H5MF.c
   *                      Jul 11 1997
   *                      Robb Matzke
   *
   * Purpose:             File memory management functions.
   *
   *-------------------------------------------------------------------------
   */
  
  /****************/
  /* Module Setup */
  /****************/
  
  #define H5F_FRIEND      /*suppress error about including H5Fpkg	  */
  #define H5FS_FRIEND     /*suppress error about including H5Fpkg	  */
  #include "H5MFmodule.h" /* This source code file is part of the H5MF module */
  
  /***********/
  /* Headers */
  /***********/
  #include "H5private.h"   /* Generic Functions			*/
  #include "H5Eprivate.h"  /* Error handling		  	*/
  #include "H5Fpkg.h"      /* File access				*/
  #include "H5FSpkg.h"     /* File free space                      */
  #include "H5Iprivate.h"  /* IDs			  		*/
  #include "H5MFpkg.h"     /* File memory management		*/
  #include "H5VMprivate.h" /* Vectors and arrays 			*/
  
  /****************/
  /* Local Macros */
  /****************/
  
  #define H5MF_FSPACE_SHRINK 80  /* Percent of "normal" size to shrink serialized free space size */
  #define H5MF_FSPACE_EXPAND 120 /* Percent of "normal" size to expand serialized free space size */
  
  #define H5MF_CHECK_FSM(FSM, CF)                                                                              \
      do {                                                                                                     \
          HDassert(*CF == FALSE);                                                                              \
          if (!H5F_addr_defined(FSM->addr) || !H5F_addr_defined(FSM->sect_addr))                               \
              *CF = TRUE;                                                                                      \
      } while (0)
  
  /* For non-paged aggregation: map allocation request type to tracked free-space type */
  /* F_SH -- pointer to H5F_shared_t; T -- H5FD_mem_t */
  #define H5MF_ALLOC_TO_FS_AGGR_TYPE(F_SH, T)                                                                  \
      ((H5FD_MEM_DEFAULT == (F_SH)->fs_type_map[T]) ? (T) : (F_SH)->fs_type_map[T])
  
  /******************/
  /* Local Typedefs */
  /******************/
  
  /* Enum for kind of free space section+aggregator merging allowed for a file */
  typedef enum {
      H5MF_AGGR_MERGE_SEPARATE,  /* Everything in separate free list */
      H5MF_AGGR_MERGE_DICHOTOMY, /* Metadata in one free list and raw data in another */
      H5MF_AGGR_MERGE_TOGETHER   /* Metadata & raw data in one free list */
  } H5MF_aggr_merge_t;
  
  /* User data for section info iterator callback for iterating over free space sections */
  typedef struct {
      H5F_sect_info_t *sects;      /* section info to be retrieved */
      size_t           sect_count; /* # of sections requested */
      size_t           sect_idx;   /* the current count of sections */
  } H5MF_sect_iter_ud_t;
  
  /********************/
  /* Package Typedefs */
  /********************/
  
  /********************/
  /* Local Prototypes */
  /********************/
  
  /* Allocator routines */
  static haddr_t H5MF__alloc_pagefs(H5F_t *f, H5FD_mem_t alloc_type, hsize_t size);
  
  /* "File closing" routines */
  static herr_t H5MF__close_aggrfs(H5F_t *f);
  static herr_t H5MF__close_pagefs(H5F_t *f);
  static herr_t H5MF__close_shrink_eoa(H5F_t *f);
  
  /* General routines */
  static herr_t  H5MF__get_free_sects(H5F_t *f, H5FS_t *fspace, H5MF_sect_iter_ud_t *sect_udata, size_t *nums);
  static hbool_t H5MF__fsm_type_is_self_referential(H5F_shared_t *f_sh, H5F_mem_page_t fsm_type);
  static hbool_t H5MF__fsm_is_self_referential(H5F_shared_t *f_sh, H5FS_t *fspace);
  static herr_t  H5MF__continue_alloc_fsm(H5F_shared_t *f_sh, H5FS_t *sm_hdr_fspace, H5FS_t *sm_sinfo_fspace,
                                          H5FS_t *lg_hdr_fspace, H5FS_t *lg_sinfo_fspace,
                                          hbool_t *continue_alloc_fsm);
  
  /* Free-space type manager routines */
  static herr_t H5MF__create_fstype(H5F_t *f, H5F_mem_page_t type);
  static herr_t H5MF__close_fstype(H5F_t *f, H5F_mem_page_t type);
  static herr_t H5MF__delete_fstype(H5F_t *f, H5F_mem_page_t type);
  static herr_t H5MF__close_delete_fstype(H5F_t *f, H5F_mem_page_t type);
  
  /* Callbacks */
  static herr_t H5MF__sects_cb(H5FS_section_info_t *_sect, void *_udata);
  
  /*********************/
  /* Package Variables */
  /*********************/
  
  /* Package initialization variable */
  hbool_t H5_PKG_INIT_VAR = FALSE;
  
  /*****************************/
  /* Library Private Variables */
  /*****************************/
  
  /*******************/
  /* Local Variables */
  /*******************/
  
  /*-------------------------------------------------------------------------
   * Function:    H5MF_init_merge_flags
   *
   * Purpose:     Initialize the free space section+aggregator merge flags
   *              for the file.
   *
   * Return:	SUCCEED/FAIL
   *
   * Programmer:  Quincey Koziol
   *              Friday, February  1, 2008
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5MF_init_merge_flags(H5F_shared_t *f_sh)
  {
      H5MF_aggr_merge_t mapping_type;        /* Type of free list mapping */
      H5FD_mem_t        type;                /* Memory type for iteration */
      hbool_t           all_same;            /* Whether all the types map to the same value */
      herr_t            ret_value = SUCCEED; /* Return value */
  
      FUNC_ENTER_NOAPI(FAIL)
  
      /* check args */
      HDassert(f_sh);
      HDassert(f_sh->lf);
  
      /* Iterate over all the free space types to determine if sections of that type
       *  can merge with the metadata or small 'raw' data aggregator
       */
      all_same = TRUE;
      for (type = H5FD_MEM_DEFAULT; type < H5FD_MEM_NTYPES; type++)
          /* Check for any different type mappings */
          if (f_sh->fs_type_map[type] != f_sh->fs_type_map[H5FD_MEM_DEFAULT]) {
              all_same = FALSE;
              break;
          } /* end if */
  
      /* Check for all allocation types mapping to the same free list type */
      if (all_same) {
          if (f_sh->fs_type_map[H5FD_MEM_DEFAULT] == H5FD_MEM_DEFAULT)
              mapping_type = H5MF_AGGR_MERGE_SEPARATE;
          else
              mapping_type = H5MF_AGGR_MERGE_TOGETHER;
      } /* end if */
      else {
          /* Check for raw data mapping into same list as metadata */
          if (f_sh->fs_type_map[H5FD_MEM_DRAW] == f_sh->fs_type_map[H5FD_MEM_SUPER])
              mapping_type = H5MF_AGGR_MERGE_SEPARATE;
          else {
              hbool_t all_metadata_same; /* Whether all metadata go in same free list */
  
              /* One or more allocation type don't map to the same free list type */
              /* Check if all the metadata allocation types map to the same type */
              all_metadata_same = TRUE;
              for (type = H5FD_MEM_SUPER; type < H5FD_MEM_NTYPES; type++)
                  /* Skip checking raw data free list mapping */
                  /* (global heap is treated as raw data) */
                  if (type != H5FD_MEM_DRAW && type != H5FD_MEM_GHEAP) {
                      /* Check for any different type mappings */
                      if (f_sh->fs_type_map[type] != f_sh->fs_type_map[H5FD_MEM_SUPER]) {
                          all_metadata_same = FALSE;
                          break;
                      } /* end if */
                  }     /* end if */
  
              /* Check for all metadata on same free list */
              if (all_metadata_same)
                  mapping_type = H5MF_AGGR_MERGE_DICHOTOMY;
              else
                  mapping_type = H5MF_AGGR_MERGE_SEPARATE;
          } /* end else */
      }     /* end else */
  
      /* Based on mapping type, initialize merging flags for each free list type */
      switch (mapping_type) {
          case H5MF_AGGR_MERGE_SEPARATE:
              /* Don't merge any metadata together */
              HDmemset(f_sh->fs_aggr_merge, 0, sizeof(f_sh->fs_aggr_merge));
  
              /* Check if merging raw data should be allowed */
              /* (treat global heaps as raw data) */
              if (H5FD_MEM_DRAW == f_sh->fs_type_map[H5FD_MEM_DRAW] ||
                  H5FD_MEM_DEFAULT == f_sh->fs_type_map[H5FD_MEM_DRAW]) {
                  f_sh->fs_aggr_merge[H5FD_MEM_DRAW]  = H5F_FS_MERGE_RAWDATA;
                  f_sh->fs_aggr_merge[H5FD_MEM_GHEAP] = H5F_FS_MERGE_RAWDATA;
              } /* end if */
              break;
  
          case H5MF_AGGR_MERGE_DICHOTOMY:
              /* Merge all metadata together (but not raw data) */
              HDmemset(f_sh->fs_aggr_merge, H5F_FS_MERGE_METADATA, sizeof(f_sh->fs_aggr_merge));
  
              /* Allow merging raw data allocations together */
              /* (treat global heaps as raw data) */
              f_sh->fs_aggr_merge[H5FD_MEM_DRAW]  = H5F_FS_MERGE_RAWDATA;
              f_sh->fs_aggr_merge[H5FD_MEM_GHEAP] = H5F_FS_MERGE_RAWDATA;
              break;
  
          case H5MF_AGGR_MERGE_TOGETHER:
              /* Merge all allocation types together */
              HDmemset(f_sh->fs_aggr_merge, (H5F_FS_MERGE_METADATA | H5F_FS_MERGE_RAWDATA),
                       sizeof(f_sh->fs_aggr_merge));
              break;
  
          default:
              HGOTO_ERROR(H5E_RESOURCE, H5E_BADVALUE, FAIL, "invalid mapping type")
      } /* end switch */
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5MF_init_merge_flags() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5MF__alloc_to_fs_type
   *
   * Purpose:     Map "alloc_type" to the free-space manager type
   *
   * Return:      Success:        non-negative
   *              Failure:        negative
   *
   * Programmer: Vailin Choi; Nov 2016
   *
   *-------------------------------------------------------------------------
   */
  void
  H5MF__alloc_to_fs_type(H5F_shared_t *f_sh, H5FD_mem_t alloc_type, hsize_t size, H5F_mem_page_t *fs_type)
  {
      FUNC_ENTER_PACKAGE_NOERR
  
      /* Check arguments */
      HDassert(f_sh);
      HDassert(fs_type);
  
      if (H5F_SHARED_PAGED_AGGR(f_sh)) { /* paged aggregation */
          if (size >= f_sh->fs_page_size) {
              if (H5F_SHARED_HAS_FEATURE(f_sh, H5FD_FEAT_PAGED_AGGR)) { /* multi or split driver */
                  /* For non-contiguous address space, map to large size free-space manager for each alloc_type
                   */
                  if (H5FD_MEM_DEFAULT == f_sh->fs_type_map[alloc_type])
                      *fs_type = (H5F_mem_page_t)(alloc_type + (H5FD_MEM_NTYPES - 1));
                  else
                      *fs_type = (H5F_mem_page_t)(f_sh->fs_type_map[alloc_type] + (H5FD_MEM_NTYPES - 1));
              } /* end if */
              else
                  /* For contiguous address space, map to generic large size free-space manager */
                  *fs_type = H5F_MEM_PAGE_GENERIC; /* H5F_MEM_PAGE_SUPER */
          }                                        /* end if */
          else
              *fs_type = (H5F_mem_page_t)H5MF_ALLOC_TO_FS_AGGR_TYPE(f_sh, alloc_type);
      }    /* end if */
      else /* non-paged aggregation */
          *fs_type = (H5F_mem_page_t)H5MF_ALLOC_TO_FS_AGGR_TYPE(f_sh, alloc_type);
  
      FUNC_LEAVE_NOAPI_VOID
  } /* end H5MF__alloc_to_fs_type() */
  
  /*-------------------------------------------------------------------------
   * Function:	H5MF__open_fstype
   *
   * Purpose:	Open an existing free space manager of TYPE for file by
   *          creating a free-space structure.
   *          Note that TYPE can be H5F_mem_page_t or H5FD_mem_t enum types.
   *
   * Return:	Success:	non-negative
   *		Failure:	negative
   *
   * Programmer:	Quincey Koziol
   *		Jan  8 2008
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5MF__open_fstype(H5F_t *f, H5F_mem_page_t type)
  {
      const H5FS_section_class_t *classes[] = {/* Free space section classes implemented for file */
                                               H5MF_FSPACE_SECT_CLS_SIMPLE, H5MF_FSPACE_SECT_CLS_SMALL,
                                               H5MF_FSPACE_SECT_CLS_LARGE};
      hsize_t                     alignment;                 /* Alignment to use */
      hsize_t                     threshold;                 /* Threshold to use */
      H5AC_ring_t                 orig_ring = H5AC_RING_INV; /* Original ring value */
      H5AC_ring_t                 fsm_ring;                  /* Ring of FSM */
      herr_t                      ret_value = SUCCEED;       /* Return value */
  
      FUNC_ENTER_PACKAGE_TAG(H5AC__FREESPACE_TAG)
  
      /*
       * Check arguments.
       */
      HDassert(f);
      if (H5F_PAGED_AGGR(f))
          HDassert(type < H5F_MEM_PAGE_NTYPES);
      else {
          HDassert((H5FD_mem_t)type < H5FD_MEM_NTYPES);
          HDassert((H5FD_mem_t)type != H5FD_MEM_NOLIST);
      } /* end else */
      HDassert(f->shared);
      HDassert(H5F_addr_defined(f->shared->fs_addr[type]));
      HDassert(f->shared->fs_state[type] == H5F_FS_STATE_CLOSED);
  
      /* Set up the alignment and threshold to use depending on the manager type */
      if (H5F_PAGED_AGGR(f)) {
          alignment = (type == H5F_MEM_PAGE_GENERIC) ? f->shared->fs_page_size : (hsize_t)H5F_ALIGN_DEF;
          threshold = H5F_ALIGN_THRHD_DEF;
      } /* end if */
      else {
          alignment = f->shared->alignment;
          threshold = f->shared->threshold;
      } /* end else */
  
      /* Set the ring type in the API context */
      if (H5MF__fsm_type_is_self_referential(f->shared, type))
          fsm_ring = H5AC_RING_MDFSM;
      else
          fsm_ring = H5AC_RING_RDFSM;
      H5AC_set_ring(fsm_ring, &orig_ring);
  
      /* Open an existing free space structure for the file */
      if (NULL == (f->shared->fs_man[type] = H5FS_open(f, f->shared->fs_addr[type], NELMTS(classes), classes, f,
                                                       alignment, threshold)))
          HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize free space info")
  
      /* Set the state for the free space manager to "open", if it is now */
      if (f->shared->fs_man[type])
          f->shared->fs_state[type] = H5F_FS_STATE_OPEN;
  
  done:
      /* Reset the ring in the API context */
      if (orig_ring != H5AC_RING_INV)
          H5AC_set_ring(orig_ring, NULL);
  
      FUNC_LEAVE_NOAPI_TAG(ret_value)
  } /* end H5MF__open_fstype() */
  
  /*-------------------------------------------------------------------------
   * Function:	H5MF__create_fstype
   *
   * Purpose:	Create free space manager of TYPE for the file by creating
   *          a free-space structure
   *          Note that TYPE can be H5F_mem_page_t or H5FD_mem_t enum types.
   *
   * Return:	Success:	non-negative
   *		Failure:	negative
   *
   * Programmer:	Quincey Koziol
   *		Jan  8 2008
   *
   *-------------------------------------------------------------------------
   */
  static herr_t
  H5MF__create_fstype(H5F_t *f, H5F_mem_page_t type)
  {
      const H5FS_section_class_t *classes[] = {/* Free space section classes implemented for file */
                                               H5MF_FSPACE_SECT_CLS_SIMPLE, H5MF_FSPACE_SECT_CLS_SMALL,
                                               H5MF_FSPACE_SECT_CLS_LARGE};
      H5FS_create_t               fs_create;                 /* Free space creation parameters */
      hsize_t                     alignment;                 /* Alignment to use */
      hsize_t                     threshold;                 /* Threshold to use */
      H5AC_ring_t                 orig_ring = H5AC_RING_INV; /* Original ring value */
      H5AC_ring_t                 fsm_ring;                  /* Ring of FSM */
      herr_t                      ret_value = SUCCEED;       /* Return value */
  
      FUNC_ENTER_STATIC
  
      /*
       * Check arguments.
       */
      HDassert(f);
      if (H5F_PAGED_AGGR(f))
          HDassert(type < H5F_MEM_PAGE_NTYPES);
      else {
          HDassert((H5FD_mem_t)type < H5FD_MEM_NTYPES);
          HDassert((H5FD_mem_t)type != H5FD_MEM_NOLIST);
      } /* end else */
      HDassert(f->shared);
      HDassert(!H5F_addr_defined(f->shared->fs_addr[type]));
      HDassert(f->shared->fs_state[type] == H5F_FS_STATE_CLOSED);
  
      /* Set the free space creation parameters */
      fs_create.client         = H5FS_CLIENT_FILE_ID;
      fs_create.shrink_percent = H5MF_FSPACE_SHRINK;
      fs_create.expand_percent = H5MF_FSPACE_EXPAND;
      fs_create.max_sect_addr  = 1 + H5VM_log2_gen((uint64_t)f->shared->maxaddr);
      fs_create.max_sect_size  = f->shared->maxaddr;
  
      /* Set up alignment and threshold to use depending on TYPE */
      if (H5F_PAGED_AGGR(f)) {
          alignment = (type == H5F_MEM_PAGE_GENERIC) ? f->shared->fs_page_size : (hsize_t)H5F_ALIGN_DEF;
          threshold = H5F_ALIGN_THRHD_DEF;
      } /* end if */
      else {
          alignment = f->shared->alignment;
          threshold = f->shared->threshold;
      } /* end else */
  
      /* Set the ring type in the API context */
      if (H5MF__fsm_type_is_self_referential(f->shared, type))
          fsm_ring = H5AC_RING_MDFSM;
      else
          fsm_ring = H5AC_RING_RDFSM;
      H5AC_set_ring(fsm_ring, &orig_ring);
  
      if (NULL == (f->shared->fs_man[type] =
                       H5FS_create(f, NULL, &fs_create, NELMTS(classes), classes, f, alignment, threshold)))
          HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize free space info")
  
      /* Set the state for the free space manager to "open", if it is now */
      if (f->shared->fs_man[type])
          f->shared->fs_state[type] = H5F_FS_STATE_OPEN;
  
  done:
      /* Reset the ring in the API context */
      if (orig_ring != H5AC_RING_INV)
          H5AC_set_ring(orig_ring, NULL);
  
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5MF__create_fstype() */
  
  /*-------------------------------------------------------------------------
   * Function:	H5MF__start_fstype
   *
   * Purpose:	Open or create a free space manager of a given TYPE.
   *          Note that TYPE can be H5F_mem_page_t or H5FD_mem_t enum types.
   *
   * Return:	Success:	non-negative
   *		Failure:	negative
   *
   * Programmer:	Quincey Koziol
   *		Jan  8 2008
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5MF__start_fstype(H5F_t *f, H5F_mem_page_t type)
  {
      herr_t ret_value = SUCCEED; /* Return value */
  
      FUNC_ENTER_PACKAGE
  
      /*
       * Check arguments.
       */
      HDassert(f);
      HDassert(f->shared);
      if (H5F_PAGED_AGGR(f))
          HDassert(type < H5F_MEM_PAGE_NTYPES);
      else {
          HDassert((H5FD_mem_t)type < H5FD_MEM_NTYPES);
          HDassert((H5FD_mem_t)type != H5FD_MEM_NOLIST);
      } /* end else */
  
      /* Check if the free space manager exists already */
      if (H5F_addr_defined(f->shared->fs_addr[type])) {
          /* Open existing free space manager */
          if (H5MF__open_fstype(f, type) < 0)
              HGOTO_ERROR(H5E_RESOURCE, H5E_CANTOPENOBJ, FAIL, "can't initialize file free space")
      } /* end if */
      else {
          /* Create new free space manager */
          if (H5MF__create_fstype(f, type) < 0)
              HGOTO_ERROR(H5E_RESOURCE, H5E_CANTCREATE, FAIL, "can't initialize file free space")
      } /* end else */
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5MF__start_fstype() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5MF__delete_fstype
   *
   * Purpose:     Delete the free-space manager as specified by TYPE.
   *              Note that TYPE can be H5F_mem_page_t or H5FD_mem_t enum types.
   *
   * Return:      Success:        non-negative
   *              Failure:        negative
   *
   * Programmer: 	Vailin Choi; April 2013
   *
   *-------------------------------------------------------------------------
   */
  static herr_t
  H5MF__delete_fstype(H5F_t *f, H5F_mem_page_t type)
  {
      H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */
      H5AC_ring_t fsm_ring  = H5AC_RING_INV; /* Ring of FSM */
      haddr_t     tmp_fs_addr;               /* Temporary holder for free space manager address */
      herr_t      ret_value = SUCCEED;       /* Return value */
  
      FUNC_ENTER_STATIC
  
      /* check args */
      HDassert(f);
      if (H5F_PAGED_AGGR(f))
          HDassert(type < H5F_MEM_PAGE_NTYPES);
      else
          HDassert((H5FD_mem_t)type < H5FD_MEM_NTYPES);
      HDassert(H5F_addr_defined(f->shared->fs_addr[type]));
  
      /* Put address into temporary variable and reset it */
      /* (Avoids loopback in file space freeing routine) */
      tmp_fs_addr              = f->shared->fs_addr[type];
      f->shared->fs_addr[type] = HADDR_UNDEF;
  
      /* Shift to "deleting" state, to make certain we don't track any
       *  file space freed as a result of deleting the free space manager.
       */
      f->shared->fs_state[type] = H5F_FS_STATE_DELETING;
  
      /* Set the ring type in the API context */
      if (H5MF__fsm_type_is_self_referential(f->shared, type))
          fsm_ring = H5AC_RING_MDFSM;
      else
          fsm_ring = H5AC_RING_RDFSM;
      H5AC_set_ring(fsm_ring, &orig_ring);
  
  #ifdef H5MF_ALLOC_DEBUG_MORE
      HDfprintf(stderr, "%s: Before deleting free space manager\n", __func__);
  #endif /* H5MF_ALLOC_DEBUG_MORE */
  
      /* Delete free space manager for this type */
      if (H5FS_delete(f, tmp_fs_addr) < 0)
          HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "can't delete free space manager")
  
      /* Shift [back] to closed state */
      HDassert(f->shared->fs_state[type] == H5F_FS_STATE_DELETING);
      f->shared->fs_state[type] = H5F_FS_STATE_CLOSED;
  
      /* Sanity check that the free space manager for this type wasn't started up again */
      HDassert(!H5F_addr_defined(f->shared->fs_addr[type]));
  
  done:
      /* Reset the ring in the API context */
      if (orig_ring != H5AC_RING_INV)
          H5AC_set_ring(orig_ring, NULL);
  
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5MF__delete_fstype() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5MF__close_fstype
   *
   * Purpose:     Close the free space manager of TYPE for file
   *              Note that TYPE can be H5F_mem_page_t or H5FD_mem_t enum types.
   *
   * Return:      Success:        non-negative
   *              Failure:        negative
   *
   * Programmer: Vailin Choi; July 1st, 2009
   *
   *-------------------------------------------------------------------------
   */
  static herr_t
  H5MF__close_fstype(H5F_t *f, H5F_mem_page_t type)
  {
      herr_t ret_value = SUCCEED; /* Return value */
  
      FUNC_ENTER_STATIC
  
      /*
       * Check arguments.
       */
      HDassert(f);
      if (H5F_PAGED_AGGR(f))
          HDassert(type < H5F_MEM_PAGE_NTYPES);
      else
          HDassert((H5FD_mem_t)type < H5FD_MEM_NTYPES);
      HDassert(f->shared);
      HDassert(f->shared->fs_man[type]);
      HDassert(f->shared->fs_state[type] != H5F_FS_STATE_CLOSED);
  
  #ifdef H5MF_ALLOC_DEBUG_MORE
      HDfprintf(stderr, "%s: Before closing free space manager\n", __func__);
  #endif /* H5MF_ALLOC_DEBUG_MORE */
  
      /* Close an existing free space structure for the file */
      if (H5FS_close(f, f->shared->fs_man[type]) < 0)
          HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't release free space info")
      f->shared->fs_man[type]   = NULL;
      f->shared->fs_state[type] = H5F_FS_STATE_CLOSED;
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5MF__close_fstype() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5MF__add_sect
   *
   * Purpose:	    To add a section to the specified free-space manager.
   *
   * Return:      Success:        non-negative
   *              Failure:        negative
   *
   * Programmer:  Vailin Choi; April 2013
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5MF__add_sect(H5F_t *f, H5FD_mem_t alloc_type, H5FS_t *fspace, H5MF_free_section_t *node)
  {
      H5AC_ring_t    orig_ring = H5AC_RING_INV; /* Original ring value */
      H5AC_ring_t    fsm_ring  = H5AC_RING_INV; /* Ring of FSM */
      H5MF_sect_ud_t udata;                     /* User data for callback */
      H5F_mem_page_t fs_type;                   /* Free space type (mapped from allocation type) */
      herr_t         ret_value = SUCCEED;       /* Return value */
  
      FUNC_ENTER_PACKAGE
  
      HDassert(f);
      HDassert(fspace);
      HDassert(node);
  
      H5MF__alloc_to_fs_type(f->shared, alloc_type, node->sect_info.size, &fs_type);
  
      /* Construct user data for callbacks */
      udata.f                     = f;
      udata.alloc_type            = alloc_type;
      udata.allow_sect_absorb     = TRUE;
      udata.allow_eoa_shrink_only = FALSE;
  
      /* Set the ring type in the API context */
      if (H5MF__fsm_is_self_referential(f->shared, fspace))
          fsm_ring = H5AC_RING_MDFSM;
      else
          fsm_ring = H5AC_RING_RDFSM;
      H5AC_set_ring(fsm_ring, &orig_ring);
  
  #ifdef H5MF_ALLOC_DEBUG_MORE
      HDfprintf(stderr, "%s: adding node, node->sect_info.addr = %a, node->sect_info.size = %Hu\n", __func__,
                node->sect_info.addr, node->sect_info.size);
  #endif /* H5MF_ALLOC_DEBUG_MORE */
      /* Add the section */
      if (H5FS_sect_add(f, fspace, (H5FS_section_info_t *)node, H5FS_ADD_RETURNED_SPACE, &udata) < 0)
          HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, FAIL, "can't re-add section to file free space")
  
  done:
      /* Reset the ring in the API context */
      if (orig_ring != H5AC_RING_INV)
          H5AC_set_ring(orig_ring, NULL);
  
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5MF__add_sect() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5MF__find_sect
   *
   * Purpose:	To find a section from the specified free-space manager to fulfill the request.
   *		    If found, re-add the left-over space back to the manager.
   *
   * Return:	TRUE if a section is found to fulfill the request
   *		    FALSE if not
   *
   * Programmer:  Vailin Choi; April 2013
   *
   *-------------------------------------------------------------------------
   */
  htri_t
  H5MF__find_sect(H5F_t *f, H5FD_mem_t alloc_type, hsize_t size, H5FS_t *fspace, haddr_t *addr)
  {
      H5AC_ring_t          orig_ring = H5AC_RING_INV; /* Original ring value */
      H5AC_ring_t          fsm_ring  = H5AC_RING_INV; /* Ring of FSM */
      H5MF_free_section_t *node;                      /* Free space section pointer */
      htri_t               ret_value = FAIL;          /* Whether an existing free list node was found */
  
      FUNC_ENTER_PACKAGE
  
      HDassert(f);
      HDassert(fspace);
  
      /* Set the ring type in the API context */
      if (H5MF__fsm_is_self_referential(f->shared, fspace))
          fsm_ring = H5AC_RING_MDFSM;
      else
          fsm_ring = H5AC_RING_RDFSM;
      H5AC_set_ring(fsm_ring, &orig_ring);
  
      /* Try to get a section from the free space manager */
      if ((ret_value = H5FS_sect_find(f, fspace, size, (H5FS_section_info_t **)&node)) < 0)
          HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "error locating free space in file")
  
  #ifdef H5MF_ALLOC_DEBUG_MORE
      HDfprintf(stderr, "%s: section found = %t\n", __func__, ret_value);
  #endif /* H5MF_ALLOC_DEBUG_MORE */
  
      /* Check for actually finding section */
      if (ret_value) {
          /* Sanity check */
          HDassert(node);
  
          /* Retrieve return value */
          if (addr)
              *addr = node->sect_info.addr;
  
          /* Check for eliminating the section */
          if (node->sect_info.size == size) {
  #ifdef H5MF_ALLOC_DEBUG_MORE
              HDfprintf(stderr, "%s: freeing node\n", __func__);
  #endif /* H5MF_ALLOC_DEBUG_MORE */
  
              /* Free section node */
              if (H5MF__sect_free((H5FS_section_info_t *)node) < 0)
                  HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free simple section node")
          } /* end if */
          else {
              /* Adjust information for section */
              node->sect_info.addr += size;
              node->sect_info.size -= size;
  
  #ifdef H5MF_ALLOC_DEBUG_MORE
              HDfprintf(stderr, "%s: re-adding node, node->sect_info.size = %Hu\n", __func__,
                        node->sect_info.size);
  #endif /* H5MF_ALLOC_DEBUG_MORE */
  
              /* Re-add the section to the free-space manager */
              if (H5MF__add_sect(f, alloc_type, fspace, node) < 0)
                  HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, FAIL, "can't re-add section to file free space")
          } /* end else */
      }     /* end if */
  
  done:
      /* Reset the ring in the API context */
      if (orig_ring != H5AC_RING_INV)
          H5AC_set_ring(orig_ring, NULL);
  
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5MF__find_sect() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5MF_alloc
   *
   * Purpose:     Allocate SIZE bytes of file memory and return the relative
   *		address where that contiguous chunk of file memory exists.
   *		The TYPE argument describes the purpose for which the storage
   *		is being requested.
   *
   * Return:      Success:        The file address of new chunk.
   *              Failure:        HADDR_UNDEF
   *
   * Programmer:  Robb Matzke
   *              Jul 11 1997
   *
   *-------------------------------------------------------------------------
   */
  haddr_t
  H5MF_alloc(H5F_t *f, H5FD_mem_t alloc_type, hsize_t size)
  {
      H5AC_ring_t    fsm_ring  = H5AC_RING_INV; /* free space manager ring */
      H5AC_ring_t    orig_ring = H5AC_RING_INV; /* Original ring value */
      H5F_mem_page_t fs_type;                   /* Free space type (mapped from allocation type) */
      haddr_t        ret_value = HADDR_UNDEF;   /* Return value */
  
      FUNC_ENTER_NOAPI_TAG(H5AC__FREESPACE_TAG, HADDR_UNDEF)
  #ifdef H5MF_ALLOC_DEBUG
      HDfprintf(stderr, "%s: alloc_type = %u, size = %Hu\n", __func__, (unsigned)alloc_type, size);
  #endif /* H5MF_ALLOC_DEBUG */
  
      /* check arguments */
      HDassert(f);
      HDassert(f->shared);
      HDassert(f->shared->lf);
      HDassert(size > 0);
  
      H5MF__alloc_to_fs_type(f->shared, alloc_type, size, &fs_type);
  
  #ifdef H5MF_ALLOC_DEBUG_MORE
      HDfprintf(stderr, "%s: Check 1.0\n", __func__);
  #endif /* H5MF_ALLOC_DEBUG_MORE */
  
      /* Set the ring type in the API context */
      if (H5MF__fsm_type_is_self_referential(f->shared, fs_type))
          fsm_ring = H5AC_RING_MDFSM;
      else
          fsm_ring = H5AC_RING_RDFSM;
      H5AC_set_ring(fsm_ring, &orig_ring);
  
      /* Check if we are using the free space manager for this file */
      if (H5F_HAVE_FREE_SPACE_MANAGER(f)) {
          /* We are about to change the contents of the free space manager --
           * notify metadata cache that the associated fsm ring is
           * unsettled
           */
          if (H5AC_unsettle_ring(f, fsm_ring) < 0)
              HGOTO_ERROR(H5E_RESOURCE, H5E_SYSTEM, HADDR_UNDEF,
                          "attempt to notify cache that ring is unsettled failed")
  
          /* Check if the free space manager for the file has been initialized */
          if (!f->shared->fs_man[fs_type] && H5F_addr_defined(f->shared->fs_addr[fs_type])) {
              /* Open the free-space manager */
              if (H5MF__open_fstype(f, fs_type) < 0)
                  HGOTO_ERROR(H5E_RESOURCE, H5E_CANTOPENOBJ, HADDR_UNDEF, "can't initialize file free space")
              HDassert(f->shared->fs_man[fs_type]);
          } /* end if */
  
          /* Search for large enough space in the free space manager */
          if (f->shared->fs_man[fs_type])
              if (H5MF__find_sect(f, alloc_type, size, f->shared->fs_man[fs_type], &ret_value) < 0)
                  HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "error locating a node")
      } /* end if */
  
      /* If no space is found from the free-space manager, continue further action */
      if (!H5F_addr_defined(ret_value)) {
  #ifdef H5MF_ALLOC_DEBUG_MORE
          HDfprintf(stderr, "%s: Check 2.0\n", __func__);
  #endif /* H5MF_ALLOC_DEBUG_MORE */
          if (f->shared->fs_strategy == H5F_FSPACE_STRATEGY_PAGE) {
              HDassert(f->shared->fs_page_size >= H5F_FILE_SPACE_PAGE_SIZE_MIN);
              if (HADDR_UNDEF == (ret_value = H5MF__alloc_pagefs(f, alloc_type, size)))
                  HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF,
                              "allocation failed from paged aggregation")
          }      /* end if */
          else { /* For non-paged aggregation, continue further action */
              if (HADDR_UNDEF == (ret_value = H5MF_aggr_vfd_alloc(f, alloc_type, size)))
                  HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "allocation failed from aggr/vfd")
          } /* end else */
      }     /* end if */
      HDassert(H5F_addr_defined(ret_value));
  #ifdef H5MF_ALLOC_DEBUG_MORE
      HDfprintf(stderr, "%s: Check 3.0\n", __func__);
  #endif /* H5MF_ALLOC_DEBUG_MORE */
  
  done:
      /* Reset the ring in the API context */
      if (orig_ring != H5AC_RING_INV)
          H5AC_set_ring(orig_ring, NULL);
  
  #ifdef H5MF_ALLOC_DEBUG
      HDfprintf(stderr, "%s: Leaving: ret_value = %a, size = %Hu\n", __func__, ret_value, size);
  #endif /* H5MF_ALLOC_DEBUG */
  #ifdef H5MF_ALLOC_DEBUG_DUMP
      H5MF__sects_dump(f, stderr);
  #endif /* H5MF_ALLOC_DEBUG_DUMP */
  
      FUNC_LEAVE_NOAPI_TAG(ret_value)
  } /* end H5MF_alloc() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5MF__alloc_pagefs
   *
   * Purpose:     Allocate space from either the large or small free-space manager.
   *              For "large" request:
   *                  Allocate request from VFD
   *                  Determine mis-aligned fragment and return the fragment to the
   *                  appropriate manager
   *              For "small" request:
   *                  Allocate a page from the large manager
   *                  Determine whether space is available from a mis-aligned fragment
   *                  being returned to the manager
   *              Return left-over space to the manager after fulfilling request
   *
   * Return:      Success:        The file address of new chunk.
   *              Failure:        HADDR_UNDEF
   *
   * Programmer:  Vailin Choi; Dec 2012
   *
   *-------------------------------------------------------------------------
   */
  static haddr_t
  H5MF__alloc_pagefs(H5F_t *f, H5FD_mem_t alloc_type, hsize_t size)
  {
      H5F_mem_page_t       ptype;                   /* Free-space manager type */
      H5MF_free_section_t *node      = NULL;        /* Free space section pointer */
      haddr_t              ret_value = HADDR_UNDEF; /* Return value */
  
      FUNC_ENTER_STATIC
  
  #ifdef H5MF_ALLOC_DEBUG
      HDfprintf(stderr, "%s: alloc_type = %u, size = %Hu\n", __func__, (unsigned)alloc_type, size);
  #endif /* H5MF_ALLOC_DEBUG */
  
      H5MF__alloc_to_fs_type(f->shared, alloc_type, size, &ptype);
  
      switch (ptype) {
          case H5F_MEM_PAGE_GENERIC:
          case H5F_MEM_PAGE_LARGE_BTREE:
          case H5F_MEM_PAGE_LARGE_DRAW:
          case H5F_MEM_PAGE_LARGE_GHEAP:
          case H5F_MEM_PAGE_LARGE_LHEAP:
          case H5F_MEM_PAGE_LARGE_OHDR: {
              haddr_t eoa;           /* EOA for the file */
              hsize_t frag_size = 0; /* Fragment size */
  
              /* Get the EOA for the file */
              if (HADDR_UNDEF == (eoa = H5F_get_eoa(f, alloc_type)))
                  HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, HADDR_UNDEF, "Unable to get eoa")
              HDassert(!(eoa % f->shared->fs_page_size));
  
              H5MF_EOA_MISALIGN(f, (eoa + size), f->shared->fs_page_size, frag_size);
  
              /* Allocate from VFD */
              if (HADDR_UNDEF == (ret_value = H5F__alloc(f, alloc_type, size + frag_size, NULL, NULL)))
                  HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "can't allocate file space")
  
              /* If there is a mis-aligned fragment at EOA */
              if (frag_size) {
  
                  /* Start up the free-space manager */
                  if (!(f->shared->fs_man[ptype]))
                      if (H5MF__start_fstype(f, ptype) < 0)
                          HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, HADDR_UNDEF,
                                      "can't initialize file free space")
  
                  /* Create free space section for the fragment */
                  if (NULL == (node = H5MF__sect_new(H5MF_FSPACE_SECT_LARGE, ret_value + size, frag_size)))
                      HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, HADDR_UNDEF,
                                  "can't initialize free space section")
  
                  /* Add the fragment to the large free-space manager */
                  if (H5MF__add_sect(f, alloc_type, f->shared->fs_man[ptype], node) < 0)
                      HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, HADDR_UNDEF,
                                  "can't re-add section to file free space")
  
                  node = NULL;
              } /* end if */
          } break;
  
          case H5F_MEM_PAGE_META:
          case H5F_MEM_PAGE_DRAW:
          case H5F_MEM_PAGE_BTREE:
          case H5F_MEM_PAGE_GHEAP:
          case H5F_MEM_PAGE_LHEAP:
          case H5F_MEM_PAGE_OHDR: {
              haddr_t new_page; /* The address for the new file size page */
  
              /* Allocate one file space page */
              if (HADDR_UNDEF == (new_page = H5MF_alloc(f, alloc_type, f->shared->fs_page_size)))
                  HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "can't allocate file space")
  
              /* Start up the free-space manager */
              if (!(f->shared->fs_man[ptype]))
                  if (H5MF__start_fstype(f, ptype) < 0)
                      HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, HADDR_UNDEF, "can't initialize file free space")
              HDassert(f->shared->fs_man[ptype]);
  
              if (NULL == (node = H5MF__sect_new(H5MF_FSPACE_SECT_SMALL, (new_page + size),
                                                 (f->shared->fs_page_size - size))))
                  HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, HADDR_UNDEF, "can't initialize free space section")
  
              /* Add the remaining space in the page to the manager */
              if (H5MF__add_sect(f, alloc_type, f->shared->fs_man[ptype], node) < 0)
                  HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, HADDR_UNDEF,
                              "can't re-add section to file free space")
  
              node = NULL;
  
              /* Insert the new page into the Page Buffer list of new pages so
                 we don't read an empty page from disk */
              if (f->shared->page_buf != NULL && H5PB_add_new_page(f->shared, alloc_type, new_page) < 0)
                  HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, HADDR_UNDEF,
                              "can't add new page to Page Buffer new page list")
  
              ret_value = new_page;
          } break;
  
          case H5F_MEM_PAGE_NTYPES:
          case H5F_MEM_PAGE_DEFAULT:
          default:
              HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF,
                          "can't allocate file space: unrecognized type")
              break;
      } /* end switch */
  
  done:
  #ifdef H5MF_ALLOC_DEBUG
      HDfprintf(stderr, "%s: Leaving: ret_value = %a, size = %Hu\n", __func__, ret_value, size);
  #endif /* H5MF_ALLOC_DEBUG */
  #ifdef H5MF_ALLOC_DEBUG_DUMP
      H5MF__sects_dump(f, stderr);
  #endif /* H5MF_ALLOC_DEBUG_DUMP */
  
      /* Release section node, if allocated and not added to section list or merged */
      if (node)
          if (H5MF__sect_free((H5FS_section_info_t *)node) < 0)
              HDONE_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, HADDR_UNDEF, "can't free section node")
  
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5MF__alloc_pagefs() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5MF_alloc_tmp
   *
   * Purpose:     Allocate temporary space in the file
   *
   * Note:	The address returned is non-overlapping with any other address
   *		in the file and suitable for insertion into the metadata
   *		cache.
   *
   *		The address is _not_ suitable for actual file I/O and will
   *		cause an error if it is so used.
   *
   *		The space allocated with this routine should _not_ be freed,
   *		it should just be abandoned.  Calling H5MF_xfree() with space
   *              from this routine will cause an error.
   *
   * Return:      Success:        Temporary file address
   *              Failure:        HADDR_UNDEF
   *
   * Programmer:  Quincey Koziol
   *              Thursday, June  4, 2009
   *
   *-------------------------------------------------------------------------
   */
  haddr_t
  H5MF_alloc_tmp(H5F_t *f, hsize_t size)
  {
      haddr_t eoa;                     /* End of allocated space in the file */
      haddr_t ret_value = HADDR_UNDEF; /* Return value */
  
      FUNC_ENTER_NOAPI(HADDR_UNDEF)
  #ifdef H5MF_ALLOC_DEBUG
      HDfprintf(stderr, "%s: size = %Hu\n", __func__, size);
  #endif /* H5MF_ALLOC_DEBUG */
  
      /* check args */
      HDassert(f);
      HDassert(f->shared);
      HDassert(f->shared->lf);
      HDassert(size > 0);
  
      /* Retrieve the 'eoa' for the file */
      if (HADDR_UNDEF == (eoa = H5F_get_eoa(f, H5FD_MEM_DEFAULT)))
          HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, HADDR_UNDEF, "driver get_eoa request failed")
  
      /* Compute value to return */
      ret_value = f->shared->tmp_addr - size;
  
      /* Check for overlap into the actual allocated space in the file */
      if (H5F_addr_le(ret_value, eoa))
          HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, HADDR_UNDEF, "driver get_eoa request failed")
  
      /* Adjust temporary address allocator in the file */
      f->shared->tmp_addr = ret_value;
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5MF_alloc_tmp() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5MF_xfree
   *
   * Purpose:     Frees part of a file, making that part of the file
   *              available for reuse.
   *
   * Return:      Non-negative on success/Negative on failure
   *
   * Programmer:  Robb Matzke
   *              Jul 17 1997
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5MF_xfree(H5F_t *f, H5FD_mem_t alloc_type, haddr_t addr, hsize_t size)
  {
      H5F_mem_page_t       fs_type;                   /* Free space type (mapped from allocation type) */
      H5MF_free_section_t *node = NULL;               /* Free space section pointer */
      unsigned             ctype;                     /* section class type */
      H5AC_ring_t          orig_ring = H5AC_RING_INV; /* Original ring value */
      H5AC_ring_t          fsm_ring;                  /* Ring of FSM */
      herr_t               ret_value = SUCCEED;       /* Return value */
  
      FUNC_ENTER_NOAPI_TAG(H5AC__FREESPACE_TAG, FAIL)
  #ifdef H5MF_ALLOC_DEBUG
      HDfprintf(stderr, "%s: Entering - alloc_type = %u, addr = %a, size = %Hu\n", __func__,
                (unsigned)alloc_type, addr, size);
  #endif /* H5MF_ALLOC_DEBUG */
  
      /* check arguments */
      HDassert(f);
      if (!H5F_addr_defined(addr) || 0 == size)
          HGOTO_DONE(SUCCEED)
      HDassert(addr != 0); /* Can't deallocate the superblock :-) */
  
      H5MF__alloc_to_fs_type(f->shared, alloc_type, size, &fs_type);
  
      /* Set the ring type in the API context */
      if (H5MF__fsm_type_is_self_referential(f->shared, fs_type))
          fsm_ring = H5AC_RING_MDFSM;
      else
          fsm_ring = H5AC_RING_RDFSM;
      H5AC_set_ring(fsm_ring, &orig_ring);
  
      /* we are about to change the contents of the free space manager --
       * notify metadata cache that the associated fsm ring is
       * unsettled
       */
      /* Only do so for strategies that use free-space managers */
      if (H5F_HAVE_FREE_SPACE_MANAGER(f))
          if (H5AC_unsettle_ring(f, fsm_ring) < 0)
              HGOTO_ERROR(H5E_RESOURCE, H5E_SYSTEM, FAIL,
                          "attempt to notify cache that ring is unsettled failed")
  
      /* Check for attempting to free space that's a 'temporary' file address */
      if (H5F_addr_le(f->shared->tmp_addr, addr))
          HGOTO_ERROR(H5E_RESOURCE, H5E_BADRANGE, FAIL, "attempting to free temporary file space")
  
      /* If it's metadata, check if the space to free intersects with the file's
       * metadata accumulator
       */
      if (H5FD_MEM_DRAW != alloc_type) {
          /* Check if the space to free intersects with the file's metadata accumulator */
          if (H5F__accum_free(f->shared, alloc_type, addr, size) < 0)
              HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL,
                          "can't check free space intersection w/metadata accumulator")
      } /* end if */
  
      /* Check if the free space manager for the file has been initialized */
      if (!f->shared->fs_man[fs_type]) {
          /* If there's no free space manager for objects of this type,
           *  see if we can avoid creating one by checking if the freed
           *  space is at the end of the file
           */
  #ifdef H5MF_ALLOC_DEBUG_MORE
          HDfprintf(stderr, "%s: fs_addr = %a\n", __func__, f->shared->fs_addr[fs_type]);
  #endif /* H5MF_ALLOC_DEBUG_MORE */
          if (!H5F_addr_defined(f->shared->fs_addr[fs_type])) {
              htri_t status; /* "can absorb" status for section into */
  
  #ifdef H5MF_ALLOC_DEBUG_MORE
              HDfprintf(stderr, "%s: Trying to avoid starting up free space manager\n", __func__);
  #endif /* H5MF_ALLOC_DEBUG_MORE */
              /* Try to shrink the file or absorb the block into a block aggregator */
              if ((status = H5MF_try_shrink(f, alloc_type, addr, size)) < 0)
                  HGOTO_ERROR(H5E_RESOURCE, H5E_CANTMERGE, FAIL, "can't check for absorbing block")
              else if (status > 0)
                  /* Indicate success */
                  HGOTO_DONE(SUCCEED)
              else if (size < f->shared->fs_threshold) {
  #ifdef H5MF_ALLOC_DEBUG_MORE
                  HDfprintf(stderr, "%s: dropping addr = %a, size = %Hu, on the floor!\n", __func__, addr,
                            size);
  #endif /* H5MF_ALLOC_DEBUG_MORE */
                  HGOTO_DONE(SUCCEED)
              } /* end else-if */
          }     /* end if */
  
          /* If we are deleting the free space manager, leave now, to avoid
           *  [re-]starting it.
           * or if file space strategy type is not using a free space manager
           *  (H5F_FSPACE_STRATEGY_AGGR or H5F_FSPACE_STRATEGY_NONE), drop free space
           *   section on the floor.
           *
           * Note: this drops the space to free on the floor...
           *
           */
          if (f->shared->fs_state[fs_type] == H5F_FS_STATE_DELETING || !H5F_HAVE_FREE_SPACE_MANAGER(f)) {
  #ifdef H5MF_ALLOC_DEBUG_MORE
              HDfprintf(stderr, "%s: dropping addr = %a, size = %Hu, on the floor!\n", __func__, addr, size);
  #endif /* H5MF_ALLOC_DEBUG_MORE */
              HGOTO_DONE(SUCCEED)
          } /* end if */
  
          /* There's either already a free space manager, or the freed
           *  space isn't at the end of the file, so start up (or create)
           *  the file space manager
           */
          if (H5MF__start_fstype(f, fs_type) < 0)
              HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space")
      } /* end if */
  
      /* Create the free-space section for the freed section */
      ctype = H5MF_SECT_CLASS_TYPE(f, size);
      if (NULL == (node = H5MF__sect_new(ctype, addr, size)))
          HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize free space section")
  
      /* If size of the freed section is larger than threshold, add it to the free space manager */
      if (size >= f->shared->fs_threshold) {
          HDassert(f->shared->fs_man[fs_type]);
  
  #ifdef H5MF_ALLOC_DEBUG_MORE
          HDfprintf(stderr, "%s: Before H5FS_sect_add()\n", __func__);
  #endif /* H5MF_ALLOC_DEBUG_MORE */
  
          /* Add to the free space for the file */
          if (H5MF__add_sect(f, alloc_type, f->shared->fs_man[fs_type], node) < 0)
              HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, FAIL, "can't add section to file free space")
          node = NULL;
  
  #ifdef H5MF_ALLOC_DEBUG_MORE
          HDfprintf(stderr, "%s: After H5FS_sect_add()\n", __func__);
  #endif /* H5MF_ALLOC_DEBUG_MORE */
      }  /* end if */
      else {
          htri_t         merged; /* Whether node was merged */
          H5MF_sect_ud_t udata;  /* User data for callback */
  
          /* Construct user data for callbacks */
          udata.f                     = f;
          udata.alloc_type            = alloc_type;
          udata.allow_sect_absorb     = TRUE;
          udata.allow_eoa_shrink_only = FALSE;
  
          /* Try to merge the section that is smaller than threshold */
          if ((merged = H5FS_sect_try_merge(f, f->shared->fs_man[fs_type], (H5FS_section_info_t *)node,
                                            H5FS_ADD_RETURNED_SPACE, &udata)) < 0)
              HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, FAIL, "can't merge section to file free space")
          else if (merged == TRUE) /* successfully merged */
                                   /* Indicate that the node was used */
              node = NULL;
      } /* end else */
  
  done:
      /* Reset the ring in the API context */
      if (orig_ring != H5AC_RING_INV)
          H5AC_set_ring(orig_ring, NULL);
  
      /* Release section node, if allocated and not added to section list or merged */
      if (node)
          if (H5MF__sect_free((H5FS_section_info_t *)node) < 0)
              HDONE_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free simple section node")
  
  #ifdef H5MF_ALLOC_DEBUG
      HDfprintf(stderr, "%s: Leaving, ret_value = %d\n", __func__, ret_value);
  #endif /* H5MF_ALLOC_DEBUG */
  #ifdef H5MF_ALLOC_DEBUG_DUMP
      H5MF__sects_dump(f, stderr);
  #endif /* H5MF_ALLOC_DEBUG_DUMP */
      FUNC_LEAVE_NOAPI_TAG(ret_value)
  } /* end H5MF_xfree() */
  
  /*-------------------------------------------------------------------------
   * Function:	H5MF_try_extend
   *
   * Purpose:	Extend a block in the file if possible.
   *          For non-paged aggregation:
   *          --try to extend at EOA
   *          --try to extend into the aggregators
   *          --try to extend into a free-space section if adjoined
   *          For paged aggregation:
   *          --try to extend at EOA
   *          --try to extend into a free-space section if adjoined
   *          --try to extend into the page end threshold if a metadata block
   *
   * Return:	Success:	TRUE(1)  - Block was extended
   *                              FALSE(0) - Block could not be extended
   * 		Failure:	FAIL
   *
   * Programmer:	Quincey Koziol
   *              Friday, June 11, 2004
   *
   *-------------------------------------------------------------------------
   */
  htri_t
  H5MF_try_extend(H5F_t *f, H5FD_mem_t alloc_type, haddr_t addr, hsize_t size, hsize_t extra_requested)
  {
      H5AC_ring_t    orig_ring = H5AC_RING_INV; /* Original ring value */
      H5AC_ring_t    fsm_ring;                  /* Ring of FSM */
      haddr_t        end;                       /* End of block to extend */
      H5FD_mem_t     map_type;                  /* Mapped type */
      H5F_mem_page_t fs_type;                   /* free space type */
      htri_t         allow_extend = TRUE;       /* Possible to extend the block */
      hsize_t        frag_size    = 0;          /* Size of mis-aligned fragment */
      htri_t         ret_value    = FALSE;      /* Return value */
  
      FUNC_ENTER_NOAPI_TAG(H5AC__FREESPACE_TAG, FAIL)
  #ifdef H5MF_ALLOC_DEBUG
      HDfprintf(stderr, "%s: Entering: alloc_type = %u, addr = %a, size = %Hu, extra_requested = %Hu\n",
                __func__, (unsigned)alloc_type, addr, size, extra_requested);
  #endif /* H5MF_ALLOC_DEBUG */
  
      /* Sanity check */
      HDassert(f);
      HDassert(H5F_INTENT(f) & H5F_ACC_RDWR);
  
      /* Set mapped type, treating global heap as raw data */
      map_type = (alloc_type == H5FD_MEM_GHEAP) ? H5FD_MEM_DRAW : alloc_type;
  
      /* Compute end of block to extend */
      end = addr + size;
  
      /* For paged aggregation:
       *   To extend a small block: can only extend if not crossing page boundary
       *   To extend a large block at EOA: calculate in advance mis-aligned fragment so EOA will still end at
       * page boundary
       */
      if (H5F_PAGED_AGGR(f)) {
          if (size < f->shared->fs_page_size) {
              /* To extend a small block: cannot cross page boundary */
              if ((addr / f->shared->fs_page_size) != (((end + extra_requested) - 1) / f->shared->fs_page_size))
                  allow_extend = FALSE;
          } /* end if */
          else {
              haddr_t eoa; /* EOA for the file */
  
              /*   To extend a large block: calculate in advance the mis-aligned fragment so EOA will end at
               * page boundary if extended */
              if (HADDR_UNDEF == (eoa = H5F_get_eoa(f, alloc_type)))
                  HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "Unable to get eoa")
              HDassert(!(eoa % f->shared->fs_page_size));
  
              H5MF_EOA_MISALIGN(f, (eoa + extra_requested), f->shared->fs_page_size, frag_size);
          } /* end else */
      }     /* end if */
  
      /* Get free space type from allocation type */
      H5MF__alloc_to_fs_type(f->shared, alloc_type, size, &fs_type);
  
      /* Set the ring type in the API context */
      if (H5MF__fsm_type_is_self_referential(f->shared, fs_type))
          fsm_ring = H5AC_RING_MDFSM;
      else
          fsm_ring = H5AC_RING_RDFSM;
      H5AC_set_ring(fsm_ring, &orig_ring);
  
      if (allow_extend) {
          /* Try extending the block at EOA */
          if ((ret_value = H5F__try_extend(f, map_type, end, extra_requested + frag_size)) < 0)
              HGOTO_ERROR(H5E_RESOURCE, H5E_CANTEXTEND, FAIL, "error extending file")
  #ifdef H5MF_ALLOC_DEBUG_MORE
          HDfprintf(stderr, "%s: extended = %t\n", __func__, ret_value);
  #endif /* H5MF_ALLOC_DEBUG_MORE */
  
          /* If extending at EOA succeeds: */
          /*   for paged aggregation, put the fragment into the large-sized free-space manager */
          if (ret_value == TRUE && H5F_PAGED_AGGR(f) && frag_size) {
              H5MF_free_section_t *node = NULL; /* Free space section pointer */
  
              /* Should be large-sized block */
              HDassert(size >= f->shared->fs_page_size);
  
              /* Start up the free-space manager */
              if (!(f->shared->fs_man[fs_type]))
                  if (H5MF__start_fstype(f, fs_type) < 0)
                      HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space")
  
              /* Create free space section for the fragment */
              if (NULL == (node = H5MF__sect_new(H5MF_FSPACE_SECT_LARGE, end + extra_requested, frag_size)))
                  HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize free space section")
  
              /* Add the fragment to the large-sized free-space manager */
              if (H5MF__add_sect(f, alloc_type, f->shared->fs_man[fs_type], node) < 0)
                  HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, FAIL, "can't re-add section to file free space")
  
              node = NULL;
          } /* end if */
  
          /* For non-paged aggregation: try to extend into the aggregators */
          if (ret_value == FALSE && (f->shared->fs_strategy == H5F_FSPACE_STRATEGY_FSM_AGGR ||
                                     f->shared->fs_strategy == H5F_FSPACE_STRATEGY_AGGR)) {
              H5F_blk_aggr_t *aggr; /* Aggregator to use */
  
              /* Check if the block is able to extend into aggregation block */
              aggr = (map_type == H5FD_MEM_DRAW) ? &(f->shared->sdata_aggr) : &(f->shared->meta_aggr);
              if ((ret_value = H5MF__aggr_try_extend(f, aggr, map_type, end, extra_requested)) < 0)
                  HGOTO_ERROR(H5E_RESOURCE, H5E_CANTEXTEND, FAIL, "error extending aggregation block")
  
  #ifdef H5MF_ALLOC_DEBUG_MORE
              HDfprintf(stderr, "%s: H5MF__aggr_try_extend = %t\n", __func__, ret_value);
  #endif    /* H5MF_ALLOC_DEBUG_MORE */
          } /* end if */
  
          /* If no extension so far, try to extend into a free-space section */
          if (ret_value == FALSE &&
              ((f->shared->fs_strategy == H5F_FSPACE_STRATEGY_FSM_AGGR) || (H5F_PAGED_AGGR(f)))) {
              H5MF_sect_ud_t udata; /* User data */
  
              /* Construct user data for callbacks */
              udata.f          = f;
              udata.alloc_type = alloc_type;
  
              /* Check if the free space for the file has been initialized */
              if (!f->shared->fs_man[fs_type] && H5F_addr_defined(f->shared->fs_addr[fs_type]))
                  /* Open the free-space manager */
                  if (H5MF__open_fstype(f, fs_type) < 0)
                      HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space")
  
              /* Try to extend the block into a free-space section */
              if (f->shared->fs_man[fs_type]) {
                  if ((ret_value = H5FS_sect_try_extend(f, f->shared->fs_man[fs_type], addr, size,
                                                        extra_requested, H5FS_ADD_RETURNED_SPACE, &udata)) < 0)
                      HGOTO_ERROR(H5E_RESOURCE, H5E_CANTEXTEND, FAIL,
                                  "error extending block in free space manager")
  #ifdef H5MF_ALLOC_DEBUG_MORE
                  HDfprintf(stderr, "%s: Try to H5FS_sect_try_extend = %t\n", __func__, ret_value);
  #endif        /* H5MF_ALLOC_DEBUG_MORE */
              } /* end if */
  
              /* For paged aggregation and a metadata block: try to extend into page end threshold */
              if (ret_value == FALSE && H5F_PAGED_AGGR(f) && map_type != H5FD_MEM_DRAW) {
                  H5MF_EOA_MISALIGN(f, end, f->shared->fs_page_size, frag_size);
  
                  if (frag_size <= H5F_PGEND_META_THRES(f) && extra_requested <= frag_size)
                      ret_value = TRUE;
  #ifdef H5MF_ALLOC_DEBUG_MORE
                  HDfprintf(stderr, "%s: Try to extend into the page end threshold = %t\n", __func__,
                            ret_value);
  #endif        /* H5MF_ALLOC_DEBUG_MORE */
              } /* end if */
          }     /* end if */
      }         /* allow_extend */
  
  done:
      /* Reset the ring in the API context */
      if (orig_ring != H5AC_RING_INV)
          H5AC_set_ring(orig_ring, NULL);
  
  #ifdef H5MF_ALLOC_DEBUG
      HDfprintf(stderr, "%s: Leaving: ret_value = %t\n", __func__, ret_value);
  #endif /* H5MF_ALLOC_DEBUG */
  #ifdef H5MF_ALLOC_DEBUG_DUMP
      H5MF__sects_dump(f, stderr);
  #endif /* H5MF_ALLOC_DEBUG_DUMP */
  
      FUNC_LEAVE_NOAPI_TAG(ret_value)
  } /* end H5MF_try_extend() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5MF_try_shrink
   *
   * Purpose:     Try to shrink the size of a file with a block or absorb it
   *              into a block aggregator.
   *
   * Return:      Non-negative on success/Negative on failure
   *
   * Programmer:  Quincey Koziol
   *              Feb 14 2008
   *
   *-------------------------------------------------------------------------
   */
  htri_t
  H5MF_try_shrink(H5F_t *f, H5FD_mem_t alloc_type, haddr_t addr, hsize_t size)
  {
      H5MF_free_section_t *       node = NULL;               /* Free space section pointer */
      H5MF_sect_ud_t              udata;                     /* User data for callback */
      const H5FS_section_class_t *sect_cls;                  /* Section class */
      H5AC_ring_t                 orig_ring = H5AC_RING_INV; /* Original ring value */
      H5AC_ring_t                 fsm_ring  = H5AC_RING_INV; /* Ring of FSM */
      H5F_mem_page_t              fs_type;                   /* Free space type */
      htri_t                      ret_value = FALSE;         /* Return value */
  
      FUNC_ENTER_NOAPI_TAG(H5AC__FREESPACE_TAG, FAIL)
  #ifdef H5MF_ALLOC_DEBUG
      HDfprintf(stderr, "%s: Entering - alloc_type = %u, addr = %a, size = %Hu\n", __func__,
                (unsigned)alloc_type, addr, size);
  #endif /* H5MF_ALLOC_DEBUG */
  
      /* check arguments */
      HDassert(f);
      HDassert(f->shared);
      HDassert(f->shared->lf);
      HDassert(H5F_addr_defined(addr));
      HDassert(size > 0);
  
      /* Set up free-space section class information */
      sect_cls = H5MF_SECT_CLS_TYPE(f, size);
      HDassert(sect_cls);
  
      /* Get free space type from allocation type */
      H5MF__alloc_to_fs_type(f->shared, alloc_type, size, &fs_type);
  
      /* Set the ring type in the API context */
      if (H5MF__fsm_type_is_self_referential(f->shared, fs_type))
          fsm_ring = H5AC_RING_MDFSM;
      else
          fsm_ring = H5AC_RING_RDFSM;
      H5AC_set_ring(fsm_ring, &orig_ring);
  
      /* Create free-space section for block */
      if (NULL == (node = H5MF__sect_new(sect_cls->type, addr, size)))
          HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize free space section")
  
      /* Construct user data for callbacks */
      udata.f                     = f;
      udata.alloc_type            = alloc_type;
      udata.allow_sect_absorb     = FALSE; /* Force section to be absorbed into aggregator */
      udata.allow_eoa_shrink_only = FALSE;
  
      /* Check if the block can shrink the container */
      if (sect_cls->can_shrink) {
          if ((ret_value = (*sect_cls->can_shrink)((const H5FS_section_info_t *)node, &udata)) < 0)
              HGOTO_ERROR(H5E_RESOURCE, H5E_CANTMERGE, FAIL, "can't check if section can shrink container")
          if (ret_value > 0) {
              HDassert(sect_cls->shrink);
  
              if ((*sect_cls->shrink)((H5FS_section_info_t **)&node, &udata) < 0)
                  HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink container")
          } /* end if */
      }     /* end if */
  
  done:
      /* Reset the ring in the API context */
      if (orig_ring != H5AC_RING_INV)
          H5AC_set_ring(orig_ring, NULL);
  
      /* Free section node allocated */
      if (node && H5MF__sect_free((H5FS_section_info_t *)node) < 0)
          HDONE_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free simple section node")
  
  #ifdef H5MF_ALLOC_DEBUG
      HDfprintf(stderr, "%s: Leaving, ret_value = %d\n", __func__, ret_value);
  #endif /* H5MF_ALLOC_DEBUG */
      FUNC_LEAVE_NOAPI_TAG(ret_value)
  } /* end H5MF_try_shrink() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5MF_close
   *
   * Purpose:     Close the free space tracker(s) for a file:
   *              paged or non-paged aggregation
   *
   * Return:	SUCCEED/FAIL
   *
   * Programmer:  Vailin Choi; Dec 2012
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5MF_close(H5F_t *f)
  {
      herr_t ret_value = SUCCEED; /* Return value */
  
      FUNC_ENTER_NOAPI_TAG(H5AC__FREESPACE_TAG, FAIL)
  #ifdef H5MF_ALLOC_DEBUG
      HDfprintf(stderr, "%s: Entering\n", __func__);
  #endif /* H5MF_ALLOC_DEBUG */
  
      /* check args */
      HDassert(f);
      HDassert(f->shared);
  
      if (H5F_PAGED_AGGR(f)) {
          if ((ret_value = H5MF__close_pagefs(f)) < 0)
              HGOTO_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, "can't close free-space managers for 'page' file space")
      }
      else {
          if ((ret_value = H5MF__close_aggrfs(f)) < 0)
              HGOTO_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, "can't close free-space managers for 'aggr' file space")
      }
  
  done:
  #ifdef H5MF_ALLOC_DEBUG
      HDfprintf(stderr, "%s: Leaving\n", __func__);
  #endif /* H5MF_ALLOC_DEBUG */
      FUNC_LEAVE_NOAPI_TAG(ret_value)
  } /* end H5MF_close() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5MF__close_delete_fstype
   *
   * Purpose:     Common code for closing and deleting the freespace manager
   *              of TYPE for file.
   *              Note that TYPE can be H5F_mem_page_t or H5FD_mem_t enum types.
   *
   * Return:	SUCCEED/FAIL
   *
   * Programmer:	Vailin Choi
   *              Jan 2016
   *
   *-------------------------------------------------------------------------
   */
  static herr_t
  H5MF__close_delete_fstype(H5F_t *f, H5F_mem_page_t type)
  {
      herr_t ret_value = SUCCEED; /* Return value */
  
      FUNC_ENTER_STATIC
  #ifdef H5MF_ALLOC_DEBUG
      HDfprintf(stderr, "%s: Entering\n", __func__);
  #endif /* H5MF_ALLOC_DEBUG */
  
      /* check args */
      HDassert(f);
      HDassert(f->shared);
      if (H5F_PAGED_AGGR(f))
          HDassert(type < H5F_MEM_PAGE_NTYPES);
      else
          HDassert((H5FD_mem_t)type < H5FD_MEM_NTYPES);
  
  #ifdef H5MF_ALLOC_DEBUG_MORE
      HDfprintf(stderr, "%s: Check 1.0 - f->shared->fs_man[%u] = %p, f->shared->fs_addr[%u] = %a\n", __func__,
                (unsigned)type, f->shared->fs_man[type], (unsigned)type, f->shared->fs_addr[type]);
  #endif /* H5MF_ALLOC_DEBUG_MORE */
  
      /* If the free space manager for this type is open, close it */
      if (f->shared->fs_man[type])
          if (H5MF__close_fstype(f, type) < 0)
              HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't close the free space manager")
  
  #ifdef H5MF_ALLOC_DEBUG_MORE
      HDfprintf(stderr, "%s: Check 2.0 - f->shared->fs_man[%u] = %p, f->shared->fs_addr[%u] = %a\n", __func__,
                (unsigned)type, f->shared->fs_man[type], (unsigned)type, f->shared->fs_addr[type]);
  #endif /* H5MF_ALLOC_DEBUG_MORE */
  
      /* If there is free space manager info for this type, delete it */
      if (H5F_addr_defined(f->shared->fs_addr[type]))
          if (H5MF__delete_fstype(f, type) < 0)
              HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't delete the free space manager")
  
  done:
  #ifdef H5MF_ALLOC_DEBUG
      HDfprintf(stderr, "%s: Leaving\n", __func__);
  #endif /* H5MF_ALLOC_DEBUG */
      FUNC_LEAVE_NOAPI(ret_value)
  } /* H5MF__close_delete() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5MF_try_close
   *
   * Purpose:     This is called by H5Fformat_convert() to close and delete
   *              free-space managers when downgrading persistent free-space
   *              to non-persistent.
   *
   * Return:	SUCCEED/FAIL
   *
   * Programmer:	Vailin Choi
   *              Jan 2016
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5MF_try_close(H5F_t *f)
  {
      H5AC_ring_t orig_ring   = H5AC_RING_INV; /* Original ring value */
      H5AC_ring_t curr_ring   = H5AC_RING_INV; /* Current ring value */
      H5AC_ring_t needed_ring = H5AC_RING_INV; /* Ring value needed for this iteration */
      herr_t      ret_value   = SUCCEED;       /* Return value */
  
      FUNC_ENTER_NOAPI_TAG(H5AC__FREESPACE_TAG, FAIL)
  #ifdef H5MF_ALLOC_DEBUG
      HDfprintf(stderr, "%s: Entering\n", __func__);
  #endif /* H5MF_ALLOC_DEBUG */
  
      /* check args */
      HDassert(f);
  
      /* If there have been no file space allocations / deallocation so
       * far, must call H5MF_tidy_self_referential_fsm_hack() to float
       * all self referential FSMs and release file space allocated to
       * them.  Otherwise, the function will be called after the format
       * conversion, and will become very confused.
       *
       * The situation is further complicated if a cache image exists
       * and had not yet been loaded into the metadata cache.  In this
       * case, call H5AC_force_cache_image_load() instead of
       * H5MF_tidy_self_referential_fsm_hack().  H5AC_force_cache_image_load()
       * will load the cache image, and then call
       * H5MF_tidy_self_referential_fsm_hack() to discard the cache image
       * block.
       */
  
      /* Set the ring type in the API context.  In most cases, we will
       * need H5AC_RING_RDFSM, so initially set the ring in
       * the context to that value.  We will alter this later if needed.
       */
      H5AC_set_ring(H5AC_RING_RDFSM, &orig_ring);
      curr_ring = H5AC_RING_RDFSM;
  
      if (H5F_PAGED_AGGR(f)) {
          H5F_mem_page_t ptype; /* Memory type for iteration */
  
          /* Iterate over all the free space types that have managers and
           * get each free list's space
           */
          for (ptype = H5F_MEM_PAGE_META; ptype < H5F_MEM_PAGE_NTYPES; ptype++) {
              /* Test to see if we need to switch rings -- do so if required */
              if (H5MF__fsm_type_is_self_referential(f->shared, ptype))
                  needed_ring = H5AC_RING_MDFSM;
              else
                  needed_ring = H5AC_RING_RDFSM;
  
              if (needed_ring != curr_ring) {
                  H5AC_set_ring(needed_ring, NULL);
                  curr_ring = needed_ring;
              } /* end if */
  
              if (H5MF__close_delete_fstype(f, ptype) < 0)
                  HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't close the free space manager")
          } /* end for */
      }     /* end if */
      else {
          H5FD_mem_t type; /* Memory type for iteration */
  
          /* Iterate over all the free space types that have managers and
           * get each free list's space
           */
          for (type = H5FD_MEM_DEFAULT; type < H5FD_MEM_NTYPES; type++) {
              /* Test to see if we need to switch rings -- do so if required */
              if (H5MF__fsm_type_is_self_referential(f->shared, (H5F_mem_page_t)type))
                  needed_ring = H5AC_RING_MDFSM;
              else
                  needed_ring = H5AC_RING_RDFSM;
  
              if (needed_ring != curr_ring) {
                  H5AC_set_ring(needed_ring, NULL);
                  curr_ring = needed_ring;
              } /* end if */
  
              if (H5MF__close_delete_fstype(f, (H5F_mem_page_t)type) < 0)
                  HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't close the free space manager")
          } /* end for */
      }     /* end else */
  
  done:
      /* Reset the ring in the API context */
      if (orig_ring != H5AC_RING_INV)
          H5AC_set_ring(orig_ring, NULL);
  
  #ifdef H5MF_ALLOC_DEBUG
      HDfprintf(stderr, "%s: Leaving\n", __func__);
  #endif /* H5MF_ALLOC_DEBUG */
      FUNC_LEAVE_NOAPI_TAG(ret_value)
  } /* H5MF_try_close() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5MF__close_aggrfs
   *
   * Purpose:     Close the free space tracker(s) for a file: non-paged aggregation
   *
   * Return:      SUCCEED/FAIL
   *
   * Programmer:  Quincey Koziol
   *              Tuesday, January 22, 2008
   *
   *-------------------------------------------------------------------------
   */
  static herr_t
  H5MF__close_aggrfs(H5F_t *f)
  {
      H5AC_ring_t orig_ring   = H5AC_RING_INV; /* Original ring value */
      H5AC_ring_t curr_ring   = H5AC_RING_INV; /* Current ring value */
      H5AC_ring_t needed_ring = H5AC_RING_INV; /* Ring value needed for this iteration.  */
      H5FD_mem_t  type;                        /* Memory type for iteration */
      herr_t      ret_value = SUCCEED;         /* Return value */
  
      FUNC_ENTER_STATIC
  #ifdef H5MF_ALLOC_DEBUG
      HDfprintf(stderr, "%s: Entering\n", __func__);
  #endif /* H5MF_ALLOC_DEBUG */
  
      /* check args */
      HDassert(f);
      HDassert(f->shared);
      HDassert(f->shared->lf);
      HDassert(f->shared->sblock);
  
      /* Set the ring type in the API context.  In most cases, we will
       * need H5AC_RING_RDFSM, so initially set the ring in
       * the context to that value.  We will alter this later if needed.
       */
      H5AC_set_ring(H5AC_RING_RDFSM, &orig_ring);
      curr_ring = H5AC_RING_RDFSM;
  
      /* Free the space in aggregators */
      /* (for space not at EOA, it may be put into free space managers) */
      if (H5MF_free_aggrs(f) < 0)
          HGOTO_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, "can't free aggregators")
  
      /* Trying shrinking the EOA for the file */
      if (H5MF__close_shrink_eoa(f) < 0)
          HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink eoa")
  
      /* Making free-space managers persistent for superblock version >= 2 */
      if (f->shared->sblock->super_vers >= HDF5_SUPERBLOCK_VERSION_2 && f->shared->fs_persist) {
          H5O_fsinfo_t   fsinfo;    /* File space info message */
          haddr_t        final_eoa; /* Final eoa -- for sanity check */
          H5F_mem_page_t ptype;     /* Memory type for iteration */
  
          /* superblock extension and free space manager message should
           * exist at this point -- verify at least the former.
           */
          HDassert(H5F_addr_defined(f->shared->sblock->ext_addr));
  
          /* file space for all non-empty free space managers should be
           * allocated at this point, and these free space managers should
           * be written to file and thus their headers and section info
           * entries in the metadata cache should be clean.
           */
  
          /* gather data for the free space manager superblock extension message.
           *
           * In passing, verify that all the free space managers are closed.
           */
          for (ptype = H5F_MEM_PAGE_META; ptype < H5F_MEM_PAGE_NTYPES; ptype++)
              fsinfo.fs_addr[ptype - 1] = HADDR_UNDEF;
          for (type = H5FD_MEM_SUPER; type < H5FD_MEM_NTYPES; type++)
              fsinfo.fs_addr[type - 1] = f->shared->fs_addr[type];
          fsinfo.strategy            = f->shared->fs_strategy;
          fsinfo.persist             = f->shared->fs_persist;
          fsinfo.threshold           = f->shared->fs_threshold;
          fsinfo.page_size           = f->shared->fs_page_size;
          fsinfo.pgend_meta_thres    = f->shared->pgend_meta_thres;
          fsinfo.eoa_pre_fsm_fsalloc = f->shared->eoa_fsm_fsalloc;
          fsinfo.version             = f->shared->fs_version;
  
          /* Write the free space manager message -- message must already exist */
          if (H5F__super_ext_write_msg(f, H5O_FSINFO_ID, &fsinfo, FALSE, H5O_MSG_FLAG_MARK_IF_UNKNOWN) < 0)
              HGOTO_ERROR(H5E_RESOURCE, H5E_WRITEERROR, FAIL,
                          "error in writing message to superblock extension")
  
          /* Close the free space managers */
          for (type = H5FD_MEM_SUPER; type < H5FD_MEM_NTYPES; type++) {
              if (f->shared->fs_man[type]) {
                  /* Test to see if we need to switch rings -- do so if required */
                  if (H5MF__fsm_type_is_self_referential(f->shared, (H5F_mem_page_t)type))
                      needed_ring = H5AC_RING_MDFSM;
                  else
                      needed_ring = H5AC_RING_RDFSM;
  
                  if (needed_ring != curr_ring) {
                      H5AC_set_ring(needed_ring, NULL);
                      curr_ring = needed_ring;
                  } /* end if */
  
                  HDassert(f->shared->fs_state[type] == H5F_FS_STATE_OPEN);
  
                  if (H5FS_close(f, f->shared->fs_man[type]) < 0)
                      HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't close free space manager")
                  f->shared->fs_man[type]   = NULL;
                  f->shared->fs_state[type] = H5F_FS_STATE_CLOSED;
              } /* end if */
              f->shared->fs_addr[type] = HADDR_UNDEF;
          } /* end for */
  
          /* verify that we haven't dirtied any metadata cache entries
           * from the metadata free space manager ring out.
           */
          HDassert(H5AC_cache_is_clean(f, H5AC_RING_MDFSM));
  
          /* verify that the aggregators are still shutdown. */
          HDassert(f->shared->sdata_aggr.tot_size == 0);
          HDassert(f->shared->sdata_aggr.addr == 0);
          HDassert(f->shared->sdata_aggr.size == 0);
  
          HDassert(f->shared->meta_aggr.tot_size == 0);
          HDassert(f->shared->meta_aggr.addr == 0);
          HDassert(f->shared->meta_aggr.size == 0);
  
          /* Trying shrinking the EOA for the file */
          /* (in case any free space is now at the EOA) */
          if (H5MF__close_shrink_eoa(f) < 0)
              HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink eoa")
  
          /* get the eoa, and verify that it has the expected value */
          if (HADDR_UNDEF == (final_eoa = H5FD_get_eoa(f->shared->lf, H5FD_MEM_DEFAULT)))
              HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to get file size")
  
          /* f->shared->eoa_post_fsm_fsalloc is undefined if there has
           * been no file space allocation or deallocation since file
           * open.
           */
          HDassert(H5F_NULL_FSM_ADDR(f) || final_eoa == f->shared->eoa_fsm_fsalloc);
      }      /* end if */
      else { /* super_vers can be 0, 1, 2 */
          for (type = H5FD_MEM_DEFAULT; type < H5FD_MEM_NTYPES; type++)
              if (H5MF__close_delete_fstype(f, (H5F_mem_page_t)type) < 0)
                  HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space")
      } /* end else */
  
      /* Free the space in aggregators (again) */
      /* (in case any free space information re-started them) */
      if (H5MF_free_aggrs(f) < 0)
          HGOTO_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, "can't free aggregators")
  
      /* Trying shrinking the EOA for the file */
      /* (in case any free space is now at the EOA) */
      if (H5MF__close_shrink_eoa(f) < 0)
          HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink eoa")
  
  done:
      /* Reset the ring in the API context */
      if (orig_ring != H5AC_RING_INV)
          H5AC_set_ring(orig_ring, NULL);
  
  #ifdef H5MF_ALLOC_DEBUG
      HDfprintf(stderr, "%s: Leaving\n", __func__);
  #endif /* H5MF_ALLOC_DEBUG */
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5MF__close_aggrfs() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5MF__close_pagefs
   *
   * Purpose:     Close the free space tracker(s) for a file: paged aggregation
   *
   * Return:      SUCCEED/FAIL
   *
   * Programmer:  Vailin Choi; Dec 2012
   *
   *-------------------------------------------------------------------------
   */
  static herr_t
  H5MF__close_pagefs(H5F_t *f)
  {
      H5AC_ring_t    orig_ring   = H5AC_RING_INV; /* Original ring value */
      H5AC_ring_t    curr_ring   = H5AC_RING_INV; /* Current ring value */
      H5AC_ring_t    needed_ring = H5AC_RING_INV; /* Ring value needed for this iteration.  */
      H5F_mem_page_t ptype;                       /* Memory type for iteration */
      H5O_fsinfo_t   fsinfo;                      /* File space info message */
      herr_t         ret_value = SUCCEED;         /* Return value */
  
      FUNC_ENTER_STATIC
  #ifdef H5MF_ALLOC_DEBUG
      HDfprintf(stderr, "%s: Entering\n", __func__);
  #endif /* H5MF_ALLOC_DEBUG */
  
      /* check args */
      HDassert(f);
      HDassert(f->shared);
      HDassert(f->shared->lf);
      HDassert(f->shared->sblock);
      HDassert(f->shared->fs_page_size);
      HDassert(f->shared->sblock->super_vers >= HDF5_SUPERBLOCK_VERSION_2);
  
      /* Set the ring type in the API context.  In most cases, we will
       * need H5AC_RING_RDFSM, so initially set the ring in
       * the context to that value.  We will alter this later if needed.
       */
      H5AC_set_ring(H5AC_RING_RDFSM, &orig_ring);
      curr_ring = H5AC_RING_RDFSM;
  
      /* Trying shrinking the EOA for the file */
      if (H5MF__close_shrink_eoa(f) < 0)
          HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink eoa")
  
      /* Set up file space info message */
      fsinfo.strategy            = f->shared->fs_strategy;
      fsinfo.persist             = f->shared->fs_persist;
      fsinfo.threshold           = f->shared->fs_threshold;
      fsinfo.page_size           = f->shared->fs_page_size;
      fsinfo.pgend_meta_thres    = f->shared->pgend_meta_thres;
      fsinfo.eoa_pre_fsm_fsalloc = HADDR_UNDEF;
      fsinfo.version             = f->shared->fs_version;
  
      for (ptype = H5F_MEM_PAGE_META; ptype < H5F_MEM_PAGE_NTYPES; ptype++)
          fsinfo.fs_addr[ptype - 1] = HADDR_UNDEF;
  
      if (f->shared->fs_persist) {
          haddr_t final_eoa; /* final eoa -- for sanity check */
  
          /* superblock extension and free space manager message should
           * exist at this point -- verify at least the former.
           */
          HDassert(H5F_addr_defined(f->shared->sblock->ext_addr));
  
          /* file space for all non-empty free space managers should be
           * allocated at this point, and these free space managers should
           * be written to file and thus their headers and section info
           * entries in the metadata cache should be clean.
           */
  
          /* gather data for the free space manager superblock extension message.
           * Only need addresses of FSMs and eoa prior to allocation of
           * file space for the self referential free space managers.  Other
           * data was gathered above.
           */
          for (ptype = H5F_MEM_PAGE_META; ptype < H5F_MEM_PAGE_NTYPES; ptype++)
              fsinfo.fs_addr[ptype - 1] = f->shared->fs_addr[ptype];
          fsinfo.eoa_pre_fsm_fsalloc = f->shared->eoa_fsm_fsalloc;
  
          /* Write the free space manager message -- message must already exist */
          if (H5F__super_ext_write_msg(f, H5O_FSINFO_ID, &fsinfo, FALSE, H5O_MSG_FLAG_MARK_IF_UNKNOWN) < 0)
              HGOTO_ERROR(H5E_RESOURCE, H5E_WRITEERROR, FAIL,
                          "error in writing message to superblock extension")
  
          /* Close the free space managers */
          /* use H5MF__close_fstype() for this? */
          for (ptype = H5F_MEM_PAGE_META; ptype < H5F_MEM_PAGE_NTYPES; ptype++) {
              if (f->shared->fs_man[ptype]) {
                  /* Test to see if we need to switch rings -- do so if required */
                  if (H5MF__fsm_type_is_self_referential(f->shared, ptype))
                      needed_ring = H5AC_RING_MDFSM;
                  else
                      needed_ring = H5AC_RING_RDFSM;
  
                  if (needed_ring != curr_ring) {
                      H5AC_set_ring(needed_ring, NULL);
                      curr_ring = needed_ring;
                  } /* end if */
  
                  HDassert(f->shared->fs_state[ptype] == H5F_FS_STATE_OPEN);
  
                  if (H5FS_close(f, f->shared->fs_man[ptype]) < 0)
                      HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't close free space manager")
                  f->shared->fs_man[ptype]   = NULL;
                  f->shared->fs_state[ptype] = H5F_FS_STATE_CLOSED;
              } /* end if */
              f->shared->fs_addr[ptype] = HADDR_UNDEF;
          } /* end for */
  
          /* verify that we haven't dirtied any metadata cache entries
           * from the metadata free space manager ring out.
           */
          HDassert(H5AC_cache_is_clean(f, H5AC_RING_MDFSM));
  
          /* Trying shrinking the EOA for the file */
          /* (in case any free space is now at the EOA) */
          if (H5MF__close_shrink_eoa(f) < 0)
              HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink eoa")
  
          /* get the eoa, and verify that it has the expected value */
          if (HADDR_UNDEF == (final_eoa = H5FD_get_eoa(f->shared->lf, H5FD_MEM_DEFAULT)))
              HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to get file size")
  
          /* f->shared->eoa_post_fsm_fsalloc is undefined if there has
           * been no file space allocation or deallocation since file
           * open.
           *
           * If there is a cache image in the file at file open,
           * f->shared->first_alloc_dealloc will always be FALSE unless
           * the file is opened R/O, as otherwise, the image will have been
           * read and discarded by this point.
           *
           * If a cache image was created on file close, the actual EOA
           * should be in f->shared->eoa_post_mdci_fsalloc.  Note that in
           * this case, it is conceivable that f->shared->first_alloc_dealloc
           * will still be TRUE, as the cache image is allocated directly from
           * the file driver layer.  However, as this possibility seems remote,
           * it is ignored in the following assert.
           */
          HDassert((H5F_NULL_FSM_ADDR(f)) || (final_eoa == f->shared->eoa_fsm_fsalloc) ||
                   ((H5F_addr_defined(f->shared->eoa_post_mdci_fsalloc)) &&
                    (final_eoa == f->shared->eoa_post_mdci_fsalloc)));
      } /* end if */
      else {
          /* Iterate over all the free space types that have managers
           * and get each free list's space
           */
          for (ptype = H5F_MEM_PAGE_META; ptype < H5F_MEM_PAGE_NTYPES; ptype++)
              if (H5MF__close_delete_fstype(f, ptype) < 0)
                  HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't close the free space manager")
  
          /* Write file space info message to superblock extension object header */
          /* Create the superblock extension object header in advance if needed */
          if (H5F__super_ext_write_msg(f, H5O_FSINFO_ID, &fsinfo, FALSE, H5O_MSG_FLAG_MARK_IF_UNKNOWN) < 0)
              HGOTO_ERROR(H5E_RESOURCE, H5E_WRITEERROR, FAIL,
                          "error in writing message to superblock extension")
      } /* end else */
  
      /* Trying shrinking the EOA for the file */
      /* (in case any free space is now at the EOA) */
      if (H5MF__close_shrink_eoa(f) < 0)
          HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink eoa")
  
  done:
      /* Reset the ring in the API context */
      if (orig_ring != H5AC_RING_INV)
          H5AC_set_ring(orig_ring, NULL);
  
  #ifdef H5MF_ALLOC_DEBUG
      HDfprintf(stderr, "%s: Leaving\n", __func__);
  #endif /* H5MF_ALLOC_DEBUG */
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5MF__close_pagefs() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5MF__close_shrink_eoa
   *
   * Purpose:     Shrink the EOA while closing
   *
   * Return:	SUCCEED/FAIL
   *
   * Programmer:  Quincey Koziol
   *              Saturday, July 7, 2012
   *
   *-------------------------------------------------------------------------
   */
  static herr_t
  H5MF__close_shrink_eoa(H5F_t *f)
  {
      H5AC_ring_t    orig_ring   = H5AC_RING_INV; /* Original ring value */
      H5AC_ring_t    curr_ring   = H5AC_RING_INV; /* Current ring value */
      H5AC_ring_t    needed_ring = H5AC_RING_INV; /* Ring value needed for this iteration.  */
      H5F_mem_t      type;
      H5F_mem_page_t ptype;               /* Memory type for iteration */
      hbool_t        eoa_shrank;          /* Whether an EOA shrink occurs */
      htri_t         status;              /* Status value */
      H5MF_sect_ud_t udata;               /* User data for callback */
      herr_t         ret_value = SUCCEED; /* Return value */
  
      FUNC_ENTER_STATIC
  
      /* check args */
      HDassert(f);
      HDassert(f->shared);
  
      /* Construct user data for callbacks */
      udata.f                     = f;
      udata.allow_sect_absorb     = FALSE;
      udata.allow_eoa_shrink_only = TRUE;
  
      /* Set the ring type in the API context */
      H5AC_set_ring(H5AC_RING_RDFSM, &orig_ring);
      curr_ring = H5AC_RING_RDFSM;
  
      /* Iterate until no more EOA shrinking occurs */
      do {
          eoa_shrank = FALSE;
  
          if (H5F_PAGED_AGGR(f)) {
              /* Check the last section of each free-space manager */
              for (ptype = H5F_MEM_PAGE_META; ptype < H5F_MEM_PAGE_NTYPES; ptype++) {
                  if (f->shared->fs_man[ptype]) {
                      /* Test to see if we need to switch rings -- do so if required */
                      if (H5MF__fsm_type_is_self_referential(f->shared, ptype))
                          needed_ring = H5AC_RING_MDFSM;
                      else
                          needed_ring = H5AC_RING_RDFSM;
  
                      if (needed_ring != curr_ring) {
                          H5AC_set_ring(needed_ring, NULL);
                          curr_ring = needed_ring;
                      } /* end if */
  
                      udata.alloc_type = (H5FD_mem_t)(
                          (H5FD_mem_t)ptype < H5FD_MEM_NTYPES ? ptype : ((ptype % H5FD_MEM_NTYPES) + 1));
  
                      if ((status = H5FS_sect_try_shrink_eoa(f, f->shared->fs_man[ptype], &udata)) < 0)
                          HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't check for shrinking eoa")
                      else if (status > 0)
                          eoa_shrank = TRUE;
                  } /* end if */
              }     /* end for */
          }         /* end if */
          else {
              /* Check the last section of each free-space manager */
              for (type = H5FD_MEM_DEFAULT; type < H5FD_MEM_NTYPES; type++) {
                  if (f->shared->fs_man[type]) {
                      /* Test to see if we need to switch rings -- do so if required */
                      if (H5MF__fsm_type_is_self_referential(f->shared, (H5F_mem_page_t)type))
                          needed_ring = H5AC_RING_MDFSM;
                      else
                          needed_ring = H5AC_RING_RDFSM;
  
                      if (needed_ring != curr_ring) {
                          H5AC_set_ring(needed_ring, NULL);
                          curr_ring = needed_ring;
                      } /* end if */
  
                      udata.alloc_type = type;
  
                      if ((status = H5FS_sect_try_shrink_eoa(f, f->shared->fs_man[type], &udata)) < 0)
                          HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't check for shrinking eoa")
                      else if (status > 0)
                          eoa_shrank = TRUE;
                  } /* end if */
              }     /* end for */
  
              /* check the two aggregators */
              if ((status = H5MF__aggrs_try_shrink_eoa(f)) < 0)
                  HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't check for shrinking eoa")
              else if (status > 0)
                  eoa_shrank = TRUE;
          } /* end else */
      } while (eoa_shrank);
  
  done:
      /* Reset the ring in the API context */
      if (orig_ring != H5AC_RING_INV)
          H5AC_set_ring(orig_ring, NULL);
  
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5MF__close_shrink_eoa() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5MF_get_freespace
   *
   * Purpose:     Retrieve the amount of free space in the file
   *
   * Return:      Success:        Amount of free space in file
   *              Failure:        Negative
   *
   * Programmer:  Quincey Koziol
   *              Monday, October  6, 2003
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5MF_get_freespace(H5F_t *f, hsize_t *tot_space, hsize_t *meta_size)
  {
      haddr_t        ma_addr       = HADDR_UNDEF; /* Base "metadata aggregator" address */
      hsize_t        ma_size       = 0;           /* Size of "metadata aggregator" */
      haddr_t        sda_addr      = HADDR_UNDEF; /* Base "small data aggregator" address */
      hsize_t        sda_size      = 0;           /* Size of "small data aggregator" */
      hsize_t        tot_fs_size   = 0;           /* Amount of all free space managed */
      hsize_t        tot_meta_size = 0;           /* Amount of metadata for free space managers */
      H5FD_mem_t     tt;                          /* Memory type for iteration */
      H5F_mem_page_t type;                        /* Memory type for iteration */
      H5F_mem_page_t start_type;                  /* Memory type for iteration */
      H5F_mem_page_t end_type;                    /* Memory type for iteration */
      htri_t  fs_started[H5F_MEM_PAGE_NTYPES];    /* Indicate whether the free-space manager has been started */
      haddr_t fs_eoa[H5FD_MEM_NTYPES];            /* EAO for each free-space manager */
      H5AC_ring_t orig_ring   = H5AC_RING_INV;    /* Original ring value */
      H5AC_ring_t curr_ring   = H5AC_RING_INV;    /* Current ring value */
      H5AC_ring_t needed_ring = H5AC_RING_INV;    /* Ring value needed for this iteration.  */
      herr_t      ret_value   = SUCCEED;          /* Return value */
  
      FUNC_ENTER_NOAPI_TAG(H5AC__FREESPACE_TAG, FAIL)
  
      /* check args */
      HDassert(f);
      HDassert(f->shared);
      HDassert(f->shared->lf);
  
      /* Set the ring type in the API context.  In most cases, we will
       * need H5AC_RING_RDFSM, so initially set the ring in
       * the context to that value.  We will alter this later if needed.
       */
      H5AC_set_ring(H5AC_RING_RDFSM, &orig_ring);
      curr_ring = H5AC_RING_RDFSM;
  
      /* Determine start/end points for loop */
      if (H5F_PAGED_AGGR(f)) {
          start_type = H5F_MEM_PAGE_META;
          end_type   = H5F_MEM_PAGE_NTYPES;
      } /* end if */
      else {
          start_type = (H5F_mem_page_t)H5FD_MEM_SUPER;
          end_type   = (H5F_mem_page_t)H5FD_MEM_NTYPES;
      } /* end else */
  
      for (tt = H5FD_MEM_SUPER; tt < H5FD_MEM_NTYPES; tt++)
          if (HADDR_UNDEF == (fs_eoa[tt] = H5F_get_eoa(f, tt)))
              HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "driver get_eoa request failed")
  
      if (!H5F_PAGED_AGGR(f)) {
          /* Retrieve metadata aggregator info, if available */
          if (H5MF__aggr_query(f, &(f->shared->meta_aggr), &ma_addr, &ma_size) < 0)
              HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query metadata aggregator stats")
  
          /* Retrieve 'small data' aggregator info, if available */
          if (H5MF__aggr_query(f, &(f->shared->sdata_aggr), &sda_addr, &sda_size) < 0)
              HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query small data aggregator stats")
      } /* end if */
  
      /* Iterate over all the free space types that have managers and get each free list's space */
      for (type = start_type; type < end_type; type++) {
          fs_started[type] = FALSE;
  
          /* Check if the free space for the file has been initialized */
          if (!f->shared->fs_man[type] && H5F_addr_defined(f->shared->fs_addr[type])) {
              if (H5MF__open_fstype(f, type) < 0)
                  HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space")
              HDassert(f->shared->fs_man[type]);
              fs_started[type] = TRUE;
          } /* end if */
  
          /* Test to see if we need to switch rings -- do so if required */
          if (H5MF__fsm_type_is_self_referential(f->shared, (H5F_mem_page_t)type))
              needed_ring = H5AC_RING_MDFSM;
          else
              needed_ring = H5AC_RING_RDFSM;
  
          if (needed_ring != curr_ring) {
              H5AC_set_ring(needed_ring, NULL);
              curr_ring = needed_ring;
          } /* end if */
  
          /* Check if there's free space of this type */
          if (f->shared->fs_man[type]) {
              hsize_t type_fs_size   = 0; /* Amount of free space managed for each type */
              hsize_t type_meta_size = 0; /* Amount of free space metadata for each type */
  
              /* Retrieve free space size from free space manager */
              if (H5FS_sect_stats(f->shared->fs_man[type], &type_fs_size, NULL) < 0)
                  HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query free space stats")
              if (H5FS_size(f->shared->fs_man[type], &type_meta_size) < 0)
                  HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query free space metadata stats")
  
              /* Increment total free space for types */
              tot_fs_size += type_fs_size;
              tot_meta_size += type_meta_size;
          } /* end if */
      }     /* end for */
  
      /* Close the free-space managers if they were opened earlier in this routine */
      for (type = start_type; type < end_type; type++) {
          /* Test to see if we need to switch rings -- do so if required */
          if (H5MF__fsm_type_is_self_referential(f->shared, (H5F_mem_page_t)type))
              needed_ring = H5AC_RING_MDFSM;
          else
              needed_ring = H5AC_RING_RDFSM;
  
          if (needed_ring != curr_ring) {
              H5AC_set_ring(needed_ring, &curr_ring);
              curr_ring = needed_ring;
          } /* end if */
  
          if (fs_started[type])
              if (H5MF__close_fstype(f, type) < 0)
                  HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't close file free space")
      } /* end for */
  
      /* Set the value(s) to return */
      /* (The metadata & small data aggregators count as free space now, since they aren't at EOA) */
      if (tot_space)
          *tot_space = tot_fs_size + ma_size + sda_size;
      if (meta_size)
          *meta_size = tot_meta_size;
  
  done:
      /* Reset the ring in the API context */
      if (orig_ring != H5AC_RING_INV)
          H5AC_set_ring(orig_ring, NULL);
  
      FUNC_LEAVE_NOAPI_TAG(ret_value)
  } /* end H5MF_get_freespace() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5MF_get_free_sections()
   *
   * Purpose: 	To retrieve free-space section information for
   *              paged or non-paged aggregation
   *
   * Return:	SUCCEED/FAIL
   *
   * Programmer:  Vailin Choi; Dec 2012
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5MF_get_free_sections(H5F_t *f, H5FD_mem_t type, size_t nsects, H5F_sect_info_t *sect_info,
                         size_t *sect_count)
  {
      H5AC_ring_t         orig_ring   = H5AC_RING_INV; /* Original ring value */
      H5AC_ring_t         curr_ring   = H5AC_RING_INV; /* Current ring value */
      H5AC_ring_t         needed_ring = H5AC_RING_INV; /* Ring value needed for this iteration.  */
      size_t              total_sects = 0;             /* Total number of sections */
      H5MF_sect_iter_ud_t sect_udata;                  /* User data for callback */
      H5F_mem_page_t      start_type, end_type;        /* Memory types to iterate over */
      H5F_mem_page_t      ty;                          /* Memory type for iteration */
      herr_t              ret_value = SUCCEED;         /* Return value */
  
      FUNC_ENTER_NOAPI_TAG(H5AC__FREESPACE_TAG, FAIL)
  
      /* check args */
      HDassert(f);
      HDassert(f->shared);
      HDassert(f->shared->lf);
  
      /* H5MF_tidy_self_referential_fsm_hack() will fail if any self
       * referential FSM is opened prior to the call to it.  Thus call
       * it here if necessary and if it hasn't been called already.
       *
       * The situation is further complicated if a cache image exists
       * and had not yet been loaded into the metadata cache.  In this
       * case, call H5AC_force_cache_image_load() instead of
       * H5MF_tidy_self_referential_fsm_hack().  H5AC_force_cache_image_load()
       * will load the cache image, and then call
       * H5MF_tidy_self_referential_fsm_hack() to discard the cache image
       * block.
       */
  
      if (type == H5FD_MEM_DEFAULT) {
          start_type = H5F_MEM_PAGE_SUPER;
          end_type   = H5F_MEM_PAGE_NTYPES;
      } /* end if */
      else {
          start_type = end_type = (H5F_mem_page_t)type;
          if (H5F_PAGED_AGGR(f)) /* set to the corresponding LARGE free-space manager */
              end_type = (H5F_mem_page_t)(end_type + H5FD_MEM_NTYPES);
          else
              end_type++;
      } /* end else */
  
      /* Set up user data for section iteration */
      sect_udata.sects      = sect_info;
      sect_udata.sect_count = nsects;
      sect_udata.sect_idx   = 0;
  
      /* Set the ring type in the API context.  In most cases, we will
       * need H5AC_RING_RDFSM, so initially set the ring in
       * the context to that value.  We will alter this later if needed.
       */
      H5AC_set_ring(H5AC_RING_RDFSM, &orig_ring);
      curr_ring = H5AC_RING_RDFSM;
  
      /* Iterate over memory types, retrieving the number of sections of each type */
      for (ty = start_type; ty < end_type; ty++) {
          hbool_t fs_started = FALSE; /* The free-space manager is opened or not */
          size_t  nums       = 0;     /* The number of free-space sections */
  
          /* Test to see if we need to switch rings -- do so if required */
          if (H5MF__fsm_type_is_self_referential(f->shared, ty))
              needed_ring = H5AC_RING_MDFSM;
          else
              needed_ring = H5AC_RING_RDFSM;
  
          if (needed_ring != curr_ring) {
              H5AC_set_ring(needed_ring, &curr_ring);
              curr_ring = needed_ring;
          } /* end if */
  
          if (!f->shared->fs_man[ty] && H5F_addr_defined(f->shared->fs_addr[ty])) {
              if (H5MF__open_fstype(f, ty) < 0)
                  HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't open the free space manager")
              HDassert(f->shared->fs_man[ty]);
              fs_started = TRUE;
          } /* end if */
  
          /* Check if there's free space sections of this type */
          if (f->shared->fs_man[ty])
              if (H5MF__get_free_sects(f, f->shared->fs_man[ty], &sect_udata, &nums) < 0)
                  HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL,
                              "can't get section info for the free space manager")
  
          /* Increment total # of sections */
          total_sects += nums;
  
          /* Close the free space manager of this type, if we started it here */
          if (fs_started)
              if (H5MF__close_fstype(f, ty) < 0)
                  HGOTO_ERROR(H5E_RESOURCE, H5E_CANTCLOSEOBJ, FAIL, "can't close file free space")
          if ((H5F_PAGED_AGGR(f)) && (type != H5FD_MEM_DEFAULT))
              ty = (H5F_mem_page_t)(ty + H5FD_MEM_NTYPES - 2);
      } /* end for */
  
      /* Set value to return */
      *sect_count = total_sects;
  
  done:
      /* Reset the ring in the API context */
      if (orig_ring != H5AC_RING_INV)
          H5AC_set_ring(orig_ring, NULL);
  
      FUNC_LEAVE_NOAPI_TAG(ret_value)
  } /* H5MF_get_free_sections() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5MF__sects_cb()
   *
   * Purpose:	Iterator callback for each free-space section
   *          Retrieve address and size into user data
   *
   * Return:	Always succeed
   *
   * Programmer:  Vailin Choi
   *              July 1st, 2009
   *
   *-------------------------------------------------------------------------
   */
  static herr_t
  H5MF__sects_cb(H5FS_section_info_t *_sect, void *_udata)
  {
      H5MF_free_section_t *sect  = (H5MF_free_section_t *)_sect;
      H5MF_sect_iter_ud_t *udata = (H5MF_sect_iter_ud_t *)_udata;
  
      FUNC_ENTER_STATIC_NOERR
  
      if (udata->sect_idx < udata->sect_count) {
          udata->sects[udata->sect_idx].addr = sect->sect_info.addr;
          udata->sects[udata->sect_idx].size = sect->sect_info.size;
          udata->sect_idx++;
      } /* end if */
  
      FUNC_LEAVE_NOAPI(SUCCEED)
  } /* H5MF__sects_cb() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5MF__get_free_sects
   *
   * Purpose:	Retrieve section information for the specified free-space manager.
   *
   * Return:      Success:        non-negative
   *              Failure:        negative
   *
   * Programmer:  Vailin Choi; Dec 2012
   *
   *-------------------------------------------------------------------------
   */
  static herr_t
  H5MF__get_free_sects(H5F_t *f, H5FS_t *fspace, H5MF_sect_iter_ud_t *sect_udata, size_t *nums)
  {
      hsize_t hnums     = 0;       /* # of sections */
      herr_t  ret_value = SUCCEED; /* Return value */
  
      FUNC_ENTER_STATIC
  
      /* check args */
      HDassert(f);
      HDassert(sect_udata);
      HDassert(nums);
      HDassert(fspace);
  
      /* Query how many sections of this type */
      if (H5FS_sect_stats(fspace, NULL, &hnums) < 0)
          HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query free space stats")
      H5_CHECKED_ASSIGN(*nums, size_t, hnums, hsize_t);
  
      /* Check if we should retrieve the section info */
      if (sect_udata->sects && *nums > 0)
          /* Iterate over all the free space sections of this type, adding them to the user's section info */
          if (H5FS_sect_iterate(f, fspace, H5MF__sects_cb, sect_udata) < 0)
              HGOTO_ERROR(H5E_RESOURCE, H5E_BADITER, FAIL, "can't iterate over sections")
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* H5MF__get_free_sects() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5MF_settle_raw_data_fsm()
   *
   * Purpose: 	Handle any tasks required before the metadata cache
   *		can serialize or flush the raw data free space manager
   *		and any metadata free space managers that reside in the
   *		raw data free space manager ring.
   *
   *              Specifically, this means any metadata managers that DON'T
   *              handle space allocation for free space manager header or
   *              section info will reside in the raw data free space manager
   *              ring.
   *
   *              In the absence of page allocation, there is at most one
   *		free space manager per memory type defined in H5F_mem_t.
   *		Of these, the one that allocates H5FD_MEM_DRAW will
   *		always reside in the raw data free space manager ring.
   *		If there is more than one metadata free space manager,
   *		all that don't handle H5FD_MEM_FSPACE_HDR or
   *              H5FD_MEM_FSPACE_SINFO (which map to H5FD_MEM_OHDR and
   *              H5FD_MEM_LHEAP respectively) will reside in the raw
   *		data free space manager ring as well
   *
   *		With page allocation, the situation is conceptually
   *		identical, but more complex in practice.
   *
   *              In the worst case (multi file driver) page allocation
   *		can result in two free space managers for each memory
   *		type -- one for small (less than on equal to one page)
   *              allocations, and one for large (greater than one page)
   *              allocations.
   *
   *		In the more common one file case, page allocation will
   *              result in a total of three free space managers -- one for
   *              small (<= one page) raw data allocations, one for small
   *              metadata allocations (i.e, all memory types other than
   *              H5FD_MEM_DRAW), and one for all large (> one page)
   *              allocations.
   *
   *              Despite these complications, the solution is the same in
   *		the page allocation case -- free space managers (be they
   *              small data or large) are assigned to the raw data free
   *              space manager ring if they don't allocate file space for
   *              free space managers.  Note that in the one file case, the
   *		large free space manager must be assigned to the metadata
   *		free space manager ring, as it both allocates pages for
   *		the metadata free space manager, and allocates space for
   *		large (> 1 page) metadata cache entries.
   *
   *              At present, the task list for this routine is:
   *
   *		1) Reduce the EOA to the extent possible.  To do this:
   *
   *		    a) Free both aggregators.  Space not at EOA will be
   *		       added to the appropriate free space manager.
   *
   *		       The raw data aggregator should not be restarted
   *		       after this point.  It is possible that the metadata
   *		       aggregator will be.
   *
   *		    b) Free all file space currently allocated to free
   *		       space managers.
   *
   *		    c) Delete the free space manager superblock
   *		       extension message if allocated.
   *
   *		   This done, reduce the EOA by moving it to just before
   *		   the last piece of free memory in the file.
   *
   *		2) Ensure that space is allocated for the free space
   *                 manager superblock extension message.  Must do this
   *                 now, before reallocating file space for free space
   *		   managers, as it is possible that this allocation may
   *		   grab the last section in a FSM -- making it unnecessary
   *		   to re-allocate file space for it.
   *
   *		3) Scan all free space managers not involved in allocating
   *		   space for free space managers.  For each such free space
   *		   manager, test to see if it contains free space.  If
   *		   it does, allocate file space for its header and section
   *		   data.  If it contains no free space, leave it without
   *		   allocated file space as there is no need to save it to
   *		   file.
   *
   *		   Note that all free space managers in this class should
   *		   see no further space allocations / deallocations as
   *		   at this point, all raw data allocations should be
   *		   finalized, as should all metadata allocations not
   *		   involving free space managers.
   *
   *		   We will allocate space for free space managers involved
   *		   in the allocation of file space for free space managers
   *		   in H5MF_settle_meta_data_fsm()
   *
   * Return:	SUCCEED/FAIL
   *
   * Programmer:  John Mainzer
   *	        5/25/16
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5MF_settle_raw_data_fsm(H5F_t *f, hbool_t *fsm_settled)
  {
      int            pass_count;
      hsize_t        alloc_size;
      H5F_mem_t      mem_type;                    /* Memory type for iteration */
      H5F_mem_page_t fsm_type;                    /* FSM type for iteration */
      H5O_fsinfo_t   fsinfo;                      /* Free space manager info message */
      H5FS_stat_t    fs_stat;                     /* Information for free-space manager */
      H5AC_ring_t    orig_ring   = H5AC_RING_INV; /* Original ring value */
      H5AC_ring_t    curr_ring   = H5AC_RING_INV; /* Current ring value */
      H5AC_ring_t    needed_ring = H5AC_RING_INV; /* Ring value needed for this iteration */
      herr_t         ret_value   = SUCCEED;       /* Return value */
  
      FUNC_ENTER_NOAPI_TAG(H5AC__FREESPACE_TAG, FAIL)
  
      /* Check args */
      HDassert(f);
      HDassert(f->shared);
      HDassert(fsm_settled);
  
      /* Initialize structs */
      HDmemset(&fsinfo, 0, sizeof(fsinfo));
      HDmemset(&fs_stat, 0, sizeof(fs_stat));
  
      /*
       * Only need to settle things if we are persisting free space and
       * the private property in f->shared->null_fsm_addr is not enabled.
       */
      if (f->shared->fs_persist && !H5F_NULL_FSM_ADDR(f)) {
          hbool_t fsm_opened[H5F_MEM_PAGE_NTYPES];  /* State of FSM */
          hbool_t fsm_visited[H5F_MEM_PAGE_NTYPES]; /* State of FSM */
  
          /* Sanity check */
          HDassert(f->shared->sblock);
  
          /* should only be called if file is opened R/W */
          HDassert(H5F_INTENT(f) & H5F_ACC_RDWR);
  
          /* shouldn't be called unless we have a superblock supporting the
           * superblock extension.
           */
          HDassert(f->shared->sblock->super_vers >= HDF5_SUPERBLOCK_VERSION_2);
  
          /* Initialize fsm_opened and fsm_visited */
          HDmemset(fsm_opened, 0, sizeof(fsm_opened));
          HDmemset(fsm_visited, 0, sizeof(fsm_visited));
  
          /* 1) Reduce the EOA to the extent possible. */
  
          /* a) Free the space in aggregators:
           *
           * (for space not at EOF, it may be put into free space managers)
           *
           * Do this now so that the raw data FSM (and any other FSM that isn't
           * involved in space allocation for FSMs) will have no further activity.
           *
           * Note that while the raw data aggregator should not be restarted during
           * the close process, this need not be the case for the metadata aggregator.
           *
           * Note also that the aggregators will not exist if page aggregation
           * is enabled -- skip this if so.
           */
          /* Vailin -- is this correct? */
          if (!H5F_PAGED_AGGR(f) && (H5MF_free_aggrs(f) < 0))
              HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "can't free aggregators")
  
          /* Set the ring type in the DXPL.  In most cases, we will
           * need H5AC_RING_MDFSM first, so initially set the ring in
           * the DXPL to that value.  We will alter this later if
           * needed.
           */
          H5AC_set_ring(H5AC_RING_MDFSM, &orig_ring);
          curr_ring = H5AC_RING_MDFSM;
  
          /* b) Free the file space (if any) allocated to each free space manager.
           *
           * Do this to facilitate reduction of the size of the file to the
           * extent possible.  We will re-allocate space to free space managers
           * that have free space to save after this reduction.
           *
           * In the case of the raw data free space manager, and any other free
           * space manager that does not allocate space for free space managers,
           * allocations should be complete at this point, as all raw data should
           * have space allocated and be flushed to file by now.  Thus we
           * can examine such free space managers and only re-allocate space for
           * them if they contain free space.  Do this later in this function after
           * the EOA has been reduced to the extent possible.
           *
           * For free space managers that allocate file space for free space
           * managers (usually just a single metadata free space manager, but for
           * now at least, free space managers for different types of metadata
           * are possible), the matter is more ticklish due to the self-
           * referential nature of the problem.  These FSMs are dealt with in
           * H5MF_settle_meta_data_fsm().
           *
           * Since paged allocation may be enabled, there may be up to two
           * free space managers per memory type -- one for small and one for
           * large allocation.  Hence we must loop over the memory types twice
           * setting the allocation size accordingly if paged allocation is
           * enabled.
           */
          for (pass_count = 0; pass_count <= 1; pass_count++) {
              if (pass_count == 0)
                  alloc_size = 1;
              else if (H5F_PAGED_AGGR(f))
                  alloc_size = f->shared->fs_page_size + 1;
              else /* no need for a second pass */
                  break;
  
              for (mem_type = H5FD_MEM_SUPER; mem_type < H5FD_MEM_NTYPES; mem_type++) {
                  H5MF__alloc_to_fs_type(f->shared, mem_type, alloc_size, &fsm_type);
  
                  if (pass_count == 0) { /* this is the first pass */
                      HDassert(fsm_type > H5F_MEM_PAGE_DEFAULT);
                      HDassert(fsm_type < H5F_MEM_PAGE_LARGE_SUPER);
                  }                             /* end if */
                  else if (H5F_PAGED_AGGR(f)) { /* page alloc active */
                      HDassert(fsm_type >= H5F_MEM_PAGE_LARGE_SUPER);
                      HDassert(fsm_type < H5F_MEM_PAGE_NTYPES);
                  }    /* end else-if */
                  else /* paged allocation disabled -- should be unreachable */
                      HDassert(FALSE);
  
                  if (!fsm_visited[fsm_type]) {
                      fsm_visited[fsm_type] = TRUE;
  
                      /* If there is no active FSM for this type, but such a FSM has
                       * space allocated in file, open it so that we can free its file
                       * space.
                       */
                      if (NULL == f->shared->fs_man[fsm_type]) {
                          if (H5F_addr_defined(f->shared->fs_addr[fsm_type])) {
                              /* Sanity check */
                              HDassert(fsm_opened[fsm_type] == FALSE);
  
                              if (H5MF__open_fstype(f, fsm_type) < 0)
                                  HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL,
                                              "can't initialize file free space manager")
                              fsm_opened[fsm_type] = TRUE;
                          } /* end if */
                      }     /* end if */
  
                      if (f->shared->fs_man[fsm_type]) {
                          /* Test to see if we need to switch rings -- do so if required */
                          if (H5MF__fsm_type_is_self_referential(f->shared, fsm_type))
                              needed_ring = H5AC_RING_MDFSM;
                          else
                              needed_ring = H5AC_RING_RDFSM;
  
                          if (needed_ring != curr_ring) {
                              H5AC_set_ring(needed_ring, NULL);
                              curr_ring = needed_ring;
                          } /* end if */
  
                          /* Query free space manager info for this type */
                          if (H5FS_stat_info(f, f->shared->fs_man[fsm_type], &fs_stat) < 0)
                              HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't get free-space info")
  
                          /* Check if the free space manager has space in the file */
                          if (H5F_addr_defined(fs_stat.addr) || H5F_addr_defined(fs_stat.sect_addr)) {
                              /* Delete the free space manager in the file.  Will
                               * reallocate later if the free space manager contains
                               * any free space.
                               */
                              if (H5FS_free(f, f->shared->fs_man[fsm_type], TRUE) < 0)
                                  HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL,
                                              "can't release free-space headers")
                              f->shared->fs_addr[fsm_type] = HADDR_UNDEF;
                          } /* end if */
                      }     /* end if */
  
                      /* note that we are tracking opened FSM -- we will close them
                       * at the end of the function.
                       */
                  } /* end if */
              }     /* end for */
          }         /* end for */
  
          /* c) Delete the free space manager superblock extension message
           *    if allocated.
           *
           *    Must do this since the routine that writes / creates superblock
           *    extension messages will choke if the target message is
           *    unexpectedly either absent or present.
           *
           *    Update: This is probably unnecessary, as I gather that the
           *            file space manager info message is guaranteed to exist.
           *            Leave it in for now, but consider removing it.
           */
          if (H5F_addr_defined(f->shared->sblock->ext_addr))
              if (H5F__super_ext_remove_msg(f, H5O_FSINFO_ID) < 0)
                  HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL,
                              "error in removing message from superblock extension")
  
          /* As the final element in 1), shrink the EOA for the file */
          if (H5MF__close_shrink_eoa(f) < 0)
              HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink eoa")
  
          /* 2) Ensure that space is allocated for the free space manager superblock
           *    extension message.  Must do this now, before reallocating file space
           *    for free space managers, as it is possible that this allocation may
           *    grab the last section in a FSM -- making it unnecessary to
           *    re-allocate file space for it.
           *
           * Do this by writing a free space manager superblock extension message.
           *
           * Since no free space manager has file space allocated for it, this
           * message must be invalid since we can't save addresses of FSMs when
           * those addresses are unknown.  This is OK -- we will write the correct
           * values to the message at free space manager shutdown.
           */
          for (fsm_type = H5F_MEM_PAGE_SUPER; fsm_type < H5F_MEM_PAGE_NTYPES; fsm_type++)
              fsinfo.fs_addr[fsm_type - 1] = HADDR_UNDEF;
          fsinfo.strategy            = f->shared->fs_strategy;
          fsinfo.persist             = f->shared->fs_persist;
          fsinfo.threshold           = f->shared->fs_threshold;
          fsinfo.page_size           = f->shared->fs_page_size;
          fsinfo.pgend_meta_thres    = f->shared->pgend_meta_thres;
          fsinfo.eoa_pre_fsm_fsalloc = HADDR_UNDEF;
  
          if (H5F__super_ext_write_msg(f, H5O_FSINFO_ID, &fsinfo, TRUE, H5O_MSG_FLAG_MARK_IF_UNKNOWN) < 0)
              HGOTO_ERROR(H5E_RESOURCE, H5E_WRITEERROR, FAIL,
                          "error in writing fsinfo message to superblock extension")
  
          /* 3) Scan all free space managers not involved in allocating
           *    space for free space managers.  For each such free space
           *    manager, test to see if it contains free space.  If
           *    it does, allocate file space for its header and section
           *    data.  If it contains no free space, leave it without
           *    allocated file space as there is no need to save it to
           *    file.
           *
           *    Note that all free space managers in this class should
           *    see no further space allocations / deallocations as
           *    at this point, all raw data allocations should be
           *    finalized, as should all metadata allocations not involving
           *    free space managers.
           *
           *    We will allocate space for free space managers involved
           *    in the allocation of file space for free space managers
           *    in H5MF_settle_meta_data_fsm()
           */
  
          /* Reinitialize fsm_visited */
          for (fsm_type = H5F_MEM_PAGE_SUPER; fsm_type < H5F_MEM_PAGE_NTYPES; fsm_type++)
              fsm_visited[fsm_type] = FALSE;
  
          for (pass_count = 0; pass_count <= 1; pass_count++) {
              if (pass_count == 0)
                  alloc_size = 1;
              else if (H5F_PAGED_AGGR(f))
                  alloc_size = f->shared->fs_page_size + 1;
              else /* no need for a second pass */
                  break;
  
              for (mem_type = H5FD_MEM_SUPER; mem_type < H5FD_MEM_NTYPES; mem_type++) {
                  H5MF__alloc_to_fs_type(f->shared, mem_type, alloc_size, &fsm_type);
  
                  if (pass_count == 0) { /* this is the first pass */
                      HDassert(fsm_type > H5F_MEM_PAGE_DEFAULT);
                      HDassert(fsm_type < H5F_MEM_PAGE_LARGE_SUPER);
                  }                             /* end if */
                  else if (H5F_PAGED_AGGR(f)) { /* page alloc active */
                      HDassert(fsm_type >= H5F_MEM_PAGE_LARGE_SUPER);
                      HDassert(fsm_type < H5F_MEM_PAGE_NTYPES);
                  }    /* end else-if */
                  else /* paged allocation disabled -- should be unreachable */
                      HDassert(FALSE);
  
                  /* Test to see if we need to switch rings -- do so if required */
                  if (H5MF__fsm_type_is_self_referential(f->shared, fsm_type))
                      needed_ring = H5AC_RING_MDFSM;
                  else
                      needed_ring = H5AC_RING_RDFSM;
  
                  if (needed_ring != curr_ring) {
                      H5AC_set_ring(needed_ring, NULL);
                      curr_ring = needed_ring;
                  } /* end if */
  
                  /* Since there can be a many-to-one mapping from memory types
                   * to free space managers, ensure that we don't visit any FSM
                   * more than once.
                   */
                  if (!fsm_visited[fsm_type]) {
                      fsm_visited[fsm_type] = TRUE;
  
                      if (f->shared->fs_man[fsm_type]) {
                          /* Only allocate file space if the target free space manager
                           * doesn't allocate file space for free space managers.  Note
                           * that this is also the deciding factor as to whether a FSM
                           * in in the raw data FSM ring.
                           */
                          if (!H5MF__fsm_type_is_self_referential(f->shared, fsm_type)) {
                              /* The current ring should be H5AC_RING_RDFSM */
                              HDassert(curr_ring == H5AC_RING_RDFSM);
  
                              /* Query free space manager info for this type */
                              if (H5FS_stat_info(f, f->shared->fs_man[fsm_type], &fs_stat) < 0)
                                  HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't get free-space info")
  
                              /* If the free space manager contains section info,
                               * allocate space for the header and sinfo (note that
                               * space must not be allocated at present -- verify
                               * verify this with assertions).
                               */
                              if (fs_stat.serial_sect_count > 0) {
                                  /* Sanity check */
                                  HDassert(!H5F_addr_defined(fs_stat.addr));
  
                                  /* Allocate FSM header */
                                  if (H5FS_alloc_hdr(f, f->shared->fs_man[fsm_type],
                                                     &f->shared->fs_addr[fsm_type]) < 0)
                                      HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
                                                  "can't allocated free-space header")
  
                                  /* Allocate FSM section info */
                                  HDassert(!H5F_addr_defined(fs_stat.sect_addr));
                                  HDassert(fs_stat.alloc_sect_size == 0);
                                  if (H5FS_alloc_sect(f, f->shared->fs_man[fsm_type]) < 0)
                                      HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
                                                  "can't allocate free-space section info")
  
  #ifndef NDEBUG
                                  /* Re-Query free space manager info for this type */
                                  if (H5FS_stat_info(f, f->shared->fs_man[fsm_type], &fs_stat) < 0)
                                      HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL,
                                                  "can't get free-space info")
  
                                  HDassert(H5F_addr_defined(fs_stat.addr));
                                  HDassert(H5F_addr_defined(fs_stat.sect_addr));
                                  HDassert(fs_stat.serial_sect_count > 0);
                                  HDassert(fs_stat.alloc_sect_size > 0);
                                  HDassert(fs_stat.alloc_sect_size == fs_stat.sect_size);
  #endif                        /* NDEBUG */
                              } /* end if */
                              else {
                                  HDassert(!H5F_addr_defined(fs_stat.addr));
                                  HDassert(!H5F_addr_defined(fs_stat.sect_addr));
                                  HDassert(fs_stat.serial_sect_count == 0);
                                  HDassert(fs_stat.alloc_sect_size == 0);
                              } /* end else */
                          }     /* end if */
                      }         /* end if */
  
                      /* Close any opened FSMs */
                      if (fsm_opened[fsm_type]) {
                          if (H5MF__close_fstype(f, fsm_type) < 0)
                              HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL,
                                          "can't close file free space manager")
                          fsm_opened[fsm_type] = FALSE;
                      } /* end if */
                  }     /* end if */
              }         /* end for */
          }             /* end for */
  
          /* verify that all opened FSMs were closed */
          for (fsm_type = H5F_MEM_PAGE_SUPER; fsm_type < H5F_MEM_PAGE_NTYPES; fsm_type++)
              HDassert(!fsm_opened[fsm_type]);
  
          /* Indicate that the FSM was settled successfully */
          *fsm_settled = TRUE;
      } /* end if */
  
  done:
      /* Reset the ring in the API context */
      if (orig_ring != H5AC_RING_INV)
          H5AC_set_ring(orig_ring, NULL);
  
      FUNC_LEAVE_NOAPI_TAG(ret_value)
  } /* H5MF_settle_raw_data_fsm() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5MF_settle_meta_data_fsm()
   *
   * Purpose: 	If the free space manager is persistent, handle any tasks
   *		required before the metadata cache can serialize or flush
   *		the metadata free space manager(s) that handle file space
   *		allocation for free space managers.
   *
   *		In most cases, there will be only one manager assigned
   *		to this role.  However, since for reasons unknown,
   *		free space manager headers and section info blocks are
   *		different classes of memory, it is possible that two free
   *		space managers will be involved.
   *
   *		On entry to this function, the raw data settle routine
   *		(H5MF_settle_raw_data_fsm()) should have:
   *
   *      1) Freed the aggregators.
   *
   *		2) Freed all file space allocated to the free space managers.
   *
   *		3) Deleted the free space manager superblock extension message
   *
   *		4) Reduced the EOA to the extent possible.
   *
   *		5) Re-created the free space manager superblock extension
   *		   message.
   *
   *		6) Reallocated file space for all non-empty free space
   *		   managers NOT involved in allocation of space for free
   *		   space managers.
   *
   *		   Note that these free space managers (if not empty) should
   *		   have been written to file by this point, and that no
   *		   further space allocations involving them should take
   *		   place during file close.
   *
   *		On entry to this routine, the free space manager(s) involved
   *		in allocation of file space for free space managers should
   *		still be floating. (i.e. should not have any file space
   *		allocated to them.)
   *
   *		Similarly, the raw data aggregator should not have been
   *		restarted.  Note that it is probable that reallocation of
   *		space in 5) and 6) above will have re-started the metadata
   *		aggregator.
   *
   *
   *		In this routine, we proceed as follows:
   *
   *		1) Verify that the free space manager(s) involved in file
   *		   space allocation for free space managers are still floating.
   *
   *      2) Free the aggregators.
   *
   *      3) Reduce the EOA to the extent possible, and make note
   *		   of the resulting value.  This value will be stored
   *		   in the fsinfo superblock extension message and be used
   *         in the subsequent file open.
   *
   *		4) Re-allocate space for any free space manager(s) that:
   *
   *		   a) are involved in allocation of space for free space
   *		      managers, and
   *
   *		   b) contain free space.
   *
   *		   It is possible that we could allocate space for one
   *		   of these free space manager(s) only to have the allocation
   *		   result in the free space manager being empty and thus
   *		   obliging us to free the space again.  Thus there is the
   *		   potential for an infinite loop if we want to avoid saving
   *		   empty free space managers.
   *
   *		   Similarly, it is possible that we could allocate space
   *		   for a section info block, only to discover that this
   *		   allocation has changed the size of the section info --
   *		   forcing us to deallocate and start the loop over again.
   *
   *		   The solution is to modify the FSM code to
   *		   save empty FSMs to file, and to allow section info blocks
   *		   to be oversized.  That is, only allow section info to increase
   *         in size, not shrink.  The solution is now implemented.
   *
   *      5) Make note of the EOA -- used for sanity checking on
   *         FSM shutdown.  This is saved as eoa_pre_fsm_fsalloc in
   *         the free-space info message for backward compatibility
   *         with the 1.10 library that has the hack.
   *
   * Return:	SUCCEED/FAIL
   *
   * Programmer:  John Mainzer
   *	        5/25/16
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5MF_settle_meta_data_fsm(H5F_t *f, hbool_t *fsm_settled)
  {
      H5F_mem_page_t sm_fshdr_fs_type;                          /* small fs hdr fsm */
      H5F_mem_page_t sm_fssinfo_fs_type;                        /* small fs sinfo fsm */
      H5F_mem_page_t lg_fshdr_fs_type   = H5F_MEM_PAGE_DEFAULT; /* large fs hdr fsm */
      H5F_mem_page_t lg_fssinfo_fs_type = H5F_MEM_PAGE_DEFAULT; /* large fs sinfo fsm */
      H5FS_t *       sm_hdr_fspace      = NULL;                 /* ptr to sm FSM hdr alloc FSM */
      H5FS_t *       sm_sinfo_fspace    = NULL;                 /* ptr to sm FSM sinfo alloc FSM */
      H5FS_t *       lg_hdr_fspace      = NULL;                 /* ptr to lg FSM hdr alloc FSM */
      H5FS_t *       lg_sinfo_fspace    = NULL;                 /* ptr to lg FSM sinfo alloc FSM */
      haddr_t        eoa_fsm_fsalloc;                           /* eoa after file space allocation */
                                                                /* for self referential FSMs */
      hbool_t     continue_alloc_fsm = FALSE;         /* Continue allocating addr and sect_addr for FSMs */
      H5AC_ring_t orig_ring          = H5AC_RING_INV; /* Original ring value */
      herr_t      ret_value          = SUCCEED;       /* Return value */
  
      FUNC_ENTER_NOAPI_TAG(H5AC__FREESPACE_TAG, FAIL)
  
      /* Check args */
      HDassert(f);
      HDassert(f->shared);
      HDassert(fsm_settled);
  
      /*
       * Only need to settle things if we are persisting free space and
       * the private property in f->shared->null_fsm_addr is not enabled.
       */
      if (f->shared->fs_persist && !H5F_NULL_FSM_ADDR(f)) {
          /* Sanity check */
          HDassert(f->shared->lf);
  
          /* should only be called if file is opened R/W */
          HDassert(H5F_INTENT(f) & H5F_ACC_RDWR);
  
          H5MF__alloc_to_fs_type(f->shared, H5FD_MEM_FSPACE_HDR, (size_t)1, &sm_fshdr_fs_type);
          H5MF__alloc_to_fs_type(f->shared, H5FD_MEM_FSPACE_SINFO, (size_t)1, &sm_fssinfo_fs_type);
  
          HDassert(sm_fshdr_fs_type > H5F_MEM_PAGE_DEFAULT);
          HDassert(sm_fshdr_fs_type < H5F_MEM_PAGE_LARGE_SUPER);
  
          HDassert(sm_fssinfo_fs_type > H5F_MEM_PAGE_DEFAULT);
          HDassert(sm_fssinfo_fs_type < H5F_MEM_PAGE_LARGE_SUPER);
  
          HDassert(!H5F_addr_defined(f->shared->fs_addr[sm_fshdr_fs_type]));
          HDassert(!H5F_addr_defined(f->shared->fs_addr[sm_fssinfo_fs_type]));
  
          /* Note that in most cases, sm_hdr_fspace will equal sm_sinfo_fspace. */
          sm_hdr_fspace   = f->shared->fs_man[sm_fshdr_fs_type];
          sm_sinfo_fspace = f->shared->fs_man[sm_fssinfo_fs_type];
  
          if (H5F_PAGED_AGGR(f)) {
              H5MF__alloc_to_fs_type(f->shared, H5FD_MEM_FSPACE_HDR, f->shared->fs_page_size + 1,
                                     &lg_fshdr_fs_type);
              H5MF__alloc_to_fs_type(f->shared, H5FD_MEM_FSPACE_SINFO, f->shared->fs_page_size + 1,
                                     &lg_fssinfo_fs_type);
  
              HDassert(lg_fshdr_fs_type >= H5F_MEM_PAGE_LARGE_SUPER);
              HDassert(lg_fshdr_fs_type < H5F_MEM_PAGE_NTYPES);
  
              HDassert(lg_fssinfo_fs_type >= H5F_MEM_PAGE_LARGE_SUPER);
              HDassert(lg_fssinfo_fs_type < H5F_MEM_PAGE_NTYPES);
  
              HDassert(!H5F_addr_defined(f->shared->fs_addr[lg_fshdr_fs_type]));
              HDassert(!H5F_addr_defined(f->shared->fs_addr[lg_fssinfo_fs_type]));
  
              /* Note that in most cases, lg_hdr_fspace will equal lg_sinfo_fspace. */
              lg_hdr_fspace   = f->shared->fs_man[lg_fshdr_fs_type];
              lg_sinfo_fspace = f->shared->fs_man[lg_fssinfo_fs_type];
          } /* end if */
  
          /* Set the ring in the API context appropriately for subsequent calls */
          H5AC_set_ring(H5AC_RING_MDFSM, &orig_ring);
  
  #ifndef NDEBUG
          {
              H5FS_stat_t fs_stat; /* Information for hdr FSM */
  
              if (sm_hdr_fspace) {
                  /* Query free space manager info for this type */
                  if (H5FS_stat_info(f, sm_hdr_fspace, &fs_stat) < 0)
                      HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't get free-space info")
  
                  HDassert(!H5F_addr_defined(fs_stat.addr));
                  HDassert(!H5F_addr_defined(fs_stat.sect_addr));
                  HDassert(fs_stat.alloc_sect_size == 0);
              } /* end if */
  
              /* Verify that sm_sinfo_fspace is floating if it exists and is distinct */
              if ((sm_sinfo_fspace) && (sm_hdr_fspace != sm_sinfo_fspace)) {
                  /* Query free space manager info for this type */
                  if (H5FS_stat_info(f, sm_sinfo_fspace, &fs_stat) < 0)
                      HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't get free-space info")
  
                  HDassert(!H5F_addr_defined(fs_stat.addr));
                  HDassert(!H5F_addr_defined(fs_stat.sect_addr));
                  HDassert(fs_stat.alloc_sect_size == 0);
              } /* end if */
  
              if (H5F_PAGED_AGGR(f)) {
                  /* Verify that lg_hdr_fspace is floating if it exists */
                  if (lg_hdr_fspace) {
                      /* Query free space manager info for this type */
                      if (H5FS_stat_info(f, lg_hdr_fspace, &fs_stat) < 0)
                          HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't get free-space info (3)")
  
                      HDassert(!H5F_addr_defined(fs_stat.addr));
                      HDassert(!H5F_addr_defined(fs_stat.sect_addr));
                      HDassert(fs_stat.alloc_sect_size == 0);
                  } /* end if */
  
                  /* Verify that lg_sinfo_fspace is floating if it
                   * exists and is distinct
                   */
                  if ((lg_sinfo_fspace) && (lg_hdr_fspace != lg_sinfo_fspace)) {
                      /* Query free space manager info for this type */
                      if (H5FS_stat_info(f, lg_sinfo_fspace, &fs_stat) < 0)
                          HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't get free-space info (4)")
  
                      HDassert(!H5F_addr_defined(fs_stat.addr));
                      HDassert(!H5F_addr_defined(fs_stat.sect_addr));
                      HDassert(fs_stat.alloc_sect_size == 0);
                  } /* end if */
              }     /* end if */
          }
  #endif /* NDEBUG */
  
          /* Free the space in the metadata aggregator.  Do this via the
           * H5MF_free_aggrs() call.  Note that the raw data aggregator must
           * have already been freed.  Sanity checks for this?
           *
           * Note that the aggregators will not exist if paged aggregation
           * is enabled -- don't attempt to free if this is the case.
           */
          /* (for space not at EOF, it may be put into free space managers) */
          if ((!H5F_PAGED_AGGR(f)) && (H5MF_free_aggrs(f) < 0))
              HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "can't free aggregators")
  
          /* Trying shrinking the EOA for the file */
          if (H5MF__close_shrink_eoa(f) < 0)
              HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink eoa")
  
          /* WARNING:  This approach settling the self referential free space
           *           managers and allocating space for them in the file will
           *           not work as currently implemented with the split and
           *           multi file drivers, as the self referential free space
           *           manager header and section info can be stored in up to
           *           two different files -- requiring that up to two EOA's
           *           be stored in the the free space managers super block
           *           extension message.
           *
           *           As of this writing, we are solving this problem by
           *           simply not supporting persistent FSMs with the split
           *           and multi file drivers.
           *
           *           Current plans are to do away with the multi file
           *           driver, so this should be a non-issue in this case.
           *
           *           We should be able to support the split file driver
           *           without a file format change.  However, the code to
           *           do so does not exist at present.
           * NOTE: not sure whether to remove or keep the above comments
           */
  
          /*
           * Continue allocating file space for the header and section info until
           * they are all settled,
           */
          do {
              continue_alloc_fsm = FALSE;
              if (sm_hdr_fspace)
                  if (H5FS_vfd_alloc_hdr_and_section_info_if_needed(
                          f, sm_hdr_fspace, &(f->shared->fs_addr[sm_fshdr_fs_type])) < 0)
                      HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't vfd allocate sm hdr FSM file space")
  
              if (sm_sinfo_fspace && (sm_sinfo_fspace != sm_hdr_fspace))
                  if (H5FS_vfd_alloc_hdr_and_section_info_if_needed(
                          f, sm_sinfo_fspace, &(f->shared->fs_addr[sm_fssinfo_fs_type])) < 0)
                      HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
                                  "can't vfd allocate sm sinfo FSM file space")
  
              if (H5F_PAGED_AGGR(f)) {
                  if (lg_hdr_fspace)
                      if (H5FS_vfd_alloc_hdr_and_section_info_if_needed(
                              f, lg_hdr_fspace, &(f->shared->fs_addr[lg_fshdr_fs_type])) < 0)
                          HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
                                      "can't vfd allocate lg hdr FSM file space")
  
                  if (lg_sinfo_fspace && (lg_sinfo_fspace != lg_hdr_fspace))
                      if (H5FS_vfd_alloc_hdr_and_section_info_if_needed(
                              f, lg_sinfo_fspace, &(f->shared->fs_addr[lg_fssinfo_fs_type])) < 0)
                          HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
                                      "can't vfd allocate lg sinfo FSM file space")
              } /* end if */
  
              sm_hdr_fspace   = f->shared->fs_man[sm_fshdr_fs_type];
              sm_sinfo_fspace = f->shared->fs_man[sm_fssinfo_fs_type];
              if (H5F_PAGED_AGGR(f)) {
                  lg_hdr_fspace   = f->shared->fs_man[lg_fshdr_fs_type];
                  lg_sinfo_fspace = f->shared->fs_man[lg_fssinfo_fs_type];
              }
  
              if (H5MF__continue_alloc_fsm(f->shared, sm_hdr_fspace, sm_sinfo_fspace, lg_hdr_fspace,
                                           lg_sinfo_fspace, &continue_alloc_fsm) < 0)
                  HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't vfd allocate lg sinfo FSM file space")
          } while (continue_alloc_fsm);
  
          /* All free space managers should have file space allocated for them
           * now, and should see no further allocations / deallocations.
           * For backward compatibility, store the eoa in f->shared->eoa_fsm_fsalloc
           * which will be set to fsinfo.eoa_pre_fsm_fsalloc when we actually write
           * the free-space info message to the superblock extension.
           * This will allow the 1.10 library with the hack to open the file with
           * the new solution.
           */
          /* Get the eoa after allocation of file space for the self referential
           * free space managers.  Assuming no cache image, this should be the
           * final EOA of the file.
           */
          if (HADDR_UNDEF == (eoa_fsm_fsalloc = H5FD_get_eoa(f->shared->lf, H5FD_MEM_DEFAULT)))
              HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to get file size")
          f->shared->eoa_fsm_fsalloc = eoa_fsm_fsalloc;
  
          /* Indicate that the FSM was settled successfully */
          *fsm_settled = TRUE;
      } /* end if */
  
  done:
      /* Reset the ring in the API context */
      if (orig_ring != H5AC_RING_INV)
          H5AC_set_ring(orig_ring, NULL);
  
      FUNC_LEAVE_NOAPI_TAG(ret_value)
  } /* H5MF_settle_meta_data_fsm() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5MF__continue_alloc_fsm
   *
   * Purpose: 	To determine whether any of the input FSMs has allocated
   *              its "addr" and "sect_addr".
   *              Return TRUE or FALSE in *continue_alloc_fsm.
   *
   * Return:	    SUCCEED/FAIL
   *
   * Programmer:  Vailin Choi
   *              6/24/2019
   *-------------------------------------------------------------------------
   */
  static herr_t
  H5MF__continue_alloc_fsm(H5F_shared_t *f_sh, H5FS_t *sm_hdr_fspace, H5FS_t *sm_sinfo_fspace,
                           H5FS_t *lg_hdr_fspace, H5FS_t *lg_sinfo_fspace, hbool_t *continue_alloc_fsm)
  {
      FUNC_ENTER_STATIC_NOERR
  
      /* Sanity checks */
      HDassert(f_sh);
      HDassert(continue_alloc_fsm);
  
      /* Check sm_hdr_fspace */
      if (sm_hdr_fspace && sm_hdr_fspace->serial_sect_count > 0 && sm_hdr_fspace->sinfo)
          H5MF_CHECK_FSM(sm_hdr_fspace, continue_alloc_fsm);
  
      if (!(*continue_alloc_fsm))
          if (sm_sinfo_fspace && sm_sinfo_fspace != sm_hdr_fspace && sm_sinfo_fspace->serial_sect_count > 0 &&
              sm_sinfo_fspace->sinfo)
              H5MF_CHECK_FSM(sm_hdr_fspace, continue_alloc_fsm);
  
      if (H5F_SHARED_PAGED_AGGR(f_sh) && !(*continue_alloc_fsm)) {
          /* Check lg_hdr_fspace */
          if (lg_hdr_fspace && lg_hdr_fspace->serial_sect_count > 0 && lg_hdr_fspace->sinfo)
              H5MF_CHECK_FSM(lg_hdr_fspace, continue_alloc_fsm);
  
          /* Check lg_sinfo_fspace */
          if (!(*continue_alloc_fsm))
              if (lg_sinfo_fspace && lg_sinfo_fspace != lg_hdr_fspace &&
                  lg_sinfo_fspace->serial_sect_count > 0 && lg_sinfo_fspace->sinfo)
                  H5MF_CHECK_FSM(lg_sinfo_fspace, continue_alloc_fsm);
      } /* end if */
  
      FUNC_LEAVE_NOAPI(SUCCEED)
  } /* H5MF__continue_alloc_fsm() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5MF__fsm_type_is_self_referential()
   *
   * Purpose:     Return TRUE if the indicated free space manager allocates
   *		file space for free space managers.  Return FALSE otherwise.
   *
   * Return:      TRUE/FALSE
   *
   * Programmer:  John Mainzer
   *              12/6/16
   *
   *-------------------------------------------------------------------------
   */
  static hbool_t
  H5MF__fsm_type_is_self_referential(H5F_shared_t *f_sh, H5F_mem_page_t fsm_type)
  {
      H5F_mem_page_t sm_fshdr_fsm;
      H5F_mem_page_t sm_fssinfo_fsm;
      H5F_mem_page_t lg_fshdr_fsm;
      H5F_mem_page_t lg_fssinfo_fsm;
      hbool_t        result = FALSE;
  
      FUNC_ENTER_STATIC_NOERR
  
      /* Sanity check */
      HDassert(f_sh);
      HDassert(fsm_type >= H5F_MEM_PAGE_DEFAULT);
      HDassert(fsm_type < H5F_MEM_PAGE_NTYPES);
  
      H5MF__alloc_to_fs_type(f_sh, H5FD_MEM_FSPACE_HDR, (size_t)1, &sm_fshdr_fsm);
      H5MF__alloc_to_fs_type(f_sh, H5FD_MEM_FSPACE_SINFO, (size_t)1, &sm_fssinfo_fsm);
  
      if (H5F_SHARED_PAGED_AGGR(f_sh)) {
          H5MF__alloc_to_fs_type(f_sh, H5FD_MEM_FSPACE_HDR, f_sh->fs_page_size + 1, &lg_fshdr_fsm);
          H5MF__alloc_to_fs_type(f_sh, H5FD_MEM_FSPACE_SINFO, f_sh->fs_page_size + 1, &lg_fssinfo_fsm);
  
          result = (fsm_type == sm_fshdr_fsm) || (fsm_type == sm_fssinfo_fsm) || (fsm_type == lg_fshdr_fsm) ||
                   (fsm_type == lg_fssinfo_fsm);
      } /* end if */
      else {
          /* In principle, fsm_type should always be less than
           * H5F_MEM_PAGE_LARGE_SUPER whenever paged aggregation
           * is not enabled.  However, since there is code that does
           * not observe this principle, force the result to FALSE if
           * fsm_type is greater than or equal to H5F_MEM_PAGE_LARGE_SUPER.
           */
          if (fsm_type >= H5F_MEM_PAGE_LARGE_SUPER)
              result = FALSE;
          else
              result = (fsm_type == sm_fshdr_fsm) || (fsm_type == sm_fssinfo_fsm);
      } /* end else */
  
      FUNC_LEAVE_NOAPI(result)
  } /* H5MF__fsm_type_is_self_referential() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5MF__fsm_is_self_referential()
   *
   * Purpose:     Return TRUE if the indicated free space manager allocates
   *		file space for free space managers.  Return FALSE otherwise.
   *
   * Return:      TRUE/FALSE
   *
   * Programmer:  John Mainzer
   *              12/6/16
   *
   *-------------------------------------------------------------------------
   */
  static hbool_t
  H5MF__fsm_is_self_referential(H5F_shared_t *f_sh, H5FS_t *fspace)
  {
      H5F_mem_page_t sm_fshdr_fsm;
      H5F_mem_page_t sm_fssinfo_fsm;
      hbool_t        result = FALSE;
  
      FUNC_ENTER_STATIC_NOERR
  
      /* Sanity check */
      HDassert(f_sh);
      HDassert(fspace);
  
      H5MF__alloc_to_fs_type(f_sh, H5FD_MEM_FSPACE_HDR, (size_t)1, &sm_fshdr_fsm);
      H5MF__alloc_to_fs_type(f_sh, H5FD_MEM_FSPACE_SINFO, (size_t)1, &sm_fssinfo_fsm);
  
      if (H5F_SHARED_PAGED_AGGR(f_sh)) {
          H5F_mem_page_t lg_fshdr_fsm;
          H5F_mem_page_t lg_fssinfo_fsm;
  
          H5MF__alloc_to_fs_type(f_sh, H5FD_MEM_FSPACE_HDR, f_sh->fs_page_size + 1, &lg_fshdr_fsm);
          H5MF__alloc_to_fs_type(f_sh, H5FD_MEM_FSPACE_SINFO, f_sh->fs_page_size + 1, &lg_fssinfo_fsm);
  
          result = (fspace == f_sh->fs_man[sm_fshdr_fsm]) || (fspace == f_sh->fs_man[sm_fssinfo_fsm]) ||
                   (fspace == f_sh->fs_man[lg_fshdr_fsm]) || (fspace == f_sh->fs_man[lg_fssinfo_fsm]);
      } /* end if */
      else
          result = (fspace == f_sh->fs_man[sm_fshdr_fsm]) || (fspace == f_sh->fs_man[sm_fssinfo_fsm]);
  
      FUNC_LEAVE_NOAPI(result)
  } /* H5MF__fsm_is_self_referential() */
  