summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--release_docs/RELEASE.txt3
-rw-r--r--src/H5FDdirect.c233
2 files changed, 156 insertions, 80 deletions
diff --git a/release_docs/RELEASE.txt b/release_docs/RELEASE.txt
index 8a0baab..881e0d8 100644
--- a/release_docs/RELEASE.txt
+++ b/release_docs/RELEASE.txt
@@ -234,6 +234,9 @@ Bug Fixes since HDF5-1.8.0 release
Library
-------
+ - Fixed a bug in the direct I/O driver that could render files with
+ certain kinds of unaligned data unreadable or corrupt them.
+ (NAF - 2010/07/28)
- valgrind reported an error of copying data to itself when a new attribute
is written (Bug #1956). I fixed it by taking out the memcpy step in
the attribute code. (SLU - 2010/07/28)
diff --git a/src/H5FDdirect.c b/src/H5FDdirect.c
index 8219941..70b33f7 100644
--- a/src/H5FDdirect.c
+++ b/src/H5FDdirect.c
@@ -571,7 +571,7 @@ H5FD_direct_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxadd
if (HDposix_memalign(&buf2, file->fa.mboundary, file->fa.fbsize) != 0)
HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, NULL, "HDposix_memalign failed")
- if(o_flags &= O_CREAT) {
+ if(o_flags & O_CREAT) {
if(write(file->fd, (void*)buf1, sizeof(int))<0) {
if(write(file->fd, (void*)buf2, file->fa.fbsize)<0)
HGOTO_ERROR(H5E_FILE, H5E_WRITEERROR, NULL, "file system may not support Direct I/O")
@@ -587,8 +587,17 @@ H5FD_direct_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxadd
HGOTO_ERROR(H5E_FILE, H5E_READERROR, NULL, "file system may not support Direct I/O")
else
file->fa.must_align = TRUE;
- } else
- file->fa.must_align = FALSE;
+ } else {
+ if(o_flags & O_RDWR) {
+ if(file_seek(file->fd, (file_offset_t)0, SEEK_SET) < 0)
+ HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, NULL, "unable to seek to proper position")
+ if(write(file->fd, (void *)buf1, sizeof(int))<0)
+ file->fa.must_align = TRUE;
+ else
+ file->fa.must_align = FALSE;
+ } else
+ file->fa.must_align = FALSE;
+ }
}
if(buf1)
@@ -911,12 +920,13 @@ H5FD_direct_read(H5FD_t *_file, H5FD_mem_t UNUSED type, hid_t UNUSED dxpl_id, ha
hbool_t _must_align = TRUE;
herr_t ret_value=SUCCEED; /* Return value */
size_t alloc_size;
- void *copy_buf, *p2, *p3;
+ void *copy_buf = NULL, *p2;
size_t _boundary;
size_t _fbsize;
size_t _cbsize;
- haddr_t copy_addr = addr;
- size_t copy_size = size;
+ haddr_t read_size; /* Size to read into copy buffer */
+ size_t copy_size = size; /* Size remaining to read when using copy buffer */
+ size_t copy_offset; /* Offset into copy buffer of the requested data */
FUNC_ENTER_NOAPI(H5FD_direct_read, FAIL)
@@ -974,19 +984,24 @@ H5FD_direct_read(H5FD_t *_file, H5FD_mem_t UNUSED type, hid_t UNUSED dxpl_id, ha
buf = (char*)buf + nbytes;
}
} else {
+ /* Calculate where we will begin copying from the copy buffer */
+ copy_offset = (size_t)(addr % _fbsize);
+
/* allocate memory needed for the Direct IO option up to the maximal
* copy buffer size. Make a bigger buffer for aligned I/O if size is
* smaller than maximal copy buffer. */
- if(size < _cbsize)
- alloc_size = ((size / _fbsize) * _fbsize) + _fbsize;
- else
+ alloc_size = ((copy_offset + size - 1) / _fbsize + 1) * _fbsize;
+ if(alloc_size > _cbsize)
alloc_size = _cbsize;
+ HDassert(!(alloc_size % _fbsize));
if (HDposix_memalign(&copy_buf, _boundary, alloc_size) != 0)
HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "HDposix_memalign failed")
- /* look for the aligned position for reading the data */
- if(file_seek(file->fd, (file_offset_t)(copy_addr - copy_addr % _fbsize), SEEK_SET) < 0)
- HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position")
+ /* look for the aligned position for reading the data */
+ HDassert(!(((addr / _fbsize) * _fbsize) % _fbsize));
+ if(file_seek(file->fd, (file_offset_t)((addr / _fbsize) * _fbsize),
+ SEEK_SET) < 0)
+ HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position")
/*
* Read the aligned data in file into aligned buffer first, then copy the data
@@ -994,7 +1009,6 @@ H5FD_direct_read(H5FD_t *_file, H5FD_mem_t UNUSED type, hid_t UNUSED dxpl_id, ha
* size, do the reading by segment (the outer while loop). If not, do one step
* reading.
*/
- p3 = buf;
do {
/* Read the aligned data in file first. Not able to handle interrupted
* system calls and partial results like sec2 driver does because the
@@ -1002,41 +1016,48 @@ H5FD_direct_read(H5FD_t *_file, H5FD_mem_t UNUSED type, hid_t UNUSED dxpl_id, ha
* file is smaller than ALLOC_SIZE. */
HDmemset(copy_buf, 0, alloc_size);
+ /* Calculate how much data we have to read in this iteration
+ * (including unused parts of blocks) */
+ if((copy_size + copy_offset) < alloc_size)
+ read_size = ((copy_size + copy_offset - 1) / _fbsize + 1)
+ * _fbsize;
+ else
+ read_size = alloc_size;
+
+ HDassert(!(read_size % _fbsize));
do {
- nbytes = HDread(file->fd, copy_buf, alloc_size);
+ nbytes = HDread(file->fd, copy_buf, read_size);
} while(-1==nbytes && EINTR==errno);
if (-1==nbytes) /* error */
HSYS_GOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file read failed")
- /* look for the right position and copy the data to the original buffer.
- * Consider all possible situations here: file address is not aligned on
- * file block size; the end of data address is not aligned; the end of data
- * address is aligned; data size is smaller or bigger than maximal copy size.*/
- p2 = (unsigned char*)copy_buf + (size_t)(copy_addr % _fbsize);
- if(size < _cbsize)
- HDmemcpy(p3, p2, size);
- else if(size >= _cbsize && copy_size <= (alloc_size-(size_t)(copy_addr%_fbsize)))
- HDmemcpy(p3, p2, copy_size);
- else if(size >= _cbsize && copy_size > (alloc_size-(size_t)(copy_addr%_fbsize))) {
- HDmemcpy(p3, p2, (alloc_size - (size_t)(copy_addr % _fbsize)));
- p3 = (unsigned char*)p3 + (alloc_size - (size_t)(copy_addr % _fbsize));
- }
-
- /* update the size and address of data being read. */
- if(copy_size > (alloc_size - (size_t)(copy_addr % _fbsize)))
- copy_size -= (alloc_size - (size_t)(copy_addr % _fbsize));
- else
- copy_size = 0;
- copy_addr += (alloc_size - (size_t)(copy_addr % _fbsize));
+ /* Copy the needed data from the copy buffer to the output
+ * buffer, and update copy_size. If the copy buffer does not
+ * contain the rest of the data, just copy what's in the copy
+ * buffer and also update read_addr and copy_offset to read the
+ * next section of data. */
+ p2 = (unsigned char*)copy_buf + copy_offset;
+ if((copy_size + copy_offset) <= alloc_size) {
+ HDmemcpy(buf, p2, copy_size);
+ buf = (unsigned char *)buf + copy_size;
+ copy_size = 0;
+ } /* end if */
+ else {
+ HDmemcpy(buf, p2, alloc_size - copy_offset);
+ buf = (unsigned char*)buf + alloc_size - copy_offset;
+ copy_size -= alloc_size - copy_offset;
+ copy_offset = 0;
+ } /* end else */
} while (copy_size > 0);
- /*Final step: update address and buffer*/
- addr += (haddr_t)size;
- buf = (unsigned char*)buf + size;
+ /*Final step: update address*/
+ addr = (haddr_t)(((addr + size - 1) / _fbsize + 1) * _fbsize);
- if(copy_buf)
- HDfree(copy_buf);
+ if(copy_buf) {
+ HDfree(copy_buf);
+ copy_buf = NULL;
+ } /* end if */
}
/* Update current position */
@@ -1045,6 +1066,9 @@ H5FD_direct_read(H5FD_t *_file, H5FD_mem_t UNUSED type, hid_t UNUSED dxpl_id, ha
done:
if(ret_value<0) {
+ if(copy_buf)
+ HDfree(copy_buf);
+
/* Reset last file I/O information */
file->pos = HADDR_UNDEF;
file->op = OP_UNKNOWN;
@@ -1081,13 +1105,16 @@ H5FD_direct_write(H5FD_t *_file, H5FD_mem_t UNUSED type, hid_t UNUSED dxpl_id, h
hbool_t _must_align = TRUE;
herr_t ret_value=SUCCEED; /* Return value */
size_t alloc_size;
- void *copy_buf, *p1;
+ void *copy_buf = NULL, *p1;
const void *p3;
size_t _boundary;
size_t _fbsize;
size_t _cbsize;
- haddr_t copy_addr = addr;
- size_t copy_size = size;
+ haddr_t write_addr; /* Address to write copy buffer */
+ haddr_t write_size; /* Size to write from copy buffer */
+ haddr_t read_size; /* Size to read into copy buffer */
+ size_t copy_size = size; /* Size remaining to write when using copy buffer */
+ size_t copy_offset; /* Offset into copy buffer of the data to write */
FUNC_ENTER_NOAPI(H5FD_direct_write, FAIL)
@@ -1139,41 +1166,83 @@ H5FD_direct_write(H5FD_t *_file, H5FD_mem_t UNUSED type, hid_t UNUSED dxpl_id, h
buf = (const char*)buf + nbytes;
}
} else {
+ /* Calculate where we will begin reading from (on disk) and where we
+ * will begin copying from the copy buffer */
+ write_addr = (addr / _fbsize) * _fbsize;
+ copy_offset = (size_t)(addr % _fbsize);
+
/* allocate memory needed for the Direct IO option up to the maximal
* copy buffer size. Make a bigger buffer for aligned I/O if size is
* smaller than maximal copy buffer.
*/
- if(size < _cbsize)
- alloc_size = ((size / _fbsize) * _fbsize) + _fbsize;
- else
- alloc_size = _cbsize;
+ alloc_size = ((copy_offset + size - 1) / _fbsize + 1) * _fbsize;
+ if(alloc_size > _cbsize)
+ alloc_size = _cbsize;
+ HDassert(!(alloc_size % _fbsize));
if (HDposix_memalign(&copy_buf, _boundary, alloc_size) != 0)
HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "HDposix_memalign failed")
- /* look for the right position for reading the data */
- if(file_seek(file->fd, (file_offset_t)(copy_addr - copy_addr % _fbsize), SEEK_SET) < 0)
- HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position")
+ /* look for the right position for reading or writing the data */
+ if(file_seek(file->fd, (file_offset_t)write_addr, SEEK_SET) < 0)
+ HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position")
p3 = buf;
do {
+ /* Calculate how much data we have to write in this iteration
+ * (including unused parts of blocks) */
+ if((copy_size + copy_offset) < alloc_size)
+ write_size = ((copy_size + copy_offset - 1) / _fbsize + 1)
+ * _fbsize;
+ else
+ write_size = alloc_size;
+
/*
* Read the aligned data first if the aligned region doesn't fall
* entirely in the range to be writen. Not able to handle interrupted
* system calls and partial results like sec2 driver does because the
* data may no longer be aligned. It's expecially true when the data in
- * file is smaller than ALLOC_SIZE.
+ * file is smaller than ALLOC_SIZE. Only read the entire section if
+ * both ends are misaligned, otherwise only read the block on the
+ * misaligned end.
*/
- HDmemset(copy_buf, 0, alloc_size);
-
- if(copy_addr <= addr || (copy_addr + alloc_size) >= (addr + size)) {
- do {
- nbytes = read(file->fd, copy_buf, alloc_size);
- } while (-1==nbytes && EINTR==errno);
-
- if (-1==nbytes) /* error */
- HSYS_GOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file read failed")
- }
+ HDmemset(copy_buf, 0, _fbsize);
+
+ if(copy_offset > 0) {
+ if((write_addr + write_size) > (addr + size)) {
+ HDassert((write_addr + write_size) - (addr + size) < _fbsize);
+ read_size = write_size;
+ p1 = copy_buf;
+ } /* end if */
+ else {
+ read_size = _fbsize;
+ p1 = copy_buf;
+ } /* end else */
+ } /* end if */
+ else if((write_addr + write_size) > (addr + size)) {
+ HDassert((write_addr + write_size) - (addr + size) < _fbsize);
+ read_size = _fbsize;
+ p1 = (unsigned char *)copy_buf + write_size - _fbsize;
+
+ /* Seek to the last block, for reading */
+ HDassert(!((write_addr + write_size - _fbsize) % _fbsize));
+ if(file_seek(file->fd,
+ (file_offset_t)(write_addr + write_size - _fbsize),
+ SEEK_SET) < 0)
+ HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position")
+ } /* end if */
+ else
+ p1 = NULL;
+
+ if(p1) {
+ HDassert(!(read_size % _fbsize));
+ do {
+ nbytes = read(file->fd, p1, read_size);
+ } while (-1==nbytes && EINTR==errno);
+
+ if (-1==nbytes) /* error */
+ HSYS_GOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file read failed")
+ } /* end if */
/* look for the right position and append or copy the data to be written to
* the aligned buffer.
@@ -1181,46 +1250,47 @@ H5FD_direct_write(H5FD_t *_file, H5FD_mem_t UNUSED type, hid_t UNUSED dxpl_id, h
* file block size; the end of data address is not aligned; the end of data
* address is aligned; data size is smaller or bigger than maximal copy size.
*/
- p1 = (unsigned char*)copy_buf + (size_t)(copy_addr % _fbsize);
- if(size < _cbsize)
- HDmemcpy(p1, p3, size);
- else if(size >= _cbsize && copy_size <= (alloc_size-(size_t)(copy_addr%_fbsize))) {
- HDmemcpy(p1, p3, copy_size);
- }else if(size >= _cbsize && copy_size > (alloc_size-(size_t)(copy_addr%_fbsize))) {
- HDmemcpy(p1, p3, (alloc_size - (size_t)(copy_addr % _fbsize)));
- p3 = (const unsigned char *)p3 + (alloc_size - (size_t)(copy_addr % _fbsize));
- }
+ p1 = (unsigned char *)copy_buf + copy_offset;
+ if((copy_size + copy_offset) <= alloc_size) {
+ HDmemcpy(p1, p3, copy_size);
+ copy_size = 0;
+ } /* end if */
+ else {
+ HDmemcpy(p1, p3, alloc_size - copy_offset);
+ p3 = (const unsigned char *)p3 + (alloc_size - copy_offset);
+ copy_size -= alloc_size - copy_offset;
+ copy_offset = 0;
+ } /* end else */
/*look for the aligned position for writing the data*/
- if(file_seek(file->fd, (file_offset_t)(copy_addr - copy_addr % _fbsize), SEEK_SET) < 0)
+ HDassert(!(write_addr % _fbsize));
+ if(file_seek(file->fd, (file_offset_t)write_addr, SEEK_SET) < 0)
HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position")
/*
* Write the data. It doesn't truncate the extra data introduced by
* alignment because that step is done in H5FD_direct_flush.
*/
+ HDassert(!(write_size % _fbsize));
do {
- nbytes = HDwrite(file->fd, copy_buf, alloc_size);
+ nbytes = HDwrite(file->fd, copy_buf, write_size);
} while (-1==nbytes && EINTR==errno);
if (-1==nbytes) /* error */
HSYS_GOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed")
- /* update the size and address of data being read. */
- if(copy_size > (alloc_size - (size_t)(copy_addr % _fbsize)))
- copy_size -= (alloc_size - (size_t)(copy_addr % _fbsize));
- else
- copy_size = 0;
-
- copy_addr += (alloc_size - (size_t)(copy_addr % _fbsize));
+ /* update the write address */
+ write_addr += write_size;
} while (copy_size > 0);
/*Update the address and size*/
- addr += (haddr_t)size;
+ addr = write_addr;
buf = (const char*)buf + size;
- if(copy_buf)
+ if(copy_buf) {
HDfree(copy_buf);
+ copy_buf = NULL;
+ } /* end if */
}
/* Update current position and eof */
@@ -1231,6 +1301,9 @@ H5FD_direct_write(H5FD_t *_file, H5FD_mem_t UNUSED type, hid_t UNUSED dxpl_id, h
done:
if(ret_value<0) {
+ if(copy_buf)
+ HDfree(copy_buf);
+
/* Reset last file I/O information */
file->pos = HADDR_UNDEF;
file->op = OP_UNKNOWN;