* When a file system reports -1 offsets in its fs_get_file_map() function, this

will now accepted and regarded as sparse file data. FileMap::_Add() also
  correctly joins multiple vecs with that offset together, FileMap::Translate()
  will always report offset -1 even for offsets into that extent.
* read_file_io_vec_pages() (or rather, its backend common_file_io_vec_pages())
  now supports sparse files, and will just clear the memory it should read from
  offset -1 instead of passing a request to the vnode.
* ext2 now correctly reports sparse files. This should close bug #2889, as well
  as #975.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@28648 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2008-11-14 12:06:44 +00:00
parent 167f43a24c
commit 55ddbd7bca
3 changed files with 67 additions and 17 deletions

View File

@ -258,7 +258,8 @@ ext2_get_file_map(fs_volume* _volume, fs_vnode* _node, off_t offset,
off_t blockOffset = (off_t)block << volume->BlockShift();
uint32 blockLength = volume->BlockSize();
if (index > 0 && vecs[index - 1].offset == blockOffset - blockLength) {
if (index > 0 && (vecs[index - 1].offset == blockOffset - blockLength
|| (vecs[index - 1].offset == -1 && block == 0))) {
vecs[index - 1].length += blockLength;
} else {
if (index >= max) {
@ -267,7 +268,12 @@ ext2_get_file_map(fs_volume* _volume, fs_vnode* _node, off_t offset,
return B_BUFFER_OVERFLOW;
}
vecs[index].offset = blockOffset;
// 'block' is 0 for sparse blocks
if (block != 0)
vecs[index].offset = blockOffset;
else
vecs[index].offset = -1;
vecs[index].length = blockLength;
index++;
}

View File

@ -26,9 +26,9 @@
//#define TRACE_FILE_MAP
#ifdef TRACE_FILE_MAP
# define TRACE(x) dprintf x
# define TRACE(x...) dprintf_no_syslog(x)
#else
# define TRACE(x) ;
# define TRACE(x...) ;
#endif
// TODO: use a sparse array - eventually, the unused BlockMap would be something
@ -223,7 +223,7 @@ FileMap::_MakeSpace(size_t count)
status_t
FileMap::_Add(file_io_vec* vecs, size_t vecCount, off_t& lastOffset)
{
TRACE(("FileMap@%p::Add(vecCount = %ld)\n", this, vecCount));
TRACE("FileMap@%p::Add(vecCount = %ld)\n", this, vecCount);
uint32 start = fCount;
off_t offset = 0;
@ -241,7 +241,8 @@ FileMap::_Add(file_io_vec* vecs, size_t vecCount, off_t& lastOffset)
for (uint32 i = 0; i < vecCount; i++) {
if (lastExtent != NULL) {
if (lastExtent->disk.offset + lastExtent->disk.length
== vecs[i].offset) {
== vecs[i].offset
|| lastExtent->disk.offset == -1 && vecs[i].offset == -1) {
lastExtent->disk.length += vecs[i].length;
offset += vecs[i].length;
start--;
@ -261,7 +262,7 @@ FileMap::_Add(file_io_vec* vecs, size_t vecCount, off_t& lastOffset)
#ifdef TRACE_FILE_MAP
for (uint32 i = 0; i < fCount; i++) {
file_extent* extent = ExtentAt(i);
dprintf("[%ld] extent offset %Ld, disk offset %Ld, length %Ld\n",
TRACE("[%ld] extent offset %Ld, disk offset %Ld, length %Ld\n",
i, extent->offset, extent->disk.offset, extent->disk.length);
}
#endif
@ -420,7 +421,10 @@ FileMap::Translate(off_t offset, size_t size, file_io_vec* vecs, size_t* _count,
file_extent* fileExtent = _FindExtent(offset, &index);
offset -= fileExtent->offset;
vecs[0].offset = fileExtent->disk.offset + offset;
if (fileExtent->disk.offset != -1)
vecs[0].offset = fileExtent->disk.offset + offset;
else
vecs[0].offset = -1;
vecs[0].length = fileExtent->disk.length - offset;
if (vecs[0].length >= size) {
@ -575,8 +579,8 @@ file_map_init(void)
extern "C" void*
file_map_create(dev_t mountID, ino_t vnodeID, off_t size)
{
TRACE(("file_map_create(mountID = %ld, vnodeID = %Ld, size = %Ld)\n",
mountID, vnodeID, size));
TRACE("file_map_create(mountID = %ld, vnodeID = %Ld, size = %Ld)\n",
mountID, vnodeID, size);
// Get the vnode for the object
// (note, this does not grab a reference to the node)
@ -595,7 +599,7 @@ file_map_delete(void* _map)
if (map == NULL)
return;
TRACE(("file_map_delete(map = %p)\n", map));
TRACE("file_map_delete(map = %p)\n", map);
delete map;
}
@ -637,8 +641,8 @@ extern "C" status_t
file_map_translate(void* _map, off_t offset, size_t size, file_io_vec* vecs,
size_t* _count, size_t align)
{
TRACE(("file_map_translate(map %p, offset %Ld, size %ld)\n",
_map, offset, size));
TRACE("file_map_translate(map %p, offset %Ld, size %ld)\n",
_map, offset, size);
FileMap* map = (FileMap*)_map;
if (map == NULL)

View File

@ -3266,6 +3266,31 @@ dump_vnode_usage(int argc, char **argv)
#endif // ADD_DEBUGGER_COMMANDS
//! Clears an iovec array of physical pages.
static status_t
zero_pages(const iovec* vecs, size_t vecCount, size_t* _bytes)
{
size_t bytes = *_bytes;
size_t index = 0;
while (bytes > 0) {
size_t length = min_c(vecs[index].iov_len, bytes);
status_t status = vm_memset_physical((addr_t)vecs[index].iov_base, 0,
length);
if (status != B_OK) {
*_bytes = bytes;
return status;
}
bytes -= length;
}
*_bytes = bytes;
return B_OK;
}
/*! Does the dirty work of combining the file_io_vecs with the iovecs
and calls the file system hooks to read/write the request to disk.
*/
@ -3296,8 +3321,13 @@ common_file_io_vec_pages(struct vnode *vnode, void *cookie,
if (size > numBytes)
size = numBytes;
status = FS_CALL(vnode, read_pages, cookie, fileVecs[0].offset,
&vecs[vecIndex], vecCount - vecIndex, &size);
if (fileVecs[0].offset >= 0) {
status = FS_CALL(vnode, read_pages, cookie, fileVecs[0].offset,
&vecs[vecIndex], vecCount - vecIndex, &size);
} else {
// sparse read
status = zero_pages(&vecs[vecIndex], vecCount - vecIndex, &size);
}
if (status < B_OK)
return status;
@ -3390,7 +3420,16 @@ common_file_io_vec_pages(struct vnode *vnode, void *cookie,
}
size_t bytes = size;
if (doWrite) {
if (fileOffset == -1) {
if (doWrite) {
panic("sparse write attempt: vnode %p", vnode);
status = B_IO_ERROR;
} else {
// sparse read
status = zero_pages(tempVecs, tempCount, &bytes);
}
} else if (doWrite) {
status = FS_CALL(vnode, write_pages, cookie, fileOffset,
tempVecs, tempCount, &bytes);
} else {
@ -3402,7 +3441,8 @@ common_file_io_vec_pages(struct vnode *vnode, void *cookie,
totalSize += bytes;
bytesLeft -= size;
fileOffset += size;
if (fileOffset >= 0)
fileOffset += size;
fileLeft -= size;
//dprintf("-> file left = %Lu\n", fileLeft);