hrev46358 adds 9 changesets to branch 'master' old head: 81fd469dcfaa0fd2b07b985d261cadc6aea9ff58 new head: 26aef3ac62e67e29e7895213ef7c5253798564f4 overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=26aef3a+%5E81fd469 ---------------------------------------------------------------------------- e5f6591: VM: vm_memset_physical(): Correct length parameter type 07f6506: VFS: Fix broken zero_pages() Besides that it failed to actually iterate through the vectors, it shouldn't try to clear physical memory in the first place. The iovecs refer to virtual address ranges. Rename it to zero_iovecs() to avoid confusion. 426fe7d: IORequest::_CopyData(): Small optimization If we're running in the context of the user team the I/O buffer belongs to, we can use _CopySimple() as well. c63b3de: IORequest: Add ClearData() 9f7e78e: IORequest::Init(): Assert offset >= 0 Just to make sure we catch sparse file vectors that shouldn't be passed here. 24d0e21: do_iterative_fd_io_iterate(): Support sparse files * Check whether the vectors we get are sparse file vectors and satisfy them immediately instead of creating a subrequest. Untested, since the API isn't used by ext2 as it should be. * Add error == B_OK to the condition of the outer loop. fd91d2c: ext2: ExtentStream::FindBlock(): Restructure/fix * The binary search was somewhat broken. * Restructure a bit so that only the binary/linear search itself is handled separately. The handling afterwards is common again. * Fix sparse block handling: - There can be sparse blocks before the first extend. - Set the return parameter _count in this case as well. - Set the return parameter block to 0 instead of 0xffffffff. That's what ext2_get_file_map() expects. Fixes an infinite loop in ext2_get_file_map() when sparse blocks are involved, due to previously returning a wrong block and a 0 count. Ticket #9274 may be related. 05826ec: ext2_get_file_map(): Fix broken termination condition 26aef3a: ext2: Fix enabling/disabling the file cache * Inode: - Rename {Enable,Disable}FileCache() to {Create,Delete}FileCache() and IsFileCacheDisabled() to HasFileCache(), since that is what they actually do. DeleteFileCache() now also sets the attributes to NULL, which makes fCached superfluous. - Introduce {Enable,Disable}FileCache(), which actually enable/disable the file cache. Use those methods for handling O_NOCACHE. * ext2_free_cookie(): Reenable the file cache in case of O_NOCACHE. Fixes crash when O_NOCACHE was used, since the file cache was deleted without clearing the attribute and Inode::ReadAt() would use the deleted object afterward. [ Ingo Weinhold <ingo_weinhold@xxxxxx> ] ---------------------------------------------------------------------------- 11 files changed, 299 insertions(+), 132 deletions(-) headers/private/kernel/vm/vm.h | 2 +- .../kernel/file_systems/ext2/ExtentStream.cpp | 91 ++++++++------- src/add-ons/kernel/file_systems/ext2/Inode.cpp | 82 ++++++++------ src/add-ons/kernel/file_systems/ext2/Inode.h | 5 +- .../kernel/file_systems/ext2/InodeJournal.cpp | 50 ++++----- .../file_systems/ext2/kernel_interface.cpp | 17 ++- src/system/kernel/device_manager/IORequest.cpp | 112 ++++++++++++++++++- src/system/kernel/device_manager/IORequest.h | 7 ++ src/system/kernel/fs/vfs.cpp | 32 ++---- src/system/kernel/fs/vfs_request_io.cpp | 31 ++++- src/system/kernel/vm/vm.cpp | 2 +- ############################################################################ Commit: e5f65913828a6ca3d252f149ccb113e90a8532ef URL: http://cgit.haiku-os.org/haiku/commit/?id=e5f6591 Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Mon Nov 11 17:39:28 2013 UTC VM: vm_memset_physical(): Correct length parameter type ---------------------------------------------------------------------------- diff --git a/headers/private/kernel/vm/vm.h b/headers/private/kernel/vm/vm.h index 1962f41..9aa7f21 100644 --- a/headers/private/kernel/vm/vm.h +++ b/headers/private/kernel/vm/vm.h @@ -149,7 +149,7 @@ off_t vm_available_not_needed_memory(void); off_t vm_available_not_needed_memory_debug(void); size_t vm_kernel_address_space_left(void); -status_t vm_memset_physical(phys_addr_t address, int value, size_t length); +status_t vm_memset_physical(phys_addr_t address, int value, phys_size_t length); status_t vm_memcpy_from_physical(void* to, phys_addr_t from, size_t length, bool user); status_t vm_memcpy_to_physical(phys_addr_t to, const void* from, size_t length, diff --git a/src/system/kernel/vm/vm.cpp b/src/system/kernel/vm/vm.cpp index 2e5a374..7afa856 100644 --- a/src/system/kernel/vm/vm.cpp +++ b/src/system/kernel/vm/vm.cpp @@ -4975,7 +4975,7 @@ vm_resize_area(area_id areaID, size_t newSize, bool kernel) status_t -vm_memset_physical(phys_addr_t address, int value, size_t length) +vm_memset_physical(phys_addr_t address, int value, phys_size_t length) { return sPhysicalPageMapper->MemsetPhysical(address, value, length); } ############################################################################ Commit: 07f6506eb661220c5e2603c2c6896175a001fa69 URL: http://cgit.haiku-os.org/haiku/commit/?id=07f6506 Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Mon Nov 11 17:45:12 2013 UTC VFS: Fix broken zero_pages() Besides that it failed to actually iterate through the vectors, it shouldn't try to clear physical memory in the first place. The iovecs refer to virtual address ranges. Rename it to zero_iovecs() to avoid confusion. ---------------------------------------------------------------------------- diff --git a/src/system/kernel/fs/vfs.cpp b/src/system/kernel/fs/vfs.cpp index 561688f..02cf8ff 100644 --- a/src/system/kernel/fs/vfs.cpp +++ b/src/system/kernel/fs/vfs.cpp @@ -3401,29 +3401,17 @@ dump_vnode_usage(int argc, char** argv) #endif // ADD_DEBUGGER_COMMANDS -/*! Clears an iovec array of physical pages. - Returns in \a _bytes the number of bytes successfully cleared. + +/*! Clears memory specified by an iovec array. */ -static status_t -zero_pages(const iovec* vecs, size_t vecCount, size_t* _bytes) +static void +zero_iovecs(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; - } - + for (size_t i = 0; i < vecCount && bytes > 0; i++) { + size_t length = std::min(vecs[i].iov_len, bytes); + memset(vecs[i].iov_base, 0, length); bytes -= length; } - - return B_OK; } @@ -3463,7 +3451,8 @@ common_file_io_vec_pages(struct vnode* vnode, void* cookie, &vecs[vecIndex], vecCount - vecIndex, &size); } else { // sparse read - status = zero_pages(&vecs[vecIndex], vecCount - vecIndex, &size); + zero_iovecs(&vecs[vecIndex], vecCount - vecIndex, size); + status = B_OK; } if (status != B_OK) return status; @@ -3566,7 +3555,8 @@ common_file_io_vec_pages(struct vnode* vnode, void* cookie, status = B_IO_ERROR; } else { // sparse read - status = zero_pages(tempVecs, tempCount, &bytes); + zero_iovecs(tempVecs, tempCount, bytes); + status = B_OK; } } else if (doWrite) { status = FS_CALL(vnode, write_pages, cookie, fileOffset, ############################################################################ Commit: 426fe7db1db7b0f85660e792f7166ddcf96c4ac8 URL: http://cgit.haiku-os.org/haiku/commit/?id=426fe7d Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Mon Nov 11 17:47:21 2013 UTC IORequest::_CopyData(): Small optimization If we're running in the context of the user team the I/O buffer belongs to, we can use _CopySimple() as well. ---------------------------------------------------------------------------- diff --git a/src/system/kernel/device_manager/IORequest.cpp b/src/system/kernel/device_manager/IORequest.cpp index 19b9be3..48ae3b7 100644 --- a/src/system/kernel/device_manager/IORequest.cpp +++ b/src/system/kernel/device_manager/IORequest.cpp @@ -1173,7 +1173,7 @@ IORequest::_CopyData(void* _buffer, off_t offset, size_t size, bool copyIn) if (fBuffer->IsPhysical()) { copyFunction = &IORequest::_CopyPhysical; } else { - copyFunction = fBuffer->IsUser() + copyFunction = fBuffer->IsUser() && fTeam != team_get_current_team_id() ? &IORequest::_CopyUser : &IORequest::_CopySimple; } ############################################################################ Commit: c63b3de66577d284d5781262ad499347affa4031 URL: http://cgit.haiku-os.org/haiku/commit/?id=c63b3de Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Mon Nov 11 17:48:54 2013 UTC IORequest: Add ClearData() ---------------------------------------------------------------------------- diff --git a/src/system/kernel/device_manager/IORequest.cpp b/src/system/kernel/device_manager/IORequest.cpp index 48ae3b7..2fc2376 100644 --- a/src/system/kernel/device_manager/IORequest.cpp +++ b/src/system/kernel/device_manager/IORequest.cpp @@ -13,6 +13,7 @@ #include <debug.h> #include <heap.h> #include <kernel.h> +#include <team.h> #include <thread.h> #include <util/AutoLock.h> #include <vm/vm.h> @@ -1154,6 +1155,60 @@ IORequest::CopyData(const void* buffer, off_t offset, size_t size) status_t +IORequest::ClearData(off_t offset, generic_size_t size) +{ + if (size == 0) + return B_OK; + + if (offset < fOffset || offset + (off_t)size > fOffset + (off_t)fLength) { + panic("IORequest::ClearData(): invalid range: (%" B_PRIdOFF + ", %" B_PRIuGENADDR ")", offset, size); + return B_BAD_VALUE; + } + + // If we can, we directly copy from/to the virtual buffer. The memory is + // locked in this case. + status_t (*clearFunction)(generic_addr_t, generic_size_t, team_id); + if (fBuffer->IsPhysical()) { + clearFunction = &IORequest::_ClearDataPhysical; + } else { + clearFunction = fBuffer->IsUser() && fTeam != team_get_current_team_id() + ? &IORequest::_ClearDataUser : &IORequest::_ClearDataSimple; + } + + // skip bytes if requested + generic_io_vec* vecs = fBuffer->Vecs(); + generic_size_t skipBytes = offset - fOffset; + generic_size_t vecOffset = 0; + while (skipBytes > 0) { + if (vecs[0].length > skipBytes) { + vecOffset = skipBytes; + break; + } + + skipBytes -= vecs[0].length; + vecs++; + } + + // clear vector-wise + while (size > 0) { + generic_size_t toClear = min_c(size, vecs[0].length - vecOffset); + status_t error = clearFunction(vecs[0].base + vecOffset, toClear, + fTeam); + if (error != B_OK) + return error; + + size -= toClear; + vecs++; + vecOffset = 0; + } + + return B_OK; + +} + + +status_t IORequest::_CopyData(void* _buffer, off_t offset, size_t size, bool copyIn) { if (size == 0) @@ -1271,6 +1326,57 @@ IORequest::_CopyUser(void* _bounceBuffer, generic_addr_t _external, size_t size, } +/*static*/ status_t +IORequest::_ClearDataSimple(generic_addr_t external, generic_size_t size, + team_id team) +{ + memset((void*)(addr_t)external, 0, (size_t)size); + return B_OK; +} + + +/*static*/ status_t +IORequest::_ClearDataPhysical(generic_addr_t external, generic_size_t size, + team_id team) +{ + return vm_memset_physical((phys_addr_t)external, 0, (phys_size_t)size); +} + + +/*static*/ status_t +IORequest::_ClearDataUser(generic_addr_t _external, generic_size_t size, + team_id team) +{ + uint8* external = (uint8*)(addr_t)_external; + + while (size > 0) { + static const int32 kEntryCount = 8; + physical_entry entries[kEntryCount]; + + uint32 count = kEntryCount; + status_t error = get_memory_map_etc(team, external, size, entries, + &count); + if (error != B_OK && error != B_BUFFER_OVERFLOW) { + panic("IORequest::_ClearDataUser(): Failed to get physical memory " + "for user memory %p\n", external); + return B_BAD_ADDRESS; + } + + for (uint32 i = 0; i < count; i++) { + const physical_entry& entry = entries[i]; + error = _ClearDataPhysical(entry.address, entry.size, team); + if (error != B_OK) + return error; + + size -= entry.size; + external += entry.size; + } + } + + return B_OK; +} + + void IORequest::Dump() const { diff --git a/src/system/kernel/device_manager/IORequest.h b/src/system/kernel/device_manager/IORequest.h index 14dd396..f0f1e39 100644 --- a/src/system/kernel/device_manager/IORequest.h +++ b/src/system/kernel/device_manager/IORequest.h @@ -302,6 +302,7 @@ struct IORequest : IORequestChunk, DoublyLinkedListLinkImpl<IORequest> { size_t size); status_t CopyData(const void* buffer, off_t offset, size_t size); + status_t ClearData(off_t offset, generic_size_t size); void Dump() const; @@ -317,6 +318,12 @@ private: static status_t _CopyUser(void* bounceBuffer, generic_addr_t external, size_t size, team_id team, bool copyIn); + static status_t _ClearDataSimple(generic_addr_t external, + generic_size_t size, team_id team); + static status_t _ClearDataPhysical(generic_addr_t external, + generic_size_t size, team_id team); + static status_t _ClearDataUser(generic_addr_t external, + generic_size_t size, team_id team); mutex fLock; IORequestOwner* fOwner; ############################################################################ Commit: 9f7e78ee7980f77cb2c96da32274e02def571b74 URL: http://cgit.haiku-os.org/haiku/commit/?id=9f7e78e Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Mon Nov 11 21:17:34 2013 UTC IORequest::Init(): Assert offset >= 0 Just to make sure we catch sparse file vectors that shouldn't be passed here. ---------------------------------------------------------------------------- diff --git a/src/system/kernel/device_manager/IORequest.cpp b/src/system/kernel/device_manager/IORequest.cpp index 2fc2376..f39f213 100644 --- a/src/system/kernel/device_manager/IORequest.cpp +++ b/src/system/kernel/device_manager/IORequest.cpp @@ -724,6 +724,8 @@ status_t IORequest::Init(off_t offset, generic_addr_t buffer, generic_size_t length, bool write, uint32 flags) { + ASSERT(offset >= 0); + generic_io_vec vec; vec.base = buffer; vec.length = length; @@ -736,6 +738,8 @@ IORequest::Init(off_t offset, generic_size_t firstVecOffset, const generic_io_vec* vecs, size_t count, generic_size_t length, bool write, uint32 flags) { + ASSERT(offset >= 0); + fBuffer = IOBuffer::Create(count, (flags & B_VIP_IO_REQUEST) != 0); if (fBuffer == NULL) return B_NO_MEMORY; ############################################################################ Commit: 24d0e21f51e88ab35cc3f1c1750741dfeb40933d URL: http://cgit.haiku-os.org/haiku/commit/?id=24d0e21 Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Mon Nov 11 17:58:09 2013 UTC do_iterative_fd_io_iterate(): Support sparse files * Check whether the vectors we get are sparse file vectors and satisfy them immediately instead of creating a subrequest. Untested, since the API isn't used by ext2 as it should be. * Add error == B_OK to the condition of the outer loop. ---------------------------------------------------------------------------- diff --git a/src/system/kernel/fs/vfs_request_io.cpp b/src/system/kernel/fs/vfs_request_io.cpp index 4a7984d..8c42dbd 100644 --- a/src/system/kernel/fs/vfs_request_io.cpp +++ b/src/system/kernel/fs/vfs_request_io.cpp @@ -165,12 +165,33 @@ do_iterative_fd_io_iterate(void* _cookie, io_request* request, // create subrequests for the file vecs we've got size_t subRequestCount = 0; - for (size_t i = 0; i < vecCount && subRequestCount < kMaxSubRequests; i++) { + for (size_t i = 0; + i < vecCount && subRequestCount < kMaxSubRequests && error == B_OK; + i++) { off_t vecOffset = vecs[i].offset; off_t vecLength = min_c(vecs[i].length, (off_t)requestLength); TRACE_RIO("[%ld] vec %lu offset: %lld, length: %lld\n", find_thread(NULL), i, vecOffset, vecLength); + // Special offset -1 means that this is part of sparse file that is + // zero. We fill it in right here. + if (vecOffset == -1) { + if (request->IsWrite()) { + panic("do_iterative_fd_io_iterate(): write to sparse file " + "vector"); + error = B_BAD_VALUE; + break; + } + + error = request->ClearData(requestOffset, vecLength); + if (error != B_OK) + break; + + requestOffset += vecLength; + requestLength -= vecLength; + continue; + } + while (vecLength > 0 && subRequestCount < kMaxSubRequests) { TRACE_RIO("[%ld] creating subrequest: offset: %lld, length: " "%lld\n", find_thread(NULL), vecOffset, vecLength); @@ -200,6 +221,14 @@ do_iterative_fd_io_iterate(void* _cookie, io_request* request, request->Advance(requestOffset - cookie->request_offset); cookie->request_offset = requestOffset; + // If we don't have any sub requests at this point, that means all that + // remained were zeroed sparse file vectors. So the request is done now. + if (subRequestCount == 0) { + ASSERT(request->RemainingBytes() == 0); + request->SetStatusAndNotify(B_OK); + return B_OK; + } + // Schedule the subrequests. IORequest* nextSubRequest = request->FirstSubRequest(); while (nextSubRequest != NULL) { ############################################################################ Commit: fd91d2cbe1f045c71e94fa7db6fbce2b6b0d4883 URL: http://cgit.haiku-os.org/haiku/commit/?id=fd91d2c Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Mon Nov 11 20:45:03 2013 UTC Ticket: https://dev.haiku-os.org/ticket/9274 ext2: ExtentStream::FindBlock(): Restructure/fix * The binary search was somewhat broken. * Restructure a bit so that only the binary/linear search itself is handled separately. The handling afterwards is common again. * Fix sparse block handling: - There can be sparse blocks before the first extend. - Set the return parameter _count in this case as well. - Set the return parameter block to 0 instead of 0xffffffff. That's what ext2_get_file_map() expects. Fixes an infinite loop in ext2_get_file_map() when sparse blocks are involved, due to previously returning a wrong block and a 0 count. Ticket #9274 may be related. ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/file_systems/ext2/ExtentStream.cpp b/src/add-ons/kernel/file_systems/ext2/ExtentStream.cpp index 6bf7ff6..3374d1b 100644 --- a/src/add-ons/kernel/file_systems/ext2/ExtentStream.cpp +++ b/src/add-ons/kernel/file_systems/ext2/ExtentStream.cpp @@ -77,60 +77,71 @@ ExtentStream::FindBlock(off_t offset, fsblock_t& block, uint32 *_count) panic("ExtentStream::FindBlock() invalid header\n"); } + // find the extend following the one that should contain the logical block + int32 extentIndex; if (stream->extent_header.NumEntries() > 7) { // binary search when enough entries int32 low = 0; int32 high = stream->extent_header.NumEntries() - 1; - int32 middle = 0; - while (low <= high) { - middle = (high + low) >> 1; - if (stream->extent_entries[middle].LogicalBlock() == index) - break; - if (stream->extent_entries[middle].LogicalBlock() < index) - low = middle + 1; - else + while (low < high) { + int32 middle = (high + low + 1) / 2; + if (stream->extent_entries[middle].LogicalBlock() > index) high = middle - 1; + else + low = middle; } - if (stream->extent_entries[middle].LogicalBlock() > index) - middle--; - fileblock_t diff = index - - stream->extent_entries[middle].LogicalBlock(); - if (diff > stream->extent_entries[middle].Length()) { - // sparse block - TRACE("FindBlock() sparse block index %" B_PRIu64 " at %" B_PRIu32 - "\n", index, stream->extent_entries[middle].LogicalBlock()); - block = 0xffffffff; - return B_OK; + + extentIndex = low + 1; + } else { + extentIndex = stream->extent_header.NumEntries(); + for (int32 i = 0; i < stream->extent_header.NumEntries(); i++) { + if (stream->extent_entries[i].LogicalBlock() > index) { + extentIndex = i; + break; + } } + } - block = stream->extent_entries[middle].PhysicalBlock() + diff; - if (_count) - *_count = stream->extent_entries[middle].Length() - diff; - TRACE("FindBlock(offset %" B_PRIdOFF "): %" B_PRIu64 " %" B_PRIu32 - "\n", offset, block, _count != NULL ? *_count : 1); + fileblock_t logicalEndIndex + = (fSize + fVolume->BlockSize() - 1) >> fVolume->BlockShift(); + + if (extentIndex == 0) { + // sparse block at the beginning of the stream + block = 0; + if (_count != NULL) { + *_count = stream->extent_header.NumEntries() == 0 + ? logicalEndIndex - index + : stream->extent_entries[0].LogicalBlock() - index; + } + TRACE("FindBlock() sparse block index %" B_PRIu64 " at beginning of " + "stream\n", index); return B_OK; } - for (int32 i = 0; i < stream->extent_header.NumEntries(); i++) { - if (stream->extent_entries[i].LogicalBlock() > index) { - // sparse block - TRACE("FindBlock() sparse block index %" B_PRIu64 " at %" B_PRIu32 - "\n", index, stream->extent_entries[i].LogicalBlock()); - block = 0xffffffff; - return B_OK; - } - fileblock_t diff = index - stream->extent_entries[i].LogicalBlock(); - if (diff < stream->extent_entries[i].Length()) { - block = stream->extent_entries[i].PhysicalBlock() + diff; - if (_count) - *_count = stream->extent_entries[i].Length() - diff; - TRACE("FindBlock(offset %" B_PRIdOFF "): %" B_PRIu64 " %" B_PRIu32 - "\n", offset, block, _count != NULL ? *_count : 1); - return B_OK; + const ext2_extent_entry& extent = stream->extent_entries[extentIndex - 1]; + // the extent supposedly containing the offset + fileblock_t diff = index - extent.LogicalBlock(); + if (diff >= extent.Length()) { + // sparse block between extends or at the end of the stream + TRACE("FindBlock() sparse block index %" B_PRIu64 " at %" B_PRIu32 + "\n", index, extent.LogicalBlock()); + block = 0; + if (_count != NULL) { + *_count = stream->extent_header.NumEntries() == extentIndex + ? logicalEndIndex - index + : stream->extent_entries[extentIndex].LogicalBlock() - index; } + return B_OK; } - return B_ERROR; + block = extent.PhysicalBlock() + diff; + if (_count != NULL) + *_count = extent.Length() - diff; + + TRACE("FindBlock(offset %" B_PRIdOFF "): %" B_PRIu64 " %" B_PRIu32 + "\n", offset, block, _count != NULL ? *_count : 1); + + return B_OK; } ############################################################################ Commit: 05826ec74b13fa9e5daf7a56f30dc4aa40b67707 URL: http://cgit.haiku-os.org/haiku/commit/?id=05826ec Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Mon Nov 11 20:48:32 2013 UTC ext2_get_file_map(): Fix broken termination condition ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp b/src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp index daea2ec..9d38de2 100644 --- a/src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp @@ -465,14 +465,15 @@ ext2_get_file_map(fs_volume* _volume, fs_vnode* _node, off_t offset, } offset += blockLength; - size -= blockLength; - if ((off_t)size <= vecs[index - 1].length || offset >= inode->Size()) { + if (offset >= inode->Size() || size <= blockLength) { // We're done! *_count = index; TRACE("ext2_get_file_map for inode %" B_PRIdINO "\n", inode->ID()); return B_OK; } + + size -= blockLength; } // can never get here ############################################################################ Revision: hrev46358 Commit: 26aef3ac62e67e29e7895213ef7c5253798564f4 URL: http://cgit.haiku-os.org/haiku/commit/?id=26aef3a Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Mon Nov 11 21:16:14 2013 UTC ext2: Fix enabling/disabling the file cache * Inode: - Rename {Enable,Disable}FileCache() to {Create,Delete}FileCache() and IsFileCacheDisabled() to HasFileCache(), since that is what they actually do. DeleteFileCache() now also sets the attributes to NULL, which makes fCached superfluous. - Introduce {Enable,Disable}FileCache(), which actually enable/disable the file cache. Use those methods for handling O_NOCACHE. * ext2_free_cookie(): Reenable the file cache in case of O_NOCACHE. Fixes crash when O_NOCACHE was used, since the file cache was deleted without clearing the attribute and Inode::ReadAt() would use the deleted object afterward. ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/file_systems/ext2/Inode.cpp b/src/add-ons/kernel/file_systems/ext2/Inode.cpp index e8a1529..7f84af7 100644 --- a/src/add-ons/kernel/file_systems/ext2/Inode.cpp +++ b/src/add-ons/kernel/file_systems/ext2/Inode.cpp @@ -37,7 +37,6 @@ Inode::Inode(Volume* volume, ino_t id) fID(id), fCache(NULL), fMap(NULL), - fCached(false), fHasExtraAttributes(false) { rw_lock_init(&fLock, "ext2 inode"); @@ -56,11 +55,9 @@ Inode::Inode(Volume* volume, ino_t id) if (IsDirectory() || (IsSymLink() && Size() < 60)) { TRACE("Inode::Inode(): Not creating the file cache\n"); - fCached = false; - fInitStatus = B_OK; } else - fInitStatus = EnableFileCache(); + fInitStatus = CreateFileCache(); } else TRACE("Inode: Failed initialization\n"); } @@ -72,7 +69,6 @@ Inode::Inode(Volume* volume) fID(0), fCache(NULL), fMap(NULL), - fCached(false), fInitStatus(B_NO_INIT) { rw_lock_init(&fLock, "ext2 inode"); @@ -89,11 +85,7 @@ Inode::~Inode() { TRACE("Inode destructor\n"); - if (fCached) { - TRACE("Deleting the file cache and file map\n"); - file_cache_delete(FileCache()); - file_map_delete(Map()); - } + DeleteFileCache(); TRACE("Inode destructor: Done\n"); } @@ -269,7 +261,7 @@ Inode::WriteAt(Transaction& transaction, off_t pos, const uint8* buffer, buffer, _length, *_length); ReadLocker readLocker(fLock); - if (IsFileCacheDisabled()) + if (!HasFileCache()) return B_BAD_VALUE; if (pos < 0) @@ -697,7 +689,7 @@ Inode::Create(Transaction& transaction, Inode* parent, const char* name, if (!inode->IsSymLink()) { // Vnode::Publish doesn't publish symlinks if (!inode->IsDirectory()) { - status = inode->EnableFileCache(); + status = inode->CreateFileCache(); if (status != B_OK) return status; } @@ -726,47 +718,69 @@ Inode::Create(Transaction& transaction, Inode* parent, const char* name, status_t -Inode::EnableFileCache() +Inode::CreateFileCache() { - TRACE("Inode::EnableFileCache()\n"); + TRACE("Inode::CreateFileCache()\n"); - if (fCached) - return B_OK; - if (fCache != NULL) { - fCached = true; + if (fCache != NULL) return B_OK; - } - TRACE("Inode::EnableFileCache(): Creating file cache: %" B_PRIu32 ", %" + TRACE("Inode::CreateFileCache(): Creating file cache: %" B_PRIu32 ", %" B_PRIdINO ", %" B_PRIdOFF "\n", fVolume->ID(), ID(), Size()); - fCache = file_cache_create(fVolume->ID(), ID(), Size()); - fMap = file_map_create(fVolume->ID(), ID(), Size()); + fCache = file_cache_create(fVolume->ID(), ID(), Size()); if (fCache == NULL) { - ERROR("Inode::EnableFileCache(): Failed to create file cache\n"); - fCached = false; + ERROR("Inode::CreateFileCache(): Failed to create file cache\n"); return B_ERROR; } - fCached = true; - TRACE("Inode::EnableFileCache(): Done\n"); + fMap = file_map_create(fVolume->ID(), ID(), Size()); + if (fMap == NULL) { + ERROR("Inode::CreateFileCache(): Failed to create file map\n"); + file_cache_delete(fCache); + fCache = NULL; + return B_ERROR; + } + + TRACE("Inode::CreateFileCache(): Done\n"); return B_OK; } +void +Inode::DeleteFileCache() +{ + TRACE("Inode::DeleteFileCache()\n"); + + if (fCache == NULL) + return; + + file_cache_delete(fCache); + file_map_delete(fMap); + + fCache = NULL; + fMap = NULL; +} + + status_t -Inode::DisableFileCache() +Inode::EnableFileCache() { - TRACE("Inode::DisableFileCache()\n"); + if (fCache == NULL) + return B_BAD_VALUE; - if (!fCached) - return B_OK; + file_cache_enable(fCache); + return B_OK; +} - file_cache_delete(FileCache()); - file_map_delete(Map()); - fCached = false; +status_t +Inode::DisableFileCache() +{ + status_t error = file_cache_disable(fCache); + if (error != B_OK) + return error; return B_OK; } @@ -775,7 +789,7 @@ Inode::DisableFileCache() status_t Inode::Sync() { - if (!IsFileCacheDisabled()) + if (HasFileCache()) return file_cache_sync(fCache); return B_OK; diff --git a/src/add-ons/kernel/file_systems/ext2/Inode.h b/src/add-ons/kernel/file_systems/ext2/Inode.h index 098f835..d4fe2cc 100644 --- a/src/add-ons/kernel/file_systems/ext2/Inode.h +++ b/src/add-ons/kernel/file_systems/ext2/Inode.h @@ -112,9 +112,11 @@ public: void* FileCache() const { return fCache; } void* Map() const { return fMap; } + status_t CreateFileCache(); + void DeleteFileCache(); + bool HasFileCache() { return fCache != NULL; } status_t EnableFileCache(); status_t DisableFileCache(); - bool IsFileCacheDisabled() const { return !fCached; } status_t Sync(); @@ -144,7 +146,6 @@ private: ino_t fID; void* fCache; void* fMap; - bool fCached; bool fUnlinked; bool fHasExtraAttributes; ext2_inode fNode; diff --git a/src/add-ons/kernel/file_systems/ext2/InodeJournal.cpp b/src/add-ons/kernel/file_systems/ext2/InodeJournal.cpp index cadc0f4..d674c11 100644 --- a/src/add-ons/kernel/file_systems/ext2/InodeJournal.cpp +++ b/src/add-ons/kernel/file_systems/ext2/InodeJournal.cpp @@ -39,32 +39,30 @@ InodeJournal::InodeJournal(Inode* inode) fJournalVolume = volume; fJournalBlockCache = volume->BlockCache(); - if (!inode->IsFileCacheDisabled()) - fInitStatus = inode->DisableFileCache(); - else - fInitStatus = B_OK; - - if (fInitStatus == B_OK) { - TRACE("InodeJournal::InodeJournal(): Inode's file cache disabled " - "successfully\n"); - HashRevokeManager* revokeManager = new(std::nothrow) - HashRevokeManager; - TRACE("InodeJournal::InodeJournal(): Allocated a hash revoke " - "manager at %p\n", revokeManager); - - if (revokeManager == NULL) { - TRACE("InodeJournal::InodeJournal(): Insufficient memory to " - "create the hash revoke manager\n"); - fInitStatus = B_NO_MEMORY; - } else { - fInitStatus = revokeManager->Init(); - - if (fInitStatus == B_OK) { - fRevokeManager = revokeManager; - fInitStatus = _LoadSuperBlock(); - } else - delete revokeManager; - } + if (inode->HasFileCache()) + inode->DeleteFileCache(); + + fInitStatus = B_OK; + + TRACE("InodeJournal::InodeJournal(): Inode's file cache disabled " + "successfully\n"); + HashRevokeManager* revokeManager = new(std::nothrow) + HashRevokeManager; + TRACE("InodeJournal::InodeJournal(): Allocated a hash revoke " + "manager at %p\n", revokeManager); + + if (revokeManager == NULL) { + TRACE("InodeJournal::InodeJournal(): Insufficient memory to " + "create the hash revoke manager\n"); + fInitStatus = B_NO_MEMORY; + } else { + fInitStatus = revokeManager->Init(); + + if (fInitStatus == B_OK) { + fRevokeManager = revokeManager; + fInitStatus = _LoadSuperBlock(); + } else + delete revokeManager; } } } diff --git a/src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp b/src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp index 9d38de2..9bdb045 100644 --- a/src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp @@ -759,7 +759,7 @@ ext2_create(fs_volume* _volume, fs_vnode* _directory, const char* name, TRACE("ext2_create(): Created inode\n"); - if ((openMode & O_NOCACHE) != 0 && !inode->IsFileCacheDisabled()) { + if ((openMode & O_NOCACHE) != 0) { status = inode->DisableFileCache(); if (status != B_OK) return status; @@ -830,8 +830,8 @@ ext2_create_symlink(fs_volume* _volume, fs_vnode* _directory, const char* name, link->Mode(), 0); put_vnode(volume->FSVolume(), id); - if (link->IsFileCacheDisabled()) { - status = link->EnableFileCache(); + if (!link->HasFileCache()) { + status = link->CreateFileCache(); if (status != B_OK) return status; } @@ -1132,10 +1132,12 @@ ext2_open(fs_volume* _volume, fs_vnode* _node, int openMode, void** _cookie) cookie->last_size = inode->Size(); cookie->last_notification = system_time(); + MethodDeleter<Inode, status_t> fileCacheEnabler(&Inode::EnableFileCache); if ((openMode & O_NOCACHE) != 0) { status = inode->DisableFileCache(); if (status != B_OK) return status; + fileCacheEnabler.SetTo(inode); } // Should we truncate the file? @@ -1157,6 +1159,7 @@ ext2_open(fs_volume* _volume, fs_vnode* _node, int openMode, void** _cookie) // TODO: No need to notify file size changed? } + fileCacheEnabler.Detach(); cookieDeleter.Detach(); *_cookie = cookie; @@ -1246,6 +1249,9 @@ ext2_free_cookie(fs_volume* _volume, fs_vnode* _node, void* _cookie) if (inode->Size() != cookie->last_size) notify_stat_changed(volume->ID(), inode->ID(), B_STAT_SIZE); + if ((cookie->open_mode & O_NOCACHE) != 0) + inode->EnableFileCache(); + delete cookie; return B_OK; }