From 5e98cfee43a6755c258d0e7b9a3babea73c0534f Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Fri, 1 Jul 2005 00:35:29 -0500 Subject: [svn-r11009] Purpose: Bug fix Description: When a series of files is mounted on one another and one of those files is not unmounted, the library gets confused at shutdown and goes into an infinite loop in the file interface. Solution: If there are still files left in the "closing" state when shutting down the file API, iterate over those file IDs and unmount any child files that we find mounted on those files. Platforms tested: FreeBSD 4.11 (sleipnir) Too minor to require h5committest --- release_docs/RELEASE.txt | 2 + src/H5F.c | 53 ++++++++++++++++- test/mount.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 206 insertions(+), 1 deletion(-) diff --git a/release_docs/RELEASE.txt b/release_docs/RELEASE.txt index 132bbdb..1510e41 100644 --- a/release_docs/RELEASE.txt +++ b/release_docs/RELEASE.txt @@ -296,6 +296,8 @@ Bug Fixes since HDF5-1.6.0 release Library ------- + - Fixed bug where unmounted files could cause the library to go into + an infinite loop when shutting down. QAK - 2005/06/30 - The library didn't save the information of family driver in file. The original file member size was lost after file was closed (see bug #213). This has been fixed by saving driver name and member diff --git a/src/H5F.c b/src/H5F.c index 63e108b..8c73e86 100644 --- a/src/H5F.c +++ b/src/H5F.c @@ -415,6 +415,53 @@ done: /*------------------------------------------------------------------------- + * 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: + * + *------------------------------------------------------------------------- + */ +static 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 */ + unsigned u; /* Local index */ + int ret_value = FALSE; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5F_term_unmount_cb) + + assert(f); + + if(f->mtab.nmounts) { + /* Unmount all child files */ + for (u=0; umtab.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; + + /* 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_term_interface * * Purpose: Terminate this interface: free all memory and reset global @@ -444,7 +491,11 @@ H5F_term_interface(void) if (H5_interface_initialize_g) { if ((n=H5I_nmembers(H5I_FILE))!=0) { H5I_clear_type(H5I_FILE, FALSE); - } else if (0==(n=H5I_nmembers(H5I_FILE_CLOSING))) { + } else if ((n=H5I_nmembers(H5I_FILE_CLOSING))!=0) { + /* Attempt to unmount any child files from files that are closing */ + (void)H5I_search(H5I_FILE_CLOSING, H5F_term_unmount_cb, NULL); + } + else { H5I_dec_type_ref(H5I_FILE); H5I_dec_type_ref(H5I_FILE_CLOSING); H5_interface_initialize_g = 0; diff --git a/test/mount.c b/test/mount.c index 389c48e..bff93d6 100644 --- a/test/mount.c +++ b/test/mount.c @@ -1520,6 +1520,157 @@ error: /*------------------------------------------------------------------------- + * Function: test_missing_unmount + * + * Purpose: Test that the library correctly closes open files when they + * have child files that have not been unmounted. + * + * Return: Success: 0 + * + * Failure: number of errors + * + * Programmer: Quincey Koziol + * Thursday, June 30, 2005 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static int +test_missing_unmount(hid_t fapl) +{ + hid_t fid1=-1, fid2=-1, fid3=-1; /* File IDs */ + hid_t gidA=-1, gidE=-1, gidM=-1; /* Group IDs */ + hid_t gidAE=-1, gidAEM=-1; /* Group IDs */ + char filename1[1024], + filename2[1024], + filename3[1024]; /* Name of files to mount */ + + TESTING("missing unmount"); + + h5_fixname(FILENAME[0], fapl, filename1, sizeof filename1); + h5_fixname(FILENAME[1], fapl, filename2, sizeof filename2); + h5_fixname(FILENAME[2], fapl, filename3, sizeof filename3); + + /* Create file #1 */ + if((fid1 = H5Fcreate(filename1, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) + TEST_ERROR + + if((gidA = H5Gcreate(fid1, "A", (size_t)0)) < 0) + TEST_ERROR + + if(H5Gclose(gidA) < 0) + TEST_ERROR + + if(H5Fclose(fid1) < 0) + TEST_ERROR + + + /* Create file #2 */ + if((fid2 = H5Fcreate(filename2, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) + TEST_ERROR + + if((gidE = H5Gcreate(fid2, "E", (size_t)0)) < 0) + TEST_ERROR + + if(H5Gclose(gidE) < 0) + TEST_ERROR + + if(H5Fclose(fid2) < 0) + TEST_ERROR + + + /* Create file #3 */ + if((fid3 = H5Fcreate(filename3, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) + TEST_ERROR + + if((gidM = H5Gcreate(fid3, "M", (size_t)0)) < 0) + TEST_ERROR + + if(H5Gclose(gidM) < 0) + TEST_ERROR + + if(H5Fclose(fid3) < 0) + TEST_ERROR + + + /* Re-open files and mount file #2 in file #1 and file #3 in file #2 */ + if((fid1 = H5Fopen(filename1, H5F_ACC_RDONLY, H5P_DEFAULT)) < 0) + TEST_ERROR + + if((gidA = H5Gopen(fid1, "A")) < 0) + TEST_ERROR + + /* Close file #1 */ + if(H5Fclose(fid1) < 0) + TEST_ERROR + + if((fid2 = H5Fopen(filename2, H5F_ACC_RDONLY, H5P_DEFAULT)) < 0) + TEST_ERROR + + if(H5Fmount(gidA, ".", fid2, H5P_DEFAULT) < 0) + TEST_ERROR + + /* Open group in mounted file */ + if((gidAE = H5Gopen(fid2, "A/E")) < 0) + TEST_ERROR + + /* Close file #2 */ + if(H5Fclose(fid2) < 0) + TEST_ERROR + + if((fid3 = H5Fopen(filename3, H5F_ACC_RDONLY, H5P_DEFAULT)) < 0) + TEST_ERROR + + if(H5Fmount(gidAE, ".", fid3, H5P_DEFAULT) < 0) + TEST_ERROR + + /* Open group in mounted file */ + if((gidAEM = H5Gopen(fid3, "A/E/M")) < 0) + TEST_ERROR + + /* Close file #3 */ + if(H5Fclose(fid3) < 0) + TEST_ERROR + + /* (Still have all file #2 & #3 mounted and groups open in all three files) */ + + /* Unmount file #2 & #3 */ + if(H5Funmount(gidAE,".") < 0) + TEST_ERROR + + /* Skip unmounting file #2 from file #1 */ + + /* Close groups in mounted file */ + if(H5Gclose(gidAEM) < 0) + TEST_ERROR + + if(H5Gclose(gidAE) < 0) + TEST_ERROR + + /* Close group in top file */ + if(H5Gclose(gidA) < 0) + TEST_ERROR + + PASSED(); + return 0; + +error: + H5E_BEGIN_TRY { + H5Gclose(gidM); + H5Gclose(gidE); + H5Gclose(gidAEM); + H5Gclose(gidAE); + H5Gclose(gidA); + H5Fclose(fid3); + H5Fclose(fid2); + H5Fclose(fid1); + } H5E_END_TRY; + return 1; +} /* end test_missing_unmount() */ + + +/*------------------------------------------------------------------------- * Function: main * * Purpose: Test file mounting @@ -1560,6 +1711,7 @@ main(void) nerrors += test_close(fapl); nerrors += test_mount_after_close(fapl); nerrors += test_mount_after_unmount(fapl); + nerrors += test_missing_unmount(fapl); if (nerrors) goto error; puts("All mount tests passed."); -- cgit v0.12