* 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:
parent
167f43a24c
commit
55ddbd7bca
@ -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++;
|
||||
}
|
||||
|
26
src/system/kernel/cache/file_map.cpp
vendored
26
src/system/kernel/cache/file_map.cpp
vendored
@ -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)
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user