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:
Axel Dörfler
2006-05-22 16:36:20 +00:00
parent c003d47a54
commit 517dfdf48b
+32 -15
View File
@@ -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;