From 55ddbd7bca54878d861861e82c0c5a0d196c1b85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Fri, 14 Nov 2008 12:06:44 +0000 Subject: [PATCH] * 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 --- .../file_systems/ext2/kernel_interface.cpp | 10 +++- src/system/kernel/cache/file_map.cpp | 26 +++++----- src/system/kernel/fs/vfs.cpp | 48 +++++++++++++++++-- 3 files changed, 67 insertions(+), 17 deletions(-) diff --git a/src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp b/src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp index 4568ad8021..5804d1f9ab 100644 --- a/src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp @@ -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++; } diff --git a/src/system/kernel/cache/file_map.cpp b/src/system/kernel/cache/file_map.cpp index fc39fe0772..a1dda507ba 100644 --- a/src/system/kernel/cache/file_map.cpp +++ b/src/system/kernel/cache/file_map.cpp @@ -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) diff --git a/src/system/kernel/fs/vfs.cpp b/src/system/kernel/fs/vfs.cpp index 67216b7859..63061d4e79 100644 --- a/src/system/kernel/fs/vfs.cpp +++ b/src/system/kernel/fs/vfs.cpp @@ -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);