[haiku-commits] haiku: hrev46358 - in src: add-ons/kernel/file_systems/ext2 system/kernel/device_manager system/kernel/fs

  • From: ingo_weinhold@xxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Mon, 11 Nov 2013 22:28:42 +0100 (CET)

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;
 }


Other related posts:

  • » [haiku-commits] haiku: hrev46358 - in src: add-ons/kernel/file_systems/ext2 system/kernel/device_manager system/kernel/fs - ingo_weinhold