summaryrefslogtreecommitdiffstats
path: root/src/H5Fmount.c
diff options
context:
space:
mode:
authorQuincey Koziol <koziol@hdfgroup.org>2005-07-05 21:58:50 (GMT)
committerQuincey Koziol <koziol@hdfgroup.org>2005-07-05 21:58:50 (GMT)
commit12d84d4b12f4b43dc3a399fe3ffe8a8a15797b23 (patch)
tree4591ba2fe3d7fd860686310aea85715def56d81f /src/H5Fmount.c
parent4ca9441078b3a51cec7272a6600c32eac9a5f4af (diff)
downloadhdf5-12d84d4b12f4b43dc3a399fe3ffe8a8a15797b23.zip
hdf5-12d84d4b12f4b43dc3a399fe3ffe8a8a15797b23.tar.gz
hdf5-12d84d4b12f4b43dc3a399fe3ffe8a8a15797b23.tar.bz2
[svn-r11022] Purpose:
Bug fix & code cleanup Description: Don't unmount child files from a parent file if the parent file is being held open by an object. Also, moved the mounting routines into their own source file and the superblock routines into their own file also. Solution: Moved the code for unmounting child files down in the H5F_close routine and also add checks to the file and group mounting code to unmount child files when the last object holding open a file closes. Platforms tested: FreeBSD 4.11 (sleipnir) h5committest
Diffstat (limited to 'src/H5Fmount.c')
-rw-r--r--src/H5Fmount.c713
1 files changed, 713 insertions, 0 deletions
diff --git a/src/H5Fmount.c b/src/H5Fmount.c
new file mode 100644
index 0000000..73a450d
--- /dev/null
+++ b/src/H5Fmount.c
@@ -0,0 +1,713 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * 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 files COPYING and Copyright.html. COPYING can be found at the root *
+ * of the source code distribution tree; Copyright.html can be found at the *
+ * root level of an installed copy of the electronic HDF5 document set and *
+ * is linked from the top-level documents page. It can also be found at *
+ * http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have *
+ * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#define H5F_PACKAGE /*suppress error about including H5Fpkg */
+
+/* Interface initialization */
+#define H5_INTERFACE_INIT_FUNC H5F_init_mount_interface
+
+
+/* Packages needed by this file... */
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* File access */
+#include "H5Gprivate.h" /* Groups */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Pprivate.h" /* Property lists */
+#include "H5MMprivate.h" /* Memory management */
+
+/* PRIVATE PROTOTYPES */
+
+
+/*--------------------------------------------------------------------------
+NAME
+ H5F_init_mount_interface -- Initialize interface-specific information
+USAGE
+ herr_t H5T_init_mount_interface()
+
+RETURNS
+ Non-negative on success/Negative on failure
+DESCRIPTION
+ Initializes any interface-specific data or routines. (Just calls
+ H5F_init_iterface currently).
+
+--------------------------------------------------------------------------*/
+static herr_t
+H5F_init_mount_interface(void)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5F_init_mount_interface)
+
+ FUNC_LEAVE_NOAPI(H5F_init())
+} /* H5F_init_mount_interface() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_close_mounts
+ *
+ * Purpose: Close all mounts for a given file
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, July 2, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_close_mounts(H5F_t *f)
+{
+ unsigned u; /* Local index */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5F_close_mounts, FAIL)
+
+ HDassert(f);
+
+ /* Unmount all child files */
+ for (u = 0; u < f->mtab.nmounts; u++) {
+ f->mtab.child[u].file->mtab.parent = NULL;
+ if(H5G_close(f->mtab.child[u].group) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEOBJ, FAIL, "can't close child group")
+ if(H5F_close(f->mtab.child[u].file) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close child file")
+ } /* end if */
+ f->mtab.nmounts = 0;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_close_mounts() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_term_unmount_cb
+ *
+ * Purpose: H5F_term_interface' callback function. This routine
+ * unmounts child files from files that are in the "closing"
+ * state.
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, Jun 30, 2005
+ *
+ * Modification:
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5F_term_unmount_cb(void *obj_ptr, hid_t obj_id, void UNUSED *key)
+{
+ H5F_t *f = (H5F_t *)obj_ptr; /* Alias for search info */
+ int ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT(H5F_term_unmount_cb)
+
+ assert(f);
+
+ if(f->mtab.nmounts) {
+ /* Unmount all child files */
+ if(H5F_close_mounts(f) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't unmount child file")
+
+ /* Decrement reference count for file */
+ H5I_dec_ref(obj_id);
+ } /* end if */
+ else
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "no files to unmount")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5F_term_unmount_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_mount
+ *
+ * Purpose: Mount file CHILD onto the group specified by LOC and NAME,
+ * using mount properties in PLIST. CHILD must not already be
+ * mouted and must not be a mount ancestor of the mount-point.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, October 6, 1998
+ *
+ * Modifications:
+ *
+ * Robb Matzke, 1998-10-14
+ * The reference count for the mounted H5F_t is incremented.
+ *
+ * Pedro Vicente, <pvn@ncsa.uiuc.edu> 22 Aug 2002
+ * Added `id to name' support.
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5F_mount(H5G_entry_t *loc, const char *name, H5F_t *child,
+ hid_t UNUSED plist_id, hid_t dxpl_id)
+{
+ H5G_t *mount_point = NULL; /*mount point group */
+ H5G_entry_t *mp_ent = NULL; /*mount point symbol table entry*/
+ H5F_t *ancestor = NULL; /*ancestor files */
+ H5F_t *parent = NULL; /*file containing mount point */
+ unsigned lt, rt, md; /*binary search indices */
+ int cmp; /*binary search comparison value*/
+ H5G_entry_t *ent = NULL; /*temporary symbol table entry */
+ H5G_entry_t mp_open_ent; /* entry of moint point to be opened */
+ H5RS_str_t *name_r; /* Ref-counted version of name */
+ herr_t ret_value = SUCCEED; /*return value */
+
+ FUNC_ENTER_NOAPI_NOINIT(H5F_mount)
+
+ assert(loc);
+ assert(name && *name);
+ assert(child);
+ assert(TRUE==H5P_isa_class(plist_id,H5P_MOUNT));
+
+ /*
+ * Check that the child isn't mounted, that the mount point exists, and
+ * that the mount wouldn't introduce a cycle in the mount tree.
+ */
+ if (child->mtab.parent)
+ HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, "file is already mounted")
+ if (H5G_find(loc, name, NULL, &mp_open_ent/*out*/, H5AC_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "group not found")
+ if (NULL==(mount_point=H5G_open(&mp_open_ent, dxpl_id)))
+ HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, "mount point not found")
+
+ parent = H5G_fileof(mount_point);
+ mp_ent = H5G_entof(mount_point);
+ for (ancestor=parent; ancestor; ancestor=ancestor->mtab.parent) {
+ if (ancestor==child)
+ HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, "mount would introduce a cycle")
+ }
+
+ /*
+ * Use a binary search to locate the position that the child should be
+ * inserted into the parent mount table. At the end of this paragraph
+ * `md' will be the index where the child should be inserted.
+ */
+ lt = md = 0;
+ rt=parent->mtab.nmounts;
+ cmp = -1;
+ while (lt<rt && cmp) {
+ md = (lt+rt)/2;
+ ent = H5G_entof(parent->mtab.child[md].group);
+ cmp = H5F_addr_cmp(mp_ent->header, ent->header);
+ if (cmp<0) {
+ rt = md;
+ } else if (cmp>0) {
+ lt = md+1;
+ }
+ }
+ if (cmp>0)
+ md++;
+ if (!cmp)
+ HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, "mount point is already in use")
+
+ /* Make room in the table */
+ if (parent->mtab.nmounts>=parent->mtab.nalloc) {
+ unsigned n = MAX(16, 2*parent->mtab.nalloc);
+ H5F_mount_t *x = H5MM_realloc(parent->mtab.child,
+ n*sizeof(parent->mtab.child[0]));
+ if (!x)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for mount table")
+ parent->mtab.child = x;
+ parent->mtab.nalloc = n;
+ }
+
+ /* Insert into table */
+ HDmemmove(parent->mtab.child+md+1, parent->mtab.child+md,
+ (parent->mtab.nmounts-md)*sizeof(parent->mtab.child[0]));
+ parent->mtab.nmounts++;
+ parent->mtab.child[md].group = mount_point;
+ parent->mtab.child[md].file = child;
+ child->mtab.parent = parent;
+ child->nrefs++;
+
+ /* Search the open IDs and replace names for mount operation */
+ /* We pass H5G_UNKNOWN as object type; search all IDs */
+ name_r=H5RS_wrap(name);
+ assert(name_r);
+ if (H5G_replace_name( H5G_UNKNOWN, loc, name_r, NULL, NULL, NULL, OP_MOUNT )<0)
+ HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, "unable to replace name")
+ if(H5RS_decr(name_r)<0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTDEC, FAIL, "unable to decrement name string")
+
+done:
+ if (ret_value<0 && mount_point)
+ if(H5G_close(mount_point)<0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEOBJ, FAIL, "unable to close mounted group")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_unmount
+ *
+ * Purpose: Unmount the child which is mounted at the group specified by
+ * LOC and NAME or fail if nothing is mounted there. Neither
+ * file is closed.
+ *
+ * Because the mount point is specified by name and opened as a
+ * group, the H5G_namei() will resolve it to the root of the
+ * mounted file, not the group where the file is mounted.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, October 6, 1998
+ *
+ * Modifications:
+ *
+ * Robb Matzke, 1998-10-14
+ * The ref count for the child is decremented by calling H5F_close().
+ *
+ * Pedro Vicente, <pvn@ncsa.uiuc.edu> 22 Aug 2002
+ * Added `id to name' support.
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5F_unmount(H5G_entry_t *loc, const char *name, hid_t dxpl_id)
+{
+ H5G_t *mounted = NULL; /*mount point group */
+ H5G_entry_t *mnt_ent = NULL; /*mounted symbol table entry */
+ H5F_t *child = NULL; /*mounted file */
+ H5F_t *parent = NULL; /*file where mounted */
+ H5G_entry_t *ent = NULL; /*temporary symbol table entry */
+ H5G_entry_t mnt_open_ent; /* entry used to open mount point*/
+ herr_t ret_value = FAIL; /*return value */
+ unsigned i; /*coutners */
+ unsigned lt, rt, md=0; /*binary search indices */
+ int cmp; /*binary search comparison value*/
+
+ FUNC_ENTER_NOAPI_NOINIT(H5F_unmount)
+
+ assert(loc);
+ assert(name && *name);
+
+ /*
+ * Get the mount point, or more precisely the root of the mounted file.
+ * If we get the root group and the file has a parent in the mount tree,
+ * then we must have found the mount point.
+ */
+ if (H5G_find(loc, name, NULL, &mnt_open_ent/*out*/, H5AC_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "group not found")
+ if (NULL==(mounted=H5G_open(&mnt_open_ent, dxpl_id)))
+ HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, "mount point not found")
+ child = H5G_fileof(mounted);
+ mnt_ent = H5G_entof(mounted);
+ ent = H5G_entof(child->shared->root_grp);
+
+ if (child->mtab.parent &&
+ H5F_addr_eq(mnt_ent->header, ent->header)) {
+ /*
+ * We've been given the root group of the child. We do a reverse
+ * lookup in the parent's mount table to find the correct entry.
+ */
+ parent = child->mtab.parent;
+ for (i=0; i<parent->mtab.nmounts; i++) {
+ if (parent->mtab.child[i].file==child) {
+ /* Search the open IDs replace names to reflect unmount operation */
+ if (H5G_replace_name( H5G_UNKNOWN, mnt_ent, mnt_ent->user_path_r, NULL, NULL, NULL, OP_UNMOUNT )<0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to replace name ")
+
+ /* Unmount the child */
+ parent->mtab.nmounts -= 1;
+ if(H5G_close(parent->mtab.child[i].group)<0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEOBJ, FAIL, "unable to close unmounted group")
+ child->mtab.parent = NULL;
+ if(H5F_close(child)<0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "unable to close unmounted file")
+ HDmemmove(parent->mtab.child+i, parent->mtab.child+i+1,
+ (parent->mtab.nmounts-i)* sizeof(parent->mtab.child[0]));
+ ret_value = SUCCEED;
+ }
+ }
+ assert(ret_value>=0);
+
+ } else {
+ /*
+ * We've been given the mount point in the parent. We use a binary
+ * search in the parent to locate the mounted file, if any.
+ */
+ parent = child; /*we guessed wrong*/
+ lt = 0;
+ rt = parent->mtab.nmounts;
+ cmp = -1;
+ while (lt<rt && cmp) {
+ md = (lt+rt)/2;
+ ent = H5G_entof(parent->mtab.child[md].group);
+ cmp = H5F_addr_cmp(mnt_ent->header, ent->header);
+ if (cmp<0) {
+ rt = md;
+ } else {
+ lt = md+1;
+ }
+ }
+ if (cmp)
+ HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, "not a mount point")
+
+ /* Unmount the child */
+ parent->mtab.nmounts -= 1;
+ if(H5G_close(parent->mtab.child[md].group)<0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEOBJ, FAIL, "unable to close unmounted group")
+ parent->mtab.child[md].file->mtab.parent = NULL;
+ if(H5F_close(parent->mtab.child[md].file)<0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "unable to close unmounted file")
+ HDmemmove(parent->mtab.child+md, parent->mtab.child+md+1,
+ (parent->mtab.nmounts-md)*sizeof(parent->mtab.child[0]));
+ ret_value = SUCCEED;
+ }
+
+done:
+ if (mounted)
+ if(H5G_close(mounted)<0 && ret_value>=0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEOBJ, FAIL, "can't close group")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_mountpoint
+ *
+ * Purpose: If ENT is a mount point then copy the entry for the root
+ * group of the mounted file into ENT.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, October 6, 1998
+ *
+ * Modifications:
+ *
+ * Pedro Vicente, <pvn@ncsa.uiuc.edu> 22 Aug 2002
+ * Added `id to name' support.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_mountpoint(H5G_entry_t *find/*in,out*/)
+{
+ H5F_t *parent = find->file;
+ unsigned lt, rt, md=0;
+ int cmp;
+ H5G_entry_t *ent = NULL;
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5F_mountpoint, FAIL)
+
+ assert(find);
+
+ /*
+ * The loop is necessary because we might have file1 mounted at the root
+ * of file2, which is mounted somewhere in file3.
+ */
+ do {
+ /*
+ * Use a binary search to find the potential mount point in the mount
+ * table for the parent
+ */
+ lt = 0;
+ rt = parent->mtab.nmounts;
+ cmp = -1;
+ while (lt<rt && cmp) {
+ md = (lt+rt)/2;
+ ent = H5G_entof(parent->mtab.child[md].group);
+ cmp = H5F_addr_cmp(find->header, ent->header);
+ if (cmp<0) {
+ rt = md;
+ } else {
+ lt = md+1;
+ }
+ }
+
+ /* Copy root info over to ENT */
+ if (0==cmp) {
+ /* Get the entry for the root group in the child's file */
+ ent = H5G_entof(parent->mtab.child[md].file->shared->root_grp);
+
+ /* Don't lose the user path of the group when we copy the root group's entry */
+ if(H5G_ent_copy(find,ent,H5G_COPY_LIMITED)<0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCOPY, FAIL, "unable to copy group entry")
+
+ /* Switch to child's file */
+ parent = ent->file;
+ }
+ } while (!cmp);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_has_mount
+ *
+ * Purpose: Check if a file has mounted files within it.
+ *
+ * Return: Success: TRUE/FALSE
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, January 2, 2002
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5F_has_mount(const H5F_t *file)
+{
+ htri_t ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5F_has_mount, FAIL)
+
+ assert(file);
+
+ if(file->mtab.nmounts>0)
+ ret_value=TRUE;
+ else
+ ret_value=FALSE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_has_mount() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_is_mount
+ *
+ * Purpose: Check if a file is mounted within another file.
+ *
+ * Return: Success: TRUE/FALSE
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, January 2, 2002
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5F_is_mount(const H5F_t *file)
+{
+ htri_t ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5F_is_mount, FAIL)
+
+ assert(file);
+
+ if(file->mtab.parent!=NULL)
+ ret_value=TRUE;
+ else
+ ret_value=FALSE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_is_mount() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Fmount
+ *
+ * Purpose: Mount file CHILD_ID onto the group specified by LOC_ID and
+ * NAME using mount properties PLIST_ID.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, October 6, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Fmount(hid_t loc_id, const char *name, hid_t child_id, hid_t plist_id)
+{
+ H5G_entry_t *loc = NULL;
+ H5F_t *child = NULL;
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(H5Fmount, FAIL)
+ H5TRACE4("e","isii",loc_id,name,child_id,plist_id);
+
+ /* Check arguments */
+ if (NULL==(loc=H5G_loc(loc_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if (!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name")
+ if (NULL==(child=H5I_object_verify(child_id,H5I_FILE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file")
+ if(H5P_DEFAULT == plist_id)
+ plist_id = H5P_MOUNT_DEFAULT;
+ else
+ if(TRUE != H5P_isa_class(plist_id, H5P_MOUNT))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not property list")
+
+ /* Do the mount */
+ if (H5F_mount(loc, name, child, plist_id, H5AC_dxpl_id)<0)
+ HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, "unable to mount file")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Funmount
+ *
+ * Purpose: Given a mount point, dissassociate the mount point's file
+ * from the file mounted there. Do not close either file.
+ *
+ * The mount point can either be the group in the parent or the
+ * root group of the mounted file (both groups have the same
+ * name). If the mount point was opened before the mount then
+ * it's the group in the parent, but if it was opened after the
+ * mount then it's the root group of the child.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, October 6, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Funmount(hid_t loc_id, const char *name)
+{
+ H5G_entry_t *loc = NULL;
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(H5Funmount, FAIL)
+ H5TRACE2("e","is",loc_id,name);
+
+ /* Check args */
+ if (NULL==(loc=H5G_loc(loc_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if (!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name")
+
+ /* Unmount */
+ if (H5F_unmount(loc, name, H5AC_dxpl_id)<0)
+ HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, "unable to unmount file")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_check_mounts_recurse
+ *
+ * Purpose: Helper routine for checking for file mounting hierarchies to
+ * close.
+ *
+ * Return: TRUE if entire hierarchy can be closed / FALSE otherwise
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, July 2, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static hbool_t
+H5F_check_mounts_recurse(H5F_t *f)
+{
+ hbool_t ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5F_check_mounts_recurse)
+
+ /* Check if this file is closing and if the only objects left open are
+ * the mount points */
+ if(f->closing && f->nopen_objs == f->mtab.nmounts) {
+ unsigned u;
+
+ /* Iterate over files mounted in this file and check if all can be closed */
+ for(u = 0; u < f->mtab.nmounts; u++) {
+ if(H5G_get_shared_count(f->mtab.child[u].group) > 1
+ || !H5F_check_mounts_recurse(f->mtab.child[u].file))
+ HGOTO_DONE(FALSE)
+ } /* end for */
+ } /* end if */
+
+ ret_value = TRUE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_check_mounts_recurse() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_check_mounts
+ *
+ * Purpose: Check for file mounting hierarchies that have been created
+ * and that now are composed completely of files that are closing
+ * and have no more open objects in them.
+ *
+ * When such a mounting hierarchy is detected, unmount and close
+ * all the files involved.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, July 2, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_check_mounts(H5F_t *f)
+{
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5F_check_mounts, FAIL)
+
+ /* Only try to close files for files involved in a mounting hierarchy */
+ if(f->mtab.parent || f->mtab.nmounts) {
+ H5F_t *top = f; /* Pointer to the top file in the hierarchy */
+
+ /* Find the top file in the mounting hierarchy */
+ while(top->mtab.parent) {
+ /* Get out early if we detect that this hierarchy won't close */
+ if(top->nopen_objs != top->mtab.nmounts || !top->closing)
+ HGOTO_DONE(SUCCEED)
+
+ /* Advance toward the top of the hierarchy */
+ top = top->mtab.parent;
+ } /* end while */
+
+ /* Check for closing the hierarchy */
+ if(H5F_check_mounts_recurse(top)) {
+ /* Unmount all child files */
+ if(H5F_close_mounts(top) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't unmount child file")
+
+ H5I_dec_ref(top->closing);
+ } /* end if */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_check_mounts() */
+