summaryrefslogtreecommitdiffstats
path: root/configure
Commit message (Expand)AuthorAgeFilesLines
* [svn-r19839] Updated to libtool v 2.4, autoconf 2.68 and m4-1.4.15.Larry Knox2010-11-231-843/+1939
* [svn-r19808] Purpose:Mike McGreevy2010-11-171-22/+55
* [svn-r19781] Fix for bug #1930:Vailin Choi2010-11-151-2/+3
* [svn-r19740] Snapshot version 1.9 release 79HDF Tester2010-11-071-11/+11
* [svn-r19701] Snapshot version 1.9 release 78HDF Tester2010-10-311-11/+11
* [svn-r19696] Bug 2008 - IBM Power6 Linux uses special conversion algorithms t...Raymond Lu2010-10-281-0/+197
* [svn-r19694] Changed the default NPROCS from 3 to 6 for MPI tests.Albert Cheng2010-10-281-5/+5
* [svn-r19666] Snapshot version 1.9 release 77HDF Tester2010-10-241-10/+10
* [svn-r19617] Purpose:Mike McGreevy2010-10-151-1/+1
* [svn-r19569] Snapshot version 1.9 release 76HDF Tester2010-10-101-10/+10
* [svn-r19532] Added line to config/examples.am to remove execute permission fr...Larry Knox2010-10-071-1/+1
* [svn-r19512] Snapshot version 1.9 release 75HDF Tester2010-10-051-11/+11
* [svn-r19506] Bring changes from revisions 19408, 19421, and 19442 from branch...Larry Knox2010-10-041-1/+1
* [svn-r19470] Bug fix: 1961-- AIX 6.1 --enable-share did not work.Albert Cheng2010-09-221-1/+4
* [svn-r19366] Updated autoconf to version 2.6.7, libtool to version 2.2.10, an...Larry Knox2010-09-101-2000/+1641
* [svn-r19363] When mandatory filter failed to write data chunks, the datasetRaymond Lu2010-09-091-1/+1
* [svn-r19205] Bug 1917: post cleanup.Albert Cheng2010-08-091-4/+4
* [svn-r19185] Bug fix: ID 1917Albert Cheng2010-08-061-5/+5
* [svn-r19160] Added the tests for fseeko64 and ftello64 which will be used by ...Albert Cheng2010-07-301-2/+2
* [svn-r19086] Snapshot version 1.9 release 74HDF Tester2010-07-181-10/+10
* [svn-r19076] Purpose: Fix bug 1951Neil Fortner2010-07-161-1/+1
* [svn-r19068] Bug fix: ID 1921 change mpirun to mpiexecAlbert Cheng2010-07-141-80/+27
* [svn-r19064] Snapshot version 1.9 release 73HDF Tester2010-07-111-11/+11
* [svn-r19059] Brought changes from hdf5_1_8 to add version information for for...Larry Knox2010-07-091-30/+74
* [svn-r19047] Snapshot version 1.9 release 72HDF Tester2010-07-041-11/+11
* [svn-r19031] Snapshot version 1.9 release 71HDF Tester2010-06-281-11/+11
* [svn-r19022] Snapshot version 1.9 release 70HDF Tester2010-06-201-11/+11
* [svn-r18992] Bug Fix: (ID 1921)Albert Cheng2010-06-111-15/+15
* [svn-r18823] Snapshot version 1.9 release 69HDF Tester2010-05-161-10/+10
* [svn-r18725] Description:Quincey Koziol2010-05-061-1/+1
* [svn-r18709] Purpose:Mike McGreevy2010-05-051-61/+337
* [svn-r18684] Snapshot version 1.9 release 68HDF Tester2010-05-021-11/+11
* [svn-r18659] Bug: 1764Albert Cheng2010-04-281-3/+16
* [svn-r18648] In H5T_get_native_type of H5Tnative.c, I changed the way that th...Raymond Lu2010-04-271-1/+4
* [svn-r18634] Description:Quincey Koziol2010-04-271-1/+46
* [svn-r18589] Snapshot version 1.9 release 67HDF Tester2010-04-181-10/+10
* [svn-r18579] Purpose:Mike McGreevy2010-04-151-117/+148
* [svn-r18545] Snapshot version 1.9 release 66HDF Tester2010-04-111-11/+11
* [svn-r18508] Snapshot version 1.9 release 65HDF Tester2010-04-041-10/+10
* [svn-r18469] bug fix:Albert Cheng2010-03-301-1/+1
* [svn-r18465] Snapshot version 1.9 release 64HDF Tester2010-03-281-11/+11
* [svn-r18432] Snapshot version 1.9 release 63HDF Tester2010-03-211-11/+11
* [svn-r18420] Description:Quincey Koziol2010-03-181-8/+5
* [svn-r18415] Description:Quincey Koziol2010-03-181-1/+1
* [svn-r18413] Description:Quincey Koziol2010-03-171-2/+8
* [svn-r18406] Snapshot version 1.9 release 62HDF Tester2010-03-141-11/+11
* [svn-r18350] Snapshot version 1.9 release 61HDF Tester2010-02-281-10/+10
* [svn-r18258] Rename the following files:Vailin Choi2010-02-151-1/+1
* [svn-r18217] Snapshot version 1.9 release 60HDF Tester2010-02-071-11/+11
* [svn-r18199] Snapshot version 1.9 release 59HDF Tester2010-01-311-10/+10
n656' href='#n656'>656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 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.                                                        *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/****************/
/* Module Setup */
/****************/

#include "H5Dmodule.h" /* This source code file is part of the H5D module */

/***********/
/* Headers */
/***********/
#include "H5private.h"   /* Generic Functions                        */
#include "H5CXprivate.h" /* API Contexts                             */
#include "H5Dpkg.h"      /* Dataset functions                        */
#include "H5Eprivate.h"  /* Error handling                           */
#include "H5FLprivate.h" /* Free Lists                               */
#include "H5Iprivate.h"  /* IDs                                      */
#include "H5MMprivate.h" /* Memory management                        */
#include "H5Sprivate.h"  /* Dataspace                                */

#include "H5VLnative_private.h" /* Native VOL connector                     */

/****************/
/* Local Macros */
/****************/

/******************/
/* Local Typedefs */
/******************/

/********************/
/* Local Prototypes */
/********************/

/* Setup/teardown routines */
static herr_t H5D__ioinfo_init(size_t count, H5D_dset_io_info_t *dset_info, H5D_io_info_t *io_info);
static herr_t H5D__dset_ioinfo_init(H5D_t *dset, H5D_dset_io_info_t *dset_info, H5D_storage_t *store);
static herr_t H5D__typeinfo_init(H5D_io_info_t *io_info, H5D_dset_io_info_t *dset_info, hid_t mem_type_id);
static herr_t H5D__typeinfo_init_phase2(H5D_io_info_t *io_info);
#ifdef H5_HAVE_PARALLEL
static herr_t H5D__ioinfo_adjust(H5D_io_info_t *io_info);
#endif /* H5_HAVE_PARALLEL */
static herr_t H5D__typeinfo_term(H5D_io_info_t *io_info, size_t type_info_init);

/*********************/
/* Package Variables */
/*********************/

/*******************/
/* Local Variables */
/*******************/

/* Declare a free list to manage blocks of type conversion data */
H5FL_BLK_DEFINE(type_conv);

