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:
parent
6e442c70cb
commit
c1316c8dd3
@ -81,6 +81,7 @@ using std::nothrow;
|
||||
// maximum number of iovecs per request
|
||||
#define MAX_IO_VECS 64 // 256 kB
|
||||
#define MAX_FILE_IO_VECS 32
|
||||
#define MAX_TEMP_IO_VECS 8
|
||||
|
||||
#define CACHED_FILE_EXTENTS 2
|
||||
// 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 *
|
||||
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++) {
|
||||
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
|
||||
pages_io(file_cache_ref *ref, off_t offset, const iovec *vecs, size_t count,
|
||||
size_t *_numBytes, bool doWrite)
|
||||
{
|
||||
TRACE(("pages_io: ref = %p, offset = %Ld, size = %lu, %s\n", ref, offset,
|
||||
*_numBytes, doWrite ? "write" : "read"));
|
||||
TRACE(("pages_io: ref = %p, offset = %Ld, size = %lu, vecCount = %lu, %s\n", ref, offset,
|
||||
*_numBytes, count, doWrite ? "write" : "read"));
|
||||
|
||||
// translate the iovecs into direct device accesses
|
||||
file_io_vec fileVecs[MAX_FILE_IO_VECS];
|
||||
size_t fileVecCount = MAX_FILE_IO_VECS;
|
||||
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) {
|
||||
TRACE(("get_file_map(offset = %Ld, numBytes = %lu) failed\n", offset,
|
||||
numBytes));
|
||||
return status;
|
||||
}
|
||||
|
||||
// ToDo: handle array overflow gracefully!
|
||||
// TODO: handle array overflow gracefully!
|
||||
|
||||
#ifdef TRACE_FILE_CACHE
|
||||
dprintf("got %lu file vecs for %Ld:%lu:\n", fileVecCount, offset, numBytes);
|
||||
for (size_t i = 0; i < fileVecCount; i++)
|
||||
dprintf("[%lu] offset = %Ld, size = %Ld\n", i, fileVecs[i].offset, fileVecs[i].length);
|
||||
for (size_t i = 0; i < fileVecCount; i++) {
|
||||
dprintf(" [%lu] offset = %Ld, size = %Ld\n",
|
||||
i, fileVecs[i].offset, fileVecs[i].length);
|
||||
}
|
||||
#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));
|
||||
TRACE(("pages_io: access outside of vnode %p at offset %Ld\n",
|
||||
ref->vnode, offset));
|
||||
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)
|
||||
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:
|
||||
// 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)
|
||||
if (size > fileVecs[0].length) {
|
||||
//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;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
fileVecIndex = 1;
|
||||
} else {
|
||||
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
|
||||
uint32 i = 0;
|
||||
for (; i < count; i++) {
|
||||
if (size <= vecs[i].iov_len)
|
||||
if (size < vecs[i].iov_len)
|
||||
break;
|
||||
|
||||
size -= vecs[i].iov_len;
|
||||
}
|
||||
|
||||
size_t vecOffset = size;
|
||||
size_t bytesLeft = numBytes - size;
|
||||
|
||||
for (; fileVecIndex < fileVecCount; fileVecIndex++) {
|
||||
file_io_vec &fileVec = fileVecs[fileVecIndex];
|
||||
iovec tempVecs[8];
|
||||
uint32 tempCount = 1;
|
||||
off_t fileOffset = fileVec.offset;
|
||||
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);
|
||||
tempVecs[0].iov_len = size;
|
||||
TRACE(("FILE VEC [%lu] length %Ld\n", fileVecIndex, fileLeft));
|
||||
|
||||
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)
|
||||
vecOffset += size;
|
||||
else
|
||||
vecOffset = 0;
|
||||
// size tracks how much of what is left of the current fileVec
|
||||
// (fileLeft) has been assigned to tempVecs
|
||||
size = 0;
|
||||
|
||||
while (size < fileVec.length && ++i < count) {
|
||||
tempVecs[tempCount].iov_base = vecs[i].iov_base;
|
||||
tempCount++;
|
||||
// assign what is left of the current fileVec to the tempVecs
|
||||
while (size < fileLeft && i < count
|
||||
&& 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?
|
||||
if (vecs[i].iov_len + size > fileVec.length) {
|
||||
size += tempVecs[tempCount].iov_len = vecOffset = fileVec.length - size;
|
||||
break;
|
||||
// bytes left of the current iovec
|
||||
size_t vecLeft = vecs[i].iov_len - vecOffset;
|
||||
if (vecLeft == 0) {
|
||||
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;
|
||||
if (doWrite) {
|
||||
status = vfs_write_pages(ref->deviceFD, fileVec.offset, tempVecs,
|
||||
tempCount, &bytes, false);
|
||||
} else {
|
||||
status = vfs_read_pages(ref->deviceFD, fileVec.offset, tempVecs,
|
||||
tempCount, &bytes, false);
|
||||
}
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
totalSize += bytes;
|
||||
bytesLeft -= size;
|
||||
fileOffset += size;
|
||||
fileLeft -= size;
|
||||
//dprintf("-> file left = %Lu\n", fileLeft);
|
||||
|
||||
totalSize += size;
|
||||
|
||||
if (size != bytes) {
|
||||
// there are no more bytes, let's bail out
|
||||
*_numBytes = totalSize;
|
||||
return B_OK;
|
||||
if (size != bytes || i >= count) {
|
||||
// there are no more bytes or iovecs, let's bail out
|
||||
*_numBytes = totalSize;
|
||||
return B_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*_numBytes = totalSize;
|
||||
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
|
||||
* sure that it matches that criterion.
|
||||
*/
|
||||
|
||||
/*!
|
||||
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
|
||||
sure that it matches that criterion.
|
||||
*/
|
||||
static inline status_t
|
||||
read_chunk_into_cache(file_cache_ref *ref, off_t offset, size_t size,
|
||||
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
|
||||
* read in are also copied to the provided \a buffer.
|
||||
* This function always allocates all pages; it is the responsibility of the
|
||||
* calling function to only ask for yet uncached ranges.
|
||||
* The cache_ref lock must be hold when calling this function.
|
||||
*/
|
||||
|
||||
/*!
|
||||
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
|
||||
read in are also copied to the provided \a buffer.
|
||||
This function always allocates all pages; it is the responsibility of the
|
||||
calling function to only ask for yet uncached ranges.
|
||||
The cache_ref lock must be hold when calling this function.
|
||||
*/
|
||||
static status_t
|
||||
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 -
|
||||
// public FS API
|
||||
// #pragma mark - public FS API
|
||||
|
||||
|
||||
void *
|
||||
|
Loading…
Reference in New Issue
Block a user