Synchronized with recent kernel file cache changes up to r20483.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20486 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2007-03-31 23:52:05 +00:00
parent 6e442c70cb
commit c1316c8dd3
@@ -81,6 +81,7 @@ using std::nothrow;
// maximum number of iovecs per request // maximum number of iovecs per request
#define MAX_IO_VECS 64 // 256 kB #define MAX_IO_VECS 64 // 256 kB
#define MAX_FILE_IO_VECS 32 #define MAX_FILE_IO_VECS 32
#define MAX_TEMP_IO_VECS 8
#define CACHED_FILE_EXTENTS 2 #define CACHED_FILE_EXTENTS 2
// must be smaller than MAX_FILE_IO_VECS // must be smaller than MAX_FILE_IO_VECS
@@ -1058,7 +1059,7 @@ add_to_iovec(iovec *vecs, int32 &index, int32 max, addr_t address, size_t size)
static file_extent * static file_extent *
find_file_extent(file_cache_ref *ref, off_t offset, uint32 *_index) find_file_extent(file_cache_ref *ref, off_t offset, uint32 *_index)
{ {
// ToDo: do binary search // TODO: do binary search
for (uint32 index = 0; index < ref->map.count; index++) { for (uint32 index = 0; index < ref->map.count; index++) {
file_extent *extent = ref->map[index]; file_extent *extent = ref->map[index];
@@ -1171,37 +1172,45 @@ get_file_map(file_cache_ref *ref, off_t offset, size_t size,
} }
/*!
Does the dirty work of translating the request into actual disk offsets
and reads to or writes from the supplied iovecs as specified by \a doWrite.
*/
static status_t static status_t
pages_io(file_cache_ref *ref, off_t offset, const iovec *vecs, size_t count, pages_io(file_cache_ref *ref, off_t offset, const iovec *vecs, size_t count,
size_t *_numBytes, bool doWrite) size_t *_numBytes, bool doWrite)
{ {
TRACE(("pages_io: ref = %p, offset = %Ld, size = %lu, %s\n", ref, offset, TRACE(("pages_io: ref = %p, offset = %Ld, size = %lu, vecCount = %lu, %s\n", ref, offset,
*_numBytes, doWrite ? "write" : "read")); *_numBytes, count, doWrite ? "write" : "read"));
// translate the iovecs into direct device accesses // translate the iovecs into direct device accesses
file_io_vec fileVecs[MAX_FILE_IO_VECS]; file_io_vec fileVecs[MAX_FILE_IO_VECS];
size_t fileVecCount = MAX_FILE_IO_VECS; size_t fileVecCount = MAX_FILE_IO_VECS;
size_t numBytes = *_numBytes; size_t numBytes = *_numBytes;
status_t status = get_file_map(ref, offset, numBytes, fileVecs, &fileVecCount); status_t status = get_file_map(ref, offset, numBytes, fileVecs,
&fileVecCount);
if (status < B_OK) { if (status < B_OK) {
TRACE(("get_file_map(offset = %Ld, numBytes = %lu) failed\n", offset, TRACE(("get_file_map(offset = %Ld, numBytes = %lu) failed\n", offset,
numBytes)); numBytes));
return status; return status;
} }
// ToDo: handle array overflow gracefully! // TODO: handle array overflow gracefully!
#ifdef TRACE_FILE_CACHE #ifdef TRACE_FILE_CACHE
dprintf("got %lu file vecs for %Ld:%lu:\n", fileVecCount, offset, numBytes); dprintf("got %lu file vecs for %Ld:%lu:\n", fileVecCount, offset, numBytes);
for (size_t i = 0; i < fileVecCount; i++) for (size_t i = 0; i < fileVecCount; i++) {
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) { if (fileVecCount == 0) {
// There are no file vecs at this offset, so we're obviously trying // There are no file vecs at this offset, so we're obviously trying
// to access the file outside of its bounds // to access the file outside of its bounds
TRACE(("pages_io: access outside of vnode %p at offset %Ld\n", ref->vnode, offset)); TRACE(("pages_io: access outside of vnode %p at offset %Ld\n",
ref->vnode, offset));
return B_BAD_VALUE; return B_BAD_VALUE;
} }
@@ -1221,9 +1230,10 @@ pages_io(file_cache_ref *ref, off_t offset, const iovec *vecs, size_t count,
if (status < B_OK) if (status < B_OK)
return status; return status;
// ToDo: this is a work-around for buggy device drivers! // TODO: this is a work-around for buggy device drivers!
// When our own drivers honour the length, we can: // When our own drivers honour the length, we can:
// a) also use this direct I/O for writes (otherwise, it would overwrite precious data) // a) also use this direct I/O for writes (otherwise, it would
// overwrite precious data)
// b) panic if the term below is true (at least for writes) // b) panic if the term below is true (at least for writes)
if (size > fileVecs[0].length) { if (size > fileVecs[0].length) {
//dprintf("warning: device driver %p doesn't respect total length in read_pages() call!\n", ref->device); //dprintf("warning: device driver %p doesn't respect total length in read_pages() call!\n", ref->device);
@@ -1241,7 +1251,7 @@ pages_io(file_cache_ref *ref, off_t offset, const iovec *vecs, size_t count,
*_numBytes = size; *_numBytes = size;
return B_OK; return B_OK;
} }
fileVecIndex = 1; fileVecIndex = 1;
} else { } else {
fileVecIndex = 0; fileVecIndex = 0;
@@ -1255,73 +1265,96 @@ pages_io(file_cache_ref *ref, off_t offset, const iovec *vecs, size_t count,
// first, find out where we have to continue in our iovecs // first, find out where we have to continue in our iovecs
uint32 i = 0; uint32 i = 0;
for (; i < count; i++) { for (; i < count; i++) {
if (size <= vecs[i].iov_len) if (size < vecs[i].iov_len)
break; break;
size -= vecs[i].iov_len; size -= vecs[i].iov_len;
} }
size_t vecOffset = size; size_t vecOffset = size;
size_t bytesLeft = numBytes - size;
for (; fileVecIndex < fileVecCount; fileVecIndex++) { for (; fileVecIndex < fileVecCount; fileVecIndex++) {
file_io_vec &fileVec = fileVecs[fileVecIndex]; file_io_vec &fileVec = fileVecs[fileVecIndex];
iovec tempVecs[8]; off_t fileOffset = fileVec.offset;
uint32 tempCount = 1; off_t fileLeft = fileVec.length;
tempVecs[0].iov_base = (void *)((addr_t)vecs[i].iov_base + vecOffset); fileLeft = min_c(fileVec.length, bytesLeft);
size = min_c(vecs[i].iov_len - vecOffset, fileVec.length); TRACE(("FILE VEC [%lu] length %Ld\n", fileVecIndex, fileLeft));
tempVecs[0].iov_len = size;
TRACE(("fill vec %ld, offset = %lu, size = %lu\n", i, vecOffset, size)); // process the complete fileVec
while (fileLeft > 0) {
iovec tempVecs[MAX_TEMP_IO_VECS];
uint32 tempCount = 0;
if (size >= fileVec.length) // size tracks how much of what is left of the current fileVec
vecOffset += size; // (fileLeft) has been assigned to tempVecs
else size = 0;
vecOffset = 0;
while (size < fileVec.length && ++i < count) { // assign what is left of the current fileVec to the tempVecs
tempVecs[tempCount].iov_base = vecs[i].iov_base; while (size < fileLeft && i < count
tempCount++; && tempCount < MAX_TEMP_IO_VECS) {
// try to satisfy one iovec per iteration (or as much as
// possible)
TRACE(("fill vec %ld, offset = %lu, size = %lu\n",
i, vecOffset, size));
// is this iovec larger than the file_io_vec? // bytes left of the current iovec
if (vecs[i].iov_len + size > fileVec.length) { size_t vecLeft = vecs[i].iov_len - vecOffset;
size += tempVecs[tempCount].iov_len = vecOffset = fileVec.length - size; if (vecLeft == 0) {
break; i++;
vecOffset = 0;
continue;
}
// actually available bytes
size_t tempVecSize = min_c(vecLeft, fileLeft - size);
tempVecs[tempCount].iov_base
= (void *)((addr_t)vecs[i].iov_base + vecOffset);
tempVecs[tempCount].iov_len = tempVecSize;
tempCount++;
size += tempVecSize;
vecOffset += tempVecSize;
} }
size += tempVecs[tempCount].iov_len = vecs[i].iov_len; size_t bytes = size;
} if (doWrite) {
status = vfs_write_pages(ref->deviceFD, fileOffset,
tempVecs, tempCount, &bytes, false);
} else {
status = vfs_read_pages(ref->deviceFD, fileOffset,
tempVecs, tempCount, &bytes, false);
}
if (status < B_OK)
return status;
size_t bytes = size; totalSize += bytes;
if (doWrite) { bytesLeft -= size;
status = vfs_write_pages(ref->deviceFD, fileVec.offset, tempVecs, fileOffset += size;
tempCount, &bytes, false); fileLeft -= size;
} else { //dprintf("-> file left = %Lu\n", fileLeft);
status = vfs_read_pages(ref->deviceFD, fileVec.offset, tempVecs,
tempCount, &bytes, false);
}
if (status < B_OK)
return status;
totalSize += size; if (size != bytes || i >= count) {
// there are no more bytes or iovecs, let's bail out
if (size != bytes) { *_numBytes = totalSize;
// there are no more bytes, let's bail out return B_OK;
*_numBytes = totalSize; }
return B_OK;
} }
} }
*_numBytes = totalSize;
return B_OK; return B_OK;
} }
/** This function is called by read_into_cache() (and from there only) - it /*!
* can only handle a certain amount of bytes, and read_into_cache() makes This function is called by read_into_cache() (and from there only) - it
* sure that it matches that criterion. can only handle a certain amount of bytes, and read_into_cache() makes
*/ sure that it matches that criterion.
*/
static inline status_t static inline status_t
read_chunk_into_cache(file_cache_ref *ref, off_t offset, size_t size, read_chunk_into_cache(file_cache_ref *ref, off_t offset, size_t size,
int32 pageOffset, addr_t buffer, size_t bufferSize) int32 pageOffset, addr_t buffer, size_t bufferSize)
@@ -1400,14 +1433,14 @@ read_chunk_into_cache(file_cache_ref *ref, off_t offset, size_t size,
} }
/** This function reads \a size bytes directly from the file into the cache. /*!
* If \a bufferSize does not equal zero, \a bufferSize bytes from the data This function reads \a size bytes directly from the file into the cache.
* read in are also copied to the provided \a buffer. If \a bufferSize does not equal zero, \a bufferSize bytes from the data
* This function always allocates all pages; it is the responsibility of the read in are also copied to the provided \a buffer.
* calling function to only ask for yet uncached ranges. This function always allocates all pages; it is the responsibility of the
* The cache_ref lock must be hold when calling this function. calling function to only ask for yet uncached ranges.
*/ The cache_ref lock must be hold when calling this function.
*/
static status_t static status_t
read_into_cache(file_cache_ref *ref, off_t offset, size_t size, addr_t buffer, size_t bufferSize) read_into_cache(file_cache_ref *ref, off_t offset, size_t size, addr_t buffer, size_t bufferSize)
{ {
@@ -1750,8 +1783,7 @@ cache_io(void *_cacheRef, off_t offset, addr_t buffer, size_t *_size, bool doWri
} }
// #pragma mark - // #pragma mark - public FS API
// public FS API
void * void *