The cache did not correctly retrieve the file map when the file was fragmented
into more than MAX_FILE_IO_VECS pieces. This could have very weird consequences like overwriting data outside the file (but on that same partition only). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17536 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
+32
-15
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2004-2005, Axel Dörfler, [email protected]. All rights reserved.
|
* Copyright 2004-2006, Axel Dörfler, [email protected]. All rights reserved.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ struct file_map {
|
|||||||
|
|
||||||
file_extent *operator[](uint32 index);
|
file_extent *operator[](uint32 index);
|
||||||
file_extent *ExtentAt(uint32 index);
|
file_extent *ExtentAt(uint32 index);
|
||||||
status_t Add(file_io_vec *vecs, size_t vecCount);
|
status_t Add(file_io_vec *vecs, size_t vecCount, off_t &lastOffset);
|
||||||
void Free();
|
void Free();
|
||||||
|
|
||||||
union {
|
union {
|
||||||
@@ -104,20 +104,18 @@ file_map::ExtentAt(uint32 index)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
file_map::Add(file_io_vec *vecs, size_t vecCount)
|
file_map::Add(file_io_vec *vecs, size_t vecCount, off_t &lastOffset)
|
||||||
{
|
{
|
||||||
off_t offset = 0;
|
TRACE(("file_map::Add(vecCount = %ld)\n", vecCount));
|
||||||
|
|
||||||
#if 0
|
off_t offset = 0;
|
||||||
for (uint32 i = 0; i < vecCount; i++) {
|
|
||||||
dprintf("[%ld] vecs offset %Ld, length %Ld\n",
|
|
||||||
i, vecs[i].offset, vecs[i].length);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (vecCount <= CACHED_FILE_EXTENTS && count == 0) {
|
if (vecCount <= CACHED_FILE_EXTENTS && count == 0) {
|
||||||
// just use the reserved area in the file_cache_ref structure
|
// just use the reserved area in the file_cache_ref structure
|
||||||
} else {
|
} else {
|
||||||
|
// TODO: once we can invalidate only parts of the file map,
|
||||||
|
// we might need to copy the previously cached file extends
|
||||||
|
// from the direct range
|
||||||
file_extent *newMap = (file_extent *)realloc(array,
|
file_extent *newMap = (file_extent *)realloc(array,
|
||||||
(count + vecCount) * sizeof(file_extent));
|
(count + vecCount) * sizeof(file_extent));
|
||||||
if (newMap == NULL)
|
if (newMap == NULL)
|
||||||
@@ -131,10 +129,11 @@ for (uint32 i = 0; i < vecCount; i++) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32 start = count;
|
||||||
count += vecCount;
|
count += vecCount;
|
||||||
|
|
||||||
for (uint32 i = 0; i < vecCount; i++) {
|
for (uint32 i = 0; i < vecCount; i++) {
|
||||||
file_extent *extent = ExtentAt(i);
|
file_extent *extent = ExtentAt(start + i);
|
||||||
|
|
||||||
extent->offset = offset;
|
extent->offset = offset;
|
||||||
extent->disk = vecs[i];
|
extent->disk = vecs[i];
|
||||||
@@ -142,6 +141,15 @@ for (uint32 i = 0; i < vecCount; i++) {
|
|||||||
offset += extent->disk.length;
|
offset += extent->disk.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef TRACE_FILE_CACHE
|
||||||
|
for (uint32 i = 0; i < count; i++) {
|
||||||
|
file_extent *extent = ExtentAt(i);
|
||||||
|
dprintf("[%ld] extend offset %Ld, disk offset %Ld, length %Ld\n",
|
||||||
|
i, extent->offset, extent->disk.offset, extent->disk.length);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
lastOffset = offset;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,15 +232,17 @@ get_file_map(file_cache_ref *ref, off_t offset, size_t size,
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = ref->map.Add(vecs, vecCount);
|
status_t addStatus = ref->map.Add(vecs, vecCount, mapOffset);
|
||||||
//dprintf("map.Add() status %s\n", strerror(status));
|
if (addStatus != B_OK) {
|
||||||
|
// only clobber the status in case of failure
|
||||||
|
status = addStatus;
|
||||||
|
}
|
||||||
|
|
||||||
if (status != B_BUFFER_OVERFLOW)
|
if (status != B_BUFFER_OVERFLOW)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// when we are here, the map has been stored in the array, and
|
// when we are here, the map has been stored in the array, and
|
||||||
// the array size was still too small to cover the whole file
|
// the array size was still too small to cover the whole file
|
||||||
file_io_vec *last = &vecs[vecCount - 1];
|
|
||||||
mapOffset += last->length;
|
|
||||||
vecCount = maxVecs;
|
vecCount = maxVecs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -320,6 +330,13 @@ pages_io(file_cache_ref *ref, off_t offset, const iovec *vecs, size_t count,
|
|||||||
dprintf("[%lu] offset = %Ld, size = %Ld\n", i, fileVecs[i].offset, fileVecs[i].length);
|
dprintf("[%lu] offset = %Ld, size = %Ld\n", i, fileVecs[i].offset, fileVecs[i].length);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (fileVecCount == 0) {
|
||||||
|
// There are no file vecs at this offset, so we're obviously trying
|
||||||
|
// to access the file outside of its bounds
|
||||||
|
TRACE(("pages_io: access outside of vnode %p at offset %Ld\n", ref->vnode, offset));
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
uint32 fileVecIndex;
|
uint32 fileVecIndex;
|
||||||
size_t size;
|
size_t size;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user