/*-------------------------------------------------------------------------
 * Function:	H5D__read
 *
 * Purpose:	Reads multiple (parts of) DATASETs into application memory BUFs.
 *              See H5Dread_multi() for complete details.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5D__read(size_t count, H5D_dset_io_info_t *dset_info)
{
    H5D_io_info_t io_info;                    /* Dataset I/O info  for multi dsets */
    size_t        type_info_init = 0;         /* Number of datatype info structs that have been initialized */
    H5S_t        *orig_mem_space_local;       /* Local buffer for orig_mem_space */
    H5S_t       **orig_mem_space = NULL;      /* If not NULL, ptr to an array of dataspaces       */
                                              /* containing the original memory spaces contained  */
                                              /* in dset_info.  This is needed in order to        */
                                              /* restore the original state of  dset_info if we   */
                                              /* replaced any mem spaces with equivalents         */
                                              /* projected to a rank equal to that of file_space. */
                                              /*                                                  */
                                              /* This field is only used if                       */
                                              /* H5S_select_shape_same() returns TRUE when        */
                                              /* comparing at least one mem_space and data_space, */
                                              /* and the mem_space has a different rank.          */
                                              /*                                                  */
                                              /* Note that this is a temporary variable - the     */
                                              /* projected memory space is stored in dset_info,   */
                                              /* and will be freed when that structure is         */
                                              /* freed. */
    H5D_storage_t  store_local;               /* Local buffer for store */
    H5D_storage_t *store      = &store_local; /* Union of EFL and chunk pointer in file space */
    size_t         io_op_init = 0;            /* Number I/O ops that have been initialized */
    size_t         io_skipped =
        0;            /* Number I/O ops that have been skipped (due to the dataset not being allocated) */
    size_t i;         /* Local index variable */
    char   fake_char; /* Temporary variable for NULL buffer pointers */
    herr_t ret_value = SUCCEED; /* Return value	*/

    FUNC_ENTER_NOAPI(FAIL)

    /* Init io_info */
    if (H5D__ioinfo_init(count, dset_info, &io_info) < 0)
        HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize I/O info")
    io_info.op_type = H5D_IO_OP_READ;

    /* Allocate store buffer if necessary */
    if (count > 1)
        if (NULL == (store = (H5D_storage_t *)H5MM_malloc(count * sizeof(H5D_storage_t))))
            HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate dset storage info array buffer")

#ifdef H5_HAVE_PARALLEL
    /* Check for non-MPI-based VFD.  Only need to check first dataset since all
     * share the same file. */
    if (!(H5F_HAS_FEATURE(dset_info[0].dset->oloc.file, H5FD_FEAT_HAS_MPI))) {
        H5FD_mpio_xfer_t io_xfer_mode; /* MPI I/O transfer mode */

        /* Get I/O transfer mode */
        if (H5CX_get_io_xfer_mode(&io_xfer_mode) < 0)
            HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get MPI-I/O transfer mode")

        /* Collective access is not permissible without a MPI based VFD */
        if (io_xfer_mode == H5FD_MPIO_COLLECTIVE)
            HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "collective access for MPI-based drivers only")
    }  /* end if */
#endif /*H5_HAVE_PARALLEL*/

    /* iterate over all dsets and construct I/O information necessary to do I/O */
    for (i = 0; i < count; i++) {
        haddr_t prev_tag = HADDR_UNDEF;

        /* check args */
        if (NULL == dset_info[i].dset)
            HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset")
        if (NULL == dset_info[i].dset->oloc.file)
            HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file")

        /* set metadata tagging with dset oheader addr */
        H5AC_tag(dset_info[i].dset->oloc.addr, &prev_tag);

        /* Set up datatype info for operation */
        if (H5D__typeinfo_init(&io_info, &(dset_info[i]), dset_info[i].mem_type_id) < 0)
            HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up type info")
        type_info_init++;

        /* Make certain that the number of elements in each selection is the same, and cache nelmts in
         * dset_info */
        dset_info[i].nelmts = H5S_GET_SELECT_NPOINTS(dset_info[i].mem_space);
        if (dset_info[i].nelmts != H5S_GET_SELECT_NPOINTS(dset_info[i].file_space))
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL,
                        "src and dest dataspaces have different number of elements selected")

        /* Check for a NULL buffer */
        if (NULL == dset_info[i].buf.vp) {
            /* Check for any elements selected (which is invalid) */
            if (dset_info[i].nelmts > 0)
                HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no output buffer")

            /* If the buffer is nil, and 0 element is selected, make a fake buffer.
             * This is for some MPI package like ChaMPIon on NCSA's tungsten which
             * doesn't support this feature.
             */
            dset_info[i].buf.vp = &fake_char;
        } /* end if */

        /* Make sure that both selections have their extents set */
        if (!(H5S_has_extent(dset_info[i].file_space)))
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file dataspace does not have extent set")
        if (!(H5S_has_extent(dset_info[i].mem_space)))
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "memory dataspace does not have extent set")

        /* H5S_select_shape_same() has been modified to accept topologically identical
         * selections with different rank as having the same shape (if the most
         * rapidly changing coordinates match up), but the I/O code still has
         * difficulties with the notion.
         *
         * To solve this, we check to see if H5S_select_shape_same() returns true,
         * and if the ranks of the mem and file spaces are different.  If they are,
         * construct a new mem space that is equivalent to the old mem space, and
         * use that instead.
         *
         * Note that in general, this requires us to touch up the memory buffer as
         * well.
         */
        if (dset_info[i].nelmts > 0 &&
            TRUE == H5S_SELECT_SHAPE_SAME(dset_info[i].mem_space, dset_info[i].file_space) &&
            H5S_GET_EXTENT_NDIMS(dset_info[i].mem_space) != H5S_GET_EXTENT_NDIMS(dset_info[i].file_space)) {
            ptrdiff_t buf_adj = 0;

            /* Allocate original memory space buffer if necessary */
            if (!orig_mem_space) {
                if (count > 1) {
                    /* Allocate buffer */
                    if (NULL == (orig_mem_space = (H5S_t **)H5MM_calloc(count * sizeof(H5S_t *))))
                        HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL,
                                    "couldn't allocate original memory space array buffer")
                }
                else
                    /* Use local buffer */
                    orig_mem_space = &orig_mem_space_local;
            }

            /* Save original memory space */
            orig_mem_space[i]      = dset_info[i].mem_space;
            dset_info[i].mem_space = NULL;

            /* Attempt to construct projected dataspace for memory dataspace */
            if (H5S_select_construct_projection(orig_mem_space[i], &dset_info[i].mem_space,
                                                (unsigned)H5S_GET_EXTENT_NDIMS(dset_info[i].file_space),
                                                (hsize_t)dset_info[i].type_info.dst_type_size, &buf_adj) < 0)
                HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to construct projected memory dataspace")
            HDassert(dset_info[i].mem_space);

            /* Adjust the buffer by the given amount */
            dset_info[i].buf.vp = (void *)(((uint8_t *)dset_info[i].buf.vp) + buf_adj);
        } /* end if */

        /* If space hasn't been allocated and not using external storage,
         * return fill value to buffer if fill time is upon allocation, or
         * do nothing if fill time is never.  If the dataset is compact and
         * fill time is NEVER, there is no way to tell whether part of data
         * has been overwritten.  So just proceed in reading.
         */
        if (dset_info[i].nelmts > 0 && dset_info[i].dset->shared->dcpl_cache.efl.nused == 0 &&
            !(*dset_info[i].dset->shared->layout.ops->is_space_alloc)(
                &dset_info[i].dset->shared->layout.storage) &&
            !(dset_info[i].dset->shared->layout.ops->is_data_cached &&
              (*dset_info[i].dset->shared->layout.ops->is_data_cached)(dset_info[i].dset->shared))) {
            H5D_fill_value_t fill_status; /* Whether/How the fill value is defined */

            /* Retrieve dataset's fill-value properties */
            if (H5P_is_fill_value_defined(&dset_info[i].dset->shared->dcpl_cache.fill, &fill_status) < 0)
                HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't tell if fill value defined")

            /* Should be impossible, but check anyway... */
            if (fill_status == H5D_FILL_VALUE_UNDEFINED &&
                (dset_info[i].dset->shared->dcpl_cache.fill.fill_time == H5D_FILL_TIME_ALLOC ||
                 dset_info[i].dset->shared->dcpl_cache.fill.fill_time == H5D_FILL_TIME_IFSET))
                HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL,
                            "read failed: dataset doesn't exist, no data can be read")

            /* If we're never going to fill this dataset, just leave the junk in the user's buffer */
            if (dset_info[i].dset->shared->dcpl_cache.fill.fill_time != H5D_FILL_TIME_NEVER)
                /* Go fill the user's selection with the dataset's fill value */
                if (H5D__fill(dset_info[i].dset->shared->dcpl_cache.fill.buf, dset_info[i].dset->shared->type,
                              dset_info[i].buf.vp, dset_info[i].type_info.mem_type,
                              dset_info[i].mem_space) < 0)
                    HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "filling buf failed")

            /* No need to perform any more I/O for this dataset */
            dset_info[i].skip_io = TRUE;
            io_skipped++;
        } /* end if */
        else {
            /* Set up I/O operation */
            if (H5D__dset_ioinfo_init(dset_info[i].dset, &(dset_info[i]), &(store[i])) < 0)
                HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unable to set up I/O operation")

            /* Sanity check that space is allocated, if there are elements */
            if (dset_info[i].nelmts > 0)
                HDassert(
                    (*dset_info[i].dset->shared->layout.ops->is_space_alloc)(
                        &dset_info[i].dset->shared->layout.storage) ||
                    (dset_info[i].dset->shared->layout.ops->is_data_cached &&
                     (*dset_info[i].dset->shared->layout.ops->is_data_cached)(dset_info[i].dset->shared)) ||
                    dset_info[i].dset->shared->dcpl_cache.efl.nused > 0 ||
                    dset_info[i].dset->shared->layout.type == H5D_COMPACT);

            /* Call storage method's I/O initialization routine */
            if (dset_info[i].layout_ops.io_init &&
                (dset_info[i].layout_ops.io_init)(&io_info, &(dset_info[i])) < 0)
                HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize I/O info")
            dset_info[i].skip_io = FALSE;
            io_op_init++;

            /* Reset metadata tagging */
            H5AC_tag(prev_tag, NULL);
        }
    } /* end of for loop */

    HDassert(type_info_init == count);
    HDassert(io_op_init + io_skipped == count);

    /* If no datasets have I/O, we're done */
    if (io_op_init == 0)
        HGOTO_DONE(SUCCEED)

    /* Perform second phase of type info initialization */
    if (H5D__typeinfo_init_phase2(&io_info) < 0)
        HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up type info (second phase)")

#ifdef H5_HAVE_PARALLEL
    /* Adjust I/O info for any parallel I/O */
    if (H5D__ioinfo_adjust(&io_info) < 0)
        HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to adjust I/O info for parallel I/O")
#endif /*H5_HAVE_PARALLEL*/

    /* If multi dataset I/O callback is not provided, perform read IO via
     * single-dset path with looping */
    if (io_info.md_io_ops.multi_read_md) {
        /* Create sel_pieces array if any pieces are selected */
        if (io_info.piece_count > 0) {
            HDassert(!io_info.sel_pieces);
            HDassert(io_info.pieces_added == 0);

            /* Allocate sel_pieces array */
            if (NULL ==
                (io_info.sel_pieces = H5MM_malloc(io_info.piece_count * sizeof(io_info.sel_pieces[0]))))
                HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "unable to allocate array of selected pieces")
        }

        /* MDIO-specific second phase initialization */
        for (i = 0; i < count; i++)
            if (dset_info[i].layout_ops.mdio_init) {
                haddr_t prev_tag = HADDR_UNDEF;

                /* set metadata tagging with dset oheader addr */
                H5AC_tag(dset_info[i].dset->oloc.addr, &prev_tag);

                /* Make second phase IO init call */
                if ((dset_info[i].layout_ops.mdio_init)(&io_info, &(dset_info[i])) < 0)
                    HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't populate array of selected pieces")

                /* Reset metadata tagging */
                H5AC_tag(prev_tag, NULL);
            }

        /* Invoke correct "high level" I/O routine */
        if ((*io_info.md_io_ops.multi_read_md)(&io_info) < 0)
            HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read data")
    } /* end if */
    else {
        haddr_t prev_tag = HADDR_UNDEF;

        if (!H5D_LAYOUT_CB_PERFORM_IO(&io_info) && io_info.piece_count > 0) {
            if (NULL == (io_info.mem_spaces = H5MM_malloc(io_info.piece_count * sizeof(H5S_t *))))
                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
                            "memory allocation failed for memory space list")
            if (NULL == (io_info.file_spaces = H5MM_malloc(io_info.piece_count * sizeof(H5S_t *))))
                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "memory allocation failed for file space list")
            if (NULL == (io_info.addrs = H5MM_malloc(io_info.piece_count * sizeof(haddr_t))))
                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
                            "memory allocation failed for piece address list")
            if (NULL == (io_info.element_sizes = H5MM_malloc(io_info.piece_count * sizeof(size_t))))
                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
                            "memory allocation failed for element size list")
            if (NULL == (io_info.rbufs = H5MM_malloc(io_info.piece_count * sizeof(void *))))
                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
                            "memory allocation failed for read buffer list")
        }

        /* Loop with serial & single-dset read IO path */
        for (i = 0; i < count; i++) {
            /* Check for skipped I/O */
            if (dset_info[i].skip_io)
                continue;

            /* set metadata tagging with dset oheader addr */
            H5AC_tag(dset_info[i].dset->oloc.addr, &prev_tag);

            /* Invoke correct "high level" I/O routine */
            if ((*dset_info[i].io_ops.multi_read)(&io_info, &dset_info[i]) < 0)
                HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read data")

            /* Reset metadata tagging */
            H5AC_tag(prev_tag, NULL);
        }

        /* Make final multi dataset selection I/O call if we are using both
         * features - in this case the multi_read callbacks did not perform the
         * actual I/O */
        H5_CHECK_OVERFLOW(io_info.pieces_added, size_t, uint32_t)
        if (!H5D_LAYOUT_CB_PERFORM_IO(&io_info))
            if (H5F_shared_select_read(io_info.f_sh, H5FD_MEM_DRAW, (uint32_t)io_info.pieces_added,
                                       io_info.mem_spaces, io_info.file_spaces, io_info.addrs,
                                       io_info.element_sizes, io_info.rbufs) < 0)
                HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "selection read failed")
    }

done:
    /* Shut down the I/O op information */
    for (i = 0; i < io_op_init; i++)
        if (!dset_info[i].skip_io && dset_info[i].layout_ops.io_term &&
            (*dset_info[i].layout_ops.io_term)(&io_info, &(dset_info[i])) < 0)
            HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down I/O op info")

    /* Shut down datatype info for operation */
    if (H5D__typeinfo_term(&io_info, type_info_init) < 0)
        HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down type info")

    /* Discard projected mem spaces and restore originals */
    if (orig_mem_space) {
        for (i = 0; i < count; i++)
            if (orig_mem_space[i]) {
                if (H5S_close(dset_info[i].mem_space) < 0)
                    HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL,
                                "unable to shut down projected memory dataspace")
                dset_info[i].mem_space = orig_mem_space[i];
            }

        /* Free orig_mem_space array if it was allocated */
        if (orig_mem_space != &orig_mem_space_local)
            H5MM_free(orig_mem_space);
    }

    /* Free global piece array */
    H5MM_xfree(io_info.sel_pieces);

    /* Free selection I/O arrays */
    H5MM_xfree(io_info.mem_spaces);
    H5MM_xfree(io_info.file_spaces);
    H5MM_xfree(io_info.addrs);
    H5MM_xfree(io_info.element_sizes);
    H5MM_xfree(io_info.rbufs);

    /* Free store array if it was allocated */
    if (store != &store_local)
        H5MM_free(store);

    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5D__read() */

/*-------------------------------------------------------------------------
 * Function:	H5D__write
 *
 * Purpose:	Writes multiple (part of) DATASETs to a file from application
 *          memory BUFs. See H5Dwrite_multi() for complete details.
 *
 *          This was referred from H5D__write for multi-dset work.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5D__write(size_t count, H5D_dset_io_info_t *dset_info)
{
    H5D_io_info_t io_info;                    /* Dataset I/O info for multi dsets */
    size_t        type_info_init = 0;         /* Number of datatype info structs that have been initialized */
    H5S_t        *orig_mem_space_local;       /* Local buffer for orig_mem_space */
    H5S_t       **orig_mem_space = NULL;      /* If not NULL, ptr to an array of dataspaces       */
                                              /* containing the original memory spaces contained  */
                                              /* in dset_info.  This is needed in order to        */
                                              /* restore the original state of  dset_info if we   */
                                              /* replaced any mem spaces with equivalents         */
                                              /* projected to a rank equal to that of file_space. */
                                              /*                                                  */
                                              /* This field is only used if                       */
                                              /* H5S_select_shape_same() returns TRUE when        */
                                              /* comparing at least one mem_space and data_space, */
                                              /* and the mem_space has a different rank.          */
                                              /*                                                  */
                                              /* Note that this is a temporary variable - the     */
                                              /* projected memory space is stored in dset_info,   */
                                              /* and will be freed when that structure is         */
                                              /* freed. */
    H5D_storage_t  store_local;               /* Local buffer for store */
    H5D_storage_t *store      = &store_local; /* Union of EFL and chunk pointer in file space */
    size_t         io_op_init = 0;            /* Number I/O ops that have been initialized */
    size_t         i;                         /* Local index variable */
    char           fake_char;                 /* Temporary variable for NULL buffer pointers */
    herr_t         ret_value = SUCCEED;       /* Return value	*/

    FUNC_ENTER_NOAPI(FAIL)

    /* Init io_info */
    if (H5D__ioinfo_init(count, dset_info, &io_info) < 0)
        HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize I/O info")
    io_info.op_type = H5D_IO_OP_WRITE;

    /* Allocate store buffer if necessary */
    if (count > 1)
        if (NULL == (store = (H5D_storage_t *)H5MM_malloc(count * sizeof(H5D_storage_t))))
            HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate dset storage info array buffer")

    /* iterate over all dsets and construct I/O information */
    for (i = 0; i < count; i++) {
        hbool_t should_alloc_space = FALSE; /* Whether or not to initialize dataset's storage */
        haddr_t prev_tag           = HADDR_UNDEF;

        /* check args */
        if (NULL == dset_info[i].dset)
            HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset")
        if (NULL == dset_info[i].dset->oloc.file)
            HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file")

        /* set metadata tagging with dset oheader addr */
        H5AC_tag(dset_info[i].dset->oloc.addr, &prev_tag);

        /* All filters in the DCPL must have encoding enabled. */
        if (!dset_info[i].dset->shared->checked_filters) {
            if (H5Z_can_apply(dset_info[i].dset->shared->dcpl_id, dset_info[i].dset->shared->type_id) < 0)
                HGOTO_ERROR(H5E_PLINE, H5E_CANAPPLY, FAIL, "can't apply filters")

            dset_info[i].dset->shared->checked_filters = TRUE;
        } /* end if */

        /* Check if we are allowed to write to this file */
        if (0 == (H5F_INTENT(dset_info[i].dset->oloc.file) & H5F_ACC_RDWR))
            HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "no write intent on file")

        /* Set up datatype info for operation */
        if (H5D__typeinfo_init(&io_info, &(dset_info[i]), dset_info[i].mem_type_id) < 0)
            HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up type info")
        type_info_init++;

        /* Various MPI based checks */
#ifdef H5_HAVE_PARALLEL
        if (H5F_HAS_FEATURE(dset_info[i].dset->oloc.file, H5FD_FEAT_HAS_MPI)) {
            /* If MPI based VFD is used, no VL or region reference datatype support yet. */
            /* This is because they use the global heap in the file and we don't */
            /* support parallel access of that yet */
            if (H5T_is_vl_storage(dset_info[i].type_info.mem_type) > 0)
                HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL,
                            "Parallel IO does not support writing VL or region reference datatypes yet")
        } /* end if */
        else {
            H5FD_mpio_xfer_t io_xfer_mode; /* MPI I/O transfer mode */

            /* Get I/O transfer mode */
            if (H5CX_get_io_xfer_mode(&io_xfer_mode) < 0)
                HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get MPI-I/O transfer mode")

            /* Collective access is not permissible without a MPI based VFD */
            if (io_xfer_mode == H5FD_MPIO_COLLECTIVE)
                HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "collective access for MPI-based driver only")
        } /* end else */
#endif    /*H5_HAVE_PARALLEL*/

        /* Make certain that the number of elements in each selection is the same, and cache nelmts in
         * dset_info */
        dset_info[i].nelmts = H5S_GET_SELECT_NPOINTS(dset_info[i].mem_space);
        if (dset_info[i].nelmts != H5S_GET_SELECT_NPOINTS(dset_info[i].file_space))
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL,
                        "src and dest dataspaces have different number of elements selected")

        /* Check for a NULL buffer */
        if (NULL == dset_info[i].buf.cvp) {
            /* Check for any elements selected (which is invalid) */
            if (dset_info[i].nelmts > 0)
                HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no output buffer")

            /* If the buffer is nil, and 0 element is selected, make a fake buffer.
             * This is for some MPI package like ChaMPIon on NCSA's tungsten which
             * doesn't support this feature.
             */
            dset_info[i].buf.cvp = &fake_char;
        } /* end if */

        /* Make sure that both selections have their extents set */
        if (!(H5S_has_extent(dset_info[i].file_space)))
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file dataspace does not have extent set")
        if (!(H5S_has_extent(dset_info[i].mem_space)))
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "memory dataspace does not have extent set")

        /* H5S_select_shape_same() has been modified to accept topologically
         * identical selections with different rank as having the same shape
         * (if the most rapidly changing coordinates match up), but the I/O
         * code still has difficulties with the notion.
         *
         * To solve this, we check to see if H5S_select_shape_same() returns
         * true, and if the ranks of the mem and file spaces are different.
         * If they are, construct a new mem space that is equivalent to the
         * old mem space, and use that instead.
         *
         * Note that in general, this requires us to touch up the memory buffer
         * as well.
         */
        if (dset_info[i].nelmts > 0 &&
            TRUE == H5S_SELECT_SHAPE_SAME(dset_info[i].mem_space, dset_info[i].file_space) &&
            H5S_GET_EXTENT_NDIMS(dset_info[i].mem_space) != H5S_GET_EXTENT_NDIMS(dset_info[i].file_space)) {
            ptrdiff_t buf_adj = 0;

            /* Allocate original memory space buffer if necessary */
            if (!orig_mem_space) {
                if (count > 1) {
                    /* Allocate buffer */
                    if (NULL == (orig_mem_space = (H5S_t **)H5MM_calloc(count * sizeof(H5S_t *))))
                        HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL,
                                    "couldn't allocate original memory space array buffer")
                }
                else
                    /* Use local buffer */
                    orig_mem_space = &orig_mem_space_local;
            }

            /* Save original memory space */
            orig_mem_space[i]      = dset_info[i].mem_space;
            dset_info[i].mem_space = NULL;

            /* Attempt to construct projected dataspace for memory dataspace */
            if (H5S_select_construct_projection(orig_mem_space[i], &dset_info[i].mem_space,
                                                (unsigned)H5S_GET_EXTENT_NDIMS(dset_info[i].file_space),
                                                dset_info[i].type_info.src_type_size, &buf_adj) < 0)
                HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to construct projected memory dataspace")
            HDassert(dset_info[i].mem_space);

            /* Adjust the buffer by the given amount */
            dset_info[i].buf.cvp = (const void *)(((const uint8_t *)dset_info[i].buf.cvp) + buf_adj);
        } /* end if */

        /* Retrieve dataset properties */
        /* <none needed currently> */

        /* Set up I/O operation */
        if (H5D__dset_ioinfo_init(dset_info[i].dset, &(dset_info[i]), &(store[i])) < 0)
            HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up I/O operation")

        /* Allocate dataspace and initialize it if it hasn't been. */
        should_alloc_space = dset_info[i].dset->shared->dcpl_cache.efl.nused == 0 &&
                             !(*dset_info[i].dset->shared->layout.ops->is_space_alloc)(
                                 &dset_info[i].dset->shared->layout.storage);

        /*
         * If not using an MPI-based VFD, we only need to allocate
         * and initialize storage if there's a selection in the
         * dataset's dataspace. Otherwise, we always need to participate
         * in the storage allocation since this may use collective
         * operations and we will hang if we don't participate.
         */
        if (!H5F_HAS_FEATURE(dset_info[i].dset->oloc.file, H5FD_FEAT_HAS_MPI))
            should_alloc_space = should_alloc_space && (dset_info[i].nelmts > 0);

        if (should_alloc_space) {
            hssize_t file_nelmts;    /* Number of elements in file dataset's dataspace */
            hbool_t  full_overwrite; /* Whether we are over-writing all the elements */

            /* Get the number of elements in file dataset's dataspace */
            if ((file_nelmts = H5S_GET_EXTENT_NPOINTS(dset_info[i].file_space)) < 0)
                HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL,
                            "can't retrieve number of elements in file dataset")

            /* Always allow fill values to be written if the dataset has a VL datatype */
            if (H5T_detect_class(dset_info[i].dset->shared->type, H5T_VLEN, FALSE))
                full_overwrite = FALSE;
            else
                full_overwrite = (hbool_t)((hsize_t)file_nelmts == dset_info[i].nelmts ? TRUE : FALSE);

            /* Allocate storage */
            if (H5D__alloc_storage(dset_info[i].dset, H5D_ALLOC_WRITE, full_overwrite, NULL) < 0)
                HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize storage")
        } /* end if */

        /* Call storage method's I/O initialization routine */
        /* Init io_info.dset_info[] and generate piece_info in skip list */
        if (dset_info[i].layout_ops.io_init &&
            (*dset_info[i].layout_ops.io_init)(&io_info, &(dset_info[i])) < 0)
            HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize I/O info")
        dset_info[i].skip_io = FALSE;
        io_op_init++;

        /* Reset metadata tagging */
        H5AC_tag(prev_tag, NULL);
    } /* end of for loop */

    HDassert(type_info_init == count);
    HDassert(io_op_init == count);

    /* Perform second phase of type info initialization */
    if (H5D__typeinfo_init_phase2(&io_info) < 0)
        HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up type info (second phase)")

#ifdef H5_HAVE_PARALLEL
    /* Adjust I/O info for any parallel I/O */
    if (H5D__ioinfo_adjust(&io_info) < 0)
        HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to adjust I/O info for parallel I/O")
#endif /*H5_HAVE_PARALLEL*/

    /* If multi dataset I/O callback is not provided, perform write IO via
     * single-dset path with looping */
    if (io_info.md_io_ops.multi_write_md) {
        /* Create sel_pieces array if any pieces are selected */
        if (io_info.piece_count > 0) {
            HDassert(!io_info.sel_pieces);
            HDassert(io_info.pieces_added == 0);

            /* Allocate sel_pieces array */
            if (NULL ==
                (io_info.sel_pieces = H5MM_malloc(io_info.piece_count * sizeof(io_info.sel_pieces[0]))))
                HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "unable to allocate array of selected pieces")
        }

        /* MDIO-specific second phase initialization */
        for (i = 0; i < count; i++)
            if (dset_info[i].layout_ops.mdio_init) {
                haddr_t prev_tag = HADDR_UNDEF;

                /* set metadata tagging with dset oheader addr */
                H5AC_tag(dset_info[i].dset->oloc.addr, &prev_tag);

                /* Make second phase IO init call */
                if ((dset_info[i].layout_ops.mdio_init)(&io_info, &(dset_info[i])) < 0)
                    HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't populate array of selected pieces")

                /* Reset metadata tagging */
                H5AC_tag(prev_tag, NULL);
            }

        /* Invoke correct "high level" I/O routine */
        if ((*io_info.md_io_ops.multi_write_md)(&io_info) < 0)
            HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't write data")
    } /* end if */
    else {
        haddr_t prev_tag = HADDR_UNDEF;

        if (!H5D_LAYOUT_CB_PERFORM_IO(&io_info) && io_info.piece_count > 0) {
            if (NULL == (io_info.mem_spaces = H5MM_malloc(io_info.piece_count * sizeof(H5S_t *))))
                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
                            "memory allocation failed for memory space list")
            if (NULL == (io_info.file_spaces = H5MM_malloc(io_info.piece_count * sizeof(H5S_t *))))
                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "memory allocation failed for file space list")
            if (NULL == (io_info.addrs = H5MM_malloc(io_info.piece_count * sizeof(haddr_t))))
                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
                            "memory allocation failed for piece address list")
            if (NULL == (io_info.element_sizes = H5MM_malloc(io_info.piece_count * sizeof(size_t))))
                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
                            "memory allocation failed for element size list")
            if (NULL == (io_info.wbufs = H5MM_malloc(io_info.piece_count * sizeof(const void *))))
                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
                            "memory allocation failed for read buffer list")
        }

        /* loop with serial & single-dset write IO path */
        for (i = 0; i < count; i++) {
            HDassert(!dset_info[i].skip_io);

            /* set metadata tagging with dset oheader addr */
            H5AC_tag(dset_info->dset->oloc.addr, &prev_tag);

            /* Invoke correct "high level" I/O routine */
            if ((*dset_info[i].io_ops.multi_write)(&io_info, &dset_info[i]) < 0)
                HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't write data")

            /* Reset metadata tagging */
            H5AC_tag(prev_tag, NULL);
        }

        /* Make final multi dataset selection I/O call if we are using both
         * features - in this case the multi_write callbacks did not perform the
         * actual I/O */
        H5_CHECK_OVERFLOW(io_info.pieces_added, size_t, uint32_t)
        if (!H5D_LAYOUT_CB_PERFORM_IO(&io_info))
            if (H5F_shared_select_write(io_info.f_sh, H5FD_MEM_DRAW, (uint32_t)io_info.pieces_added,
                                        io_info.mem_spaces, io_info.file_spaces, io_info.addrs,
                                        io_info.element_sizes, io_info.wbufs) < 0)
                HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "selection write failed")
    }

#ifdef OLD_WAY
    /*
     * This was taken out because it can be called in a parallel program with
     * independent access, causing the metadata cache to get corrupted. Its been
     * disabled for all types of access (serial as well as parallel) to make the
     * modification time consistent for all programs. -QAK
     *
     * We should set a value in the dataset's shared information instead and flush
     * it to the file when the dataset is being closed. -QAK
     */
    /*
     * Update modification time.  We have to do this explicitly because
     * writing to a dataset doesn't necessarily change the object header.
     */
    if (H5O_touch(&(dataset->oloc), FALSE) < 0)
        HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to update modification time")
#endif /* OLD_WAY */

done:
    /* Shut down the I/O op information */
    for (i = 0; i < io_op_init; i++) {
        HDassert(!dset_info[i].skip_io);
        if (dset_info[i].layout_ops.io_term &&
            (*dset_info[i].layout_ops.io_term)(&io_info, &(dset_info[i])) < 0)
            HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down I/O op info")
    }

    /* Shut down datatype info for operation */
    if (H5D__typeinfo_term(&io_info, type_info_init) < 0)
        HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down type info")

    /* Discard projected mem spaces and restore originals */
    if (orig_mem_space) {
        for (i = 0; i < count; i++)
            if (orig_mem_space[i]) {
                if (H5S_close(dset_info[i].mem_space) < 0)
                    HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL,
                                "unable to shut down projected memory dataspace")
                dset_info[i].mem_space = orig_mem_space[i];
            }

        /* Free orig_mem_space array if it was allocated */
        if (orig_mem_space != &orig_mem_space_local)
            H5MM_free(orig_mem_space);
    }

    /* Free global piece array */
    H5MM_xfree(io_info.sel_pieces);

    /* Free store array if it was allocated */
    if (store != &store_local)
        H5MM_free(store);

    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5D__write */

/*-------------------------------------------------------------------------
 * Function:	H5D__ioinfo_init
 *
 * Purpose:	General setup for H5D_io_info_t struct
 *
 * Return:	Non-negative on success/Negative on failure
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5D__ioinfo_init(size_t count, H5D_dset_io_info_t *dset_info, H5D_io_info_t *io_info)
{
    FUNC_ENTER_PACKAGE_NOERR

    /* check args */
    HDassert(count > 0);
    HDassert(dset_info);
    HDassert(dset_info[0].dset->oloc.file);
    HDassert(io_info);

    /* Zero out struct */
    HDmemset(io_info, 0, sizeof(*io_info));

    /* Set up simple fields */
    io_info->f_sh  = count > 0 ? H5F_SHARED(dset_info[0].dset->oloc.file) : NULL;
    io_info->count = count;

    /* Start without multi-dataset I/O ops. If we're not using the collective
     * I/O path then we will call the single dataset callbacks in a loop. */

    /* Use provided dset_info */
    io_info->dsets_info = dset_info;

    /* Start with selection I/O on if the global is on, layout callback will
     * turn it off if appropriate */
    io_info->use_select_io = H5_use_selection_io_g;

#ifdef H5_HAVE_PARALLEL
    /* Determine if the file was opened with an MPI VFD */
    if (count > 0)
        io_info->using_mpi_vfd = H5F_HAS_FEATURE(dset_info[0].dset->oloc.file, H5FD_FEAT_HAS_MPI);
#endif /* H5_HAVE_PARALLEL */

    FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5D__ioinfo_init() */

/*-------------------------------------------------------------------------
 * Function:	H5D__dset_ioinfo_init
 *
 * Purpose:	Routine for determining correct I/O operations for each I/O action.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5D__dset_ioinfo_init(H5D_t *dset, H5D_dset_io_info_t *dset_info, H5D_storage_t *store)
{
    FUNC_ENTER_PACKAGE_NOERR

    /* check args */
    HDassert(dset);
    HDassert(dset->oloc.file);
    HDassert(dset_info->type_info.tpath);

    /* Set up "normal" I/O fields */
    dset_info->dset  = dset;
    dset_info->store = store;

    /* Set I/O operations to initial values */
    dset_info->layout_ops = *dset->shared->layout.ops;

    /* Set the "high-level" I/O operations for the dataset */
    dset_info->io_ops.multi_read  = dset->shared->layout.ops->ser_read;
    dset_info->io_ops.multi_write = dset->shared->layout.ops->ser_write;

    /* Set the I/O operations for reading/writing single blocks on disk */
    if (dset_info->type_info.is_xform_noop && dset_info->type_info.is_conv_noop) {
        /*
         * If there is no data transform or type conversion then read directly
         * into the application's buffer.
         * This saves at least one mem-to-mem copy.
         */
        dset_info->io_ops.single_read  = H5D__select_read;
        dset_info->io_ops.single_write = H5D__select_write;
    } /* end if */
    else {
        /*
         * This is the general case (type conversion, usually).
         */
        dset_info->io_ops.single_read  = H5D__scatgath_read;
        dset_info->io_ops.single_write = H5D__scatgath_write;
    } /* end else */

    FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5D__dset_ioinfo_init() */

/*-------------------------------------------------------------------------
 * Function:	H5D__typeinfo_init
 *
 * Purpose:	Routine for determining correct datatype information for
 *              each I/O action.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Quincey Koziol
 *		Tuesday, March  4, 2008
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5D__typeinfo_init(H5D_io_info_t *io_info, H5D_dset_io_info_t *dset_info, hid_t mem_type_id)
{
    H5D_type_info_t  *type_info;
    const H5D_t      *dset;
    const H5T_t      *src_type;            /* Source datatype */
    const H5T_t      *dst_type;            /* Destination datatype */
    H5Z_data_xform_t *data_transform;      /* Data transform info */
    herr_t            ret_value = SUCCEED; /* Return value	*/

    FUNC_ENTER_PACKAGE

    /* check args */
    HDassert(io_info);
    HDassert(dset_info);

    /* Set convenience pointers */
    type_info = &dset_info->type_info;
    dset      = dset_info->dset;
    HDassert(dset);

    /* Patch the top level file pointer for dt->shared->u.vlen.f if needed */
    if (H5T_patch_vlen_file(dset->shared->type, H5F_VOL_OBJ(dset->oloc.file)) < 0)
        HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't patch VL datatype file pointer")

    /* Initialize type info safely */
    HDmemset(type_info, 0, sizeof(*type_info));

    /* Get the memory & dataset datatypes */
    if (NULL == (type_info->mem_type = (const H5T_t *)H5I_object_verify(mem_type_id, H5I_DATATYPE)))
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
    type_info->dset_type = dset->shared->type;

    if (io_info->op_type == H5D_IO_OP_WRITE) {
        src_type               = type_info->mem_type;
        dst_type               = dset->shared->type;
        type_info->src_type_id = mem_type_id;
        type_info->dst_type_id = dset->shared->type_id;
    } /* end if */
    else {
        src_type               = dset->shared->type;
        dst_type               = type_info->mem_type;
        type_info->src_type_id = dset->shared->type_id;
        type_info->dst_type_id = mem_type_id;
    } /* end else */

    /* Locate the type conversion function and dataspace conversion
     * functions, and set up the element numbering information. If a data
     * type conversion is necessary then register datatype IDs. Data type
     * conversion is necessary if the user has set the `need_bkg' to a high
     * enough value in xfer_parms since turning off datatype conversion also
     * turns off background preservation.
     */
    if (NULL == (type_info->tpath = H5T_path_find(src_type, dst_type)))
        HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unable to convert between src and dest datatype")

    /* Retrieve info from API context */
    if (H5CX_get_data_transform(&data_transform) < 0)
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get data transform info")

    /* Precompute some useful information */
    type_info->src_type_size = H5T_get_size(src_type);
    type_info->dst_type_size = H5T_get_size(dst_type);
    type_info->is_conv_noop  = H5T_path_noop(type_info->tpath);
    type_info->is_xform_noop = H5Z_xform_noop(data_transform);
    if (type_info->is_xform_noop && type_info->is_conv_noop) {
        type_info->cmpd_subset = NULL;
        type_info->need_bkg    = H5T_BKG_NO;
    } /* end if */
    else {
        H5T_bkg_t bkgr_buf_type; /* Background buffer type */

        /* Get info from API context */
        if (H5CX_get_bkgr_buf_type(&bkgr_buf_type) < 0)
            HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve background buffer type")

        /* Check if the datatypes are compound subsets of one another */
        type_info->cmpd_subset = H5T_path_compound_subset(type_info->tpath);

        /* Update io_info->max_type_size */
        io_info->max_type_size =
            MAX3(io_info->max_type_size, type_info->src_type_size, type_info->dst_type_size);

        /* Check if we need a background buffer */
        if ((io_info->op_type == H5D_IO_OP_WRITE) && H5T_detect_class(dset->shared->type, H5T_VLEN, FALSE))
            type_info->need_bkg = H5T_BKG_YES;
        else {
            H5T_bkg_t path_bkg; /* Type conversion's background info */

            if ((path_bkg = H5T_path_bkg(type_info->tpath))) {
                /* Retrieve the bkgr buffer property */
                type_info->need_bkg = bkgr_buf_type;
                type_info->need_bkg = MAX(path_bkg, type_info->need_bkg);
            } /* end if */
            else
                type_info->need_bkg = H5T_BKG_NO; /*never needed even if app says yes*/
        }                                         /* end else */
    }                                             /* end else */

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5D__typeinfo_init() */

/*-------------------------------------------------------------------------
 * Function:    H5D__typeinfo_init_phase2
 *
 * Purpose:     Finish initializing type info for all datasets after
 *              calculating the max type size across all datasets.
 *
 * Return:      Non-negative on success/Negative on failure
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5D__typeinfo_init_phase2(H5D_io_info_t *io_info)
{
    herr_t ret_value = SUCCEED; /* Return value */

    FUNC_ENTER_PACKAGE

    /* check args */
    HDassert(io_info);

    /* Check if we need to allocate a shared type conversion buffer */
    if (io_info->max_type_size) {
        void  *tconv_buf;    /* Temporary conversion buffer pointer */
        void  *bkgr_buf;     /* Background conversion buffer pointer */
        size_t max_temp_buf; /* Maximum temporary buffer size */
        size_t target_size;  /* Desired buffer size	*/
        size_t i;            /* Local index variable */

        /* Get info from API context */
        if (H5CX_get_max_temp_buf(&max_temp_buf) < 0)
            HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve max. temp. buf size")
        if (H5CX_get_tconv_buf(&tconv_buf) < 0)
            HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve temp. conversion buffer pointer")
        if (H5CX_get_bkgr_buf(&bkgr_buf) < 0)
            HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve background conversion buffer pointer")

        /* Set up datatype conversion/background buffers */
        target_size = max_temp_buf;

        /* If the buffer is too small to hold even one element (in the dataset with the largest , try to make
         * it bigger */
        if (target_size < io_info->max_type_size) {
            hbool_t default_buffer_info; /* Whether the buffer information are the defaults */

            /* Detect if we have all default settings for buffers */
            default_buffer_info =
                (hbool_t)((H5D_TEMP_BUF_SIZE == max_temp_buf) && (NULL == tconv_buf) && (NULL == bkgr_buf));

            /* Check if we are using the default buffer info */
            if (default_buffer_info)
                /* OK to get bigger for library default settings */
                target_size = io_info->max_type_size;
            else
                /* Don't get bigger than the application has requested */
                HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "temporary buffer max size is too small")
        } /* end if */

        /* Get a temporary buffer for type conversion unless the app has already
         * supplied one through the xfer properties. Instead of allocating a
         * buffer which is the exact size, we allocate the target size. This
         * buffer is shared among all datasets in the operation, unlike for the
         * background buffer, where each dataset gets its own. */
        if (NULL == (io_info->tconv_buf = (uint8_t *)tconv_buf)) {
            /* Allocate temporary buffer */
            if (NULL == (io_info->tconv_buf = H5FL_BLK_MALLOC(type_conv, target_size)))
                HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for type conversion")
            io_info->tconv_buf_allocated = TRUE;
        } /* end if */

        /* Don't use API provided background buffer if there's more than one dataset, since each
         * dataset needs its own */
        if (io_info->count > 1)
            bkgr_buf = NULL;

        /* Iterate over datasets */
        for (i = 0; i < io_info->count; i++) {
            H5D_type_info_t *type_info = &io_info->dsets_info[i].type_info;

            /* Compute the number of elements that will fit into buffer */
            type_info->request_nelmts = target_size / MAX(type_info->src_type_size, type_info->dst_type_size);
            ;

            /* Sanity check elements in temporary buffer */
            if (type_info->request_nelmts == 0)
                HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "temporary buffer max size is too small")

            /* Allocate background buffer if necessary */
            if (type_info->need_bkg && NULL == (type_info->bkg_buf = (uint8_t *)bkgr_buf)) {
                size_t bkg_size; /* Desired background buffer size	*/

                /* Compute the background buffer size */
                /* (don't try to use buffers smaller than the default size) */
                bkg_size = type_info->request_nelmts * type_info->dst_type_size;
                if (bkg_size < max_temp_buf)
                    bkg_size = max_temp_buf;

                /* Allocate background buffer */
                /* (Need calloc()-like call since memory needs to be initialized) */
                if (NULL == (type_info->bkg_buf = H5FL_BLK_CALLOC(type_conv, bkg_size)))
                    HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL,
                                "memory allocation failed for background conversion")
                type_info->bkg_buf_allocated = TRUE;
            } /* end if */
        }
    }

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5D__typeinfo_init_phase2() */

#ifdef H5_HAVE_PARALLEL

/*-------------------------------------------------------------------------
 * Function:	H5D__ioinfo_adjust
 *
 * Purpose:	Adjust operation's I/O info for any parallel I/O
 *
 *          This was derived from H5D__ioinfo_adjust for multi-dset work.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5D__ioinfo_adjust(H5D_io_info_t *io_info)
{
    H5D_t *dset0;               /* only the first dset , also for single dsets case */
    herr_t ret_value = SUCCEED; /* Return value	*/

    FUNC_ENTER_PACKAGE

    /* check args */
    HDassert(io_info);

    /* check the first dset, should exist either single or multi dset cases */
    HDassert(io_info->dsets_info[0].dset);
    dset0 = io_info->dsets_info[0].dset;
    HDassert(dset0->oloc.file);

    /* Reset the actual io mode properties to the default values in case
     * the DXPL (if it's non-default) was previously used in a collective
     * I/O operation.
     */
    if (!H5CX_is_def_dxpl()) {
        H5CX_set_mpio_actual_chunk_opt(H5D_MPIO_NO_CHUNK_OPTIMIZATION);
        H5CX_set_mpio_actual_io_mode(H5D_MPIO_NO_COLLECTIVE);
    } /* end if */

    /* Make any parallel I/O adjustments */
    if (io_info->using_mpi_vfd) {
        H5FD_mpio_xfer_t xfer_mode; /* Parallel transfer for this request */
        htri_t           opt;       /* Flag whether a selection is optimizable */

        /* Get the original state of parallel I/O transfer mode */
        if (H5CX_get_io_xfer_mode(&xfer_mode) < 0)
            HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get MPI-I/O transfer mode")

        /* Get MPI communicator */
        if (MPI_COMM_NULL == (io_info->comm = H5F_mpi_get_comm(dset0->oloc.file)))
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't retrieve MPI communicator")

        /* Check if we can set direct MPI-IO read/write functions */
        if ((opt = H5D__mpio_opt_possible(io_info)) < 0)
            HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "invalid check for direct IO dataspace ")

        /* Check if we can use the optimized parallel I/O routines */
        if (opt == TRUE) {
            /* Override the I/O op pointers to the MPI-specific routines, unless
             * selection I/O is to be used - in this case the file driver will
             * handle collective I/O */
            /* Check for selection/vector support in file driver? -NAF */
            if (!io_info->use_select_io) {
                io_info->md_io_ops.multi_read_md   = H5D__collective_read;
                io_info->md_io_ops.multi_write_md  = H5D__collective_write;
                io_info->md_io_ops.single_read_md  = H5D__mpio_select_read;
                io_info->md_io_ops.single_write_md = H5D__mpio_select_write;
            } /* end if */
        }     /* end if */
        else {
            /* Fail when file sync is required, since it requires collective write */
            if (io_info->op_type == H5D_IO_OP_WRITE) {
                hbool_t mpi_file_sync_required = FALSE;
                if (H5F_shared_get_mpi_file_sync_required(io_info->f_sh, &mpi_file_sync_required) < 0)
                    HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get MPI file_sync_required flag")

                if (mpi_file_sync_required)
                    HGOTO_ERROR(
                        H5E_DATASET, H5E_NO_INDEPENDENT, FAIL,
                        "Can't perform independent write when MPI_File_sync is required by ROMIO driver.")
            }

            /* Check if there are any filters in the pipeline. If there are,
             * we cannot break to independent I/O if this is a write operation
             * with multiple ranks involved; otherwise, there will be metadata
             * inconsistencies in the file.
             */
            if (io_info->op_type == H5D_IO_OP_WRITE) {
                size_t i;

                /* Check all datasets for filters */
                for (i = 0; i < io_info->count; i++)
                    if (io_info->dsets_info[i].dset->shared->dcpl_cache.pline.nused > 0)
                        break;

                /* If the above loop didn't complete at least one dataset has a filter */
                if (i < io_info->count) {
                    int comm_size = 0;

                    /* Retrieve size of MPI communicator used for file */
                    if ((comm_size = H5F_shared_mpi_get_size(io_info->f_sh)) < 0)
                        HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't get MPI communicator size")

                    if (comm_size > 1) {
                        char local_no_coll_cause_string[512];
                        char global_no_coll_cause_string[512];

                        if (H5D__mpio_get_no_coll_cause_strings(local_no_coll_cause_string, 512,
                                                                global_no_coll_cause_string, 512) < 0)
                            HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL,
                                        "can't get reasons for breaking collective I/O")

                        HGOTO_ERROR(H5E_IO, H5E_NO_INDEPENDENT, FAIL,
                                    "Can't perform independent write with filters in pipeline.\n"
                                    "    The following caused a break from collective I/O:\n"
                                    "        Local causes: %s\n"
                                    "        Global causes: %s",
                                    local_no_coll_cause_string, global_no_coll_cause_string);
                    }
                }
            }

            /* If we won't be doing collective I/O, but the user asked for
             * collective I/O, change the request to use independent I/O
             */
            if (xfer_mode == H5FD_MPIO_COLLECTIVE) {
                /* Change the xfer_mode to independent for handling the I/O */
                if (H5CX_set_io_xfer_mode(H5FD_MPIO_INDEPENDENT) < 0)
                    HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't set MPI-I/O transfer mode")
            } /* end if */
        }     /* end else */
    }         /* end if */

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5D__ioinfo_adjust() */
#endif /* H5_HAVE_PARALLEL */

/*-------------------------------------------------------------------------
 * Function:    H5D__typeinfo_term
 *
 * Purpose:     Common logic for terminating a type info object
 *
 * Return:      Non-negative on success/Negative on failure
 *
 * Programmer:  Quincey Koziol
 *              Thursday, March  6, 2008
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5D__typeinfo_term(H5D_io_info_t *io_info, size_t type_info_init)
{
    size_t i;

    FUNC_ENTER_PACKAGE_NOERR

    /* Check for releasing datatype conversion & background buffers */
    if (io_info->tconv_buf_allocated) {
        HDassert(io_info->tconv_buf);
        (void)H5FL_BLK_FREE(type_conv, io_info->tconv_buf);
    } /* end if */
    for (i = 0; i < type_info_init; i++)
        if (io_info->dsets_info[i].type_info.bkg_buf_allocated) {
            HDassert(io_info->dsets_info[i].type_info.bkg_buf);
            (void)H5FL_BLK_FREE(type_conv, io_info->dsets_info[i].type_info.bkg_buf);
        } /* end if */

    FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5D__typeinfo_term() */