Advertisement
Guest User

Untitled

a guest
Jun 4th, 2017
75
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 132.36 KB | None | 0 0
  1. Index: src/add-ons/kernel/file_systems/ext2/InodeJournal.h
  2. ===================================================================
  3. --- src/add-ons/kernel/file_systems/ext2/InodeJournal.h (revision 0)
  4. +++ src/add-ons/kernel/file_systems/ext2/InodeJournal.h (revision 0)
  5. @@ -0,0 +1,29 @@
  6. +/*
  7. + * Copyright 2001-2010, Haiku Inc. All rights reserved.
  8. + * This file may be used under the terms of the MIT License.
  9. + *
  10. + * Authors:
  11. + *     Janito V. Ferreira Filho
  12. + */
  13. +#ifndef INODEJOURNAL_H
  14. +#define INODEJOURNAL_H
  15. +
  16. +
  17. +#include "Inode.h"
  18. +#include "Journal.h"
  19. +
  20. +
  21. +class InodeJournal : public Journal {
  22. +public:
  23. +                       InodeJournal(Inode* inode);
  24. +                       ~InodeJournal();
  25. +
  26. +           status_t    InitCheck();
  27. +          
  28. +           status_t    MapBlock(uint32 logical, uint32& physical);
  29. +private:
  30. +           Inode*      fInode;
  31. +           status_t    fInitStatus;
  32. +};
  33. +
  34. +#endif // INODEJOURNAL_H
  35. Index: src/add-ons/kernel/file_systems/ext2/InodeAllocator.cpp
  36. ===================================================================
  37. --- src/add-ons/kernel/file_systems/ext2/InodeAllocator.cpp (revision 0)
  38. +++ src/add-ons/kernel/file_systems/ext2/InodeAllocator.cpp (revision 0)
  39. @@ -0,0 +1,110 @@
  40. +/*
  41. + * Copyright 2001-2010, Haiku Inc. All rights reserved.
  42. + * This file may be used under the terms of the MIT License.
  43. + *
  44. + * Authors:
  45. + *     Janito V. Ferreira Filho
  46. + */
  47. +
  48. +#include "InodeAllocator.h"
  49. +
  50. +#include <util/AutoLock.h>
  51. +
  52. +#include "BitmapBlock.h"
  53. +#include "Volume.h"
  54. +
  55. +
  56. +//#define TRACE_EXT2
  57. +#ifdef TRACE_EXT2
  58. +#  define TRACE(x...) dprintf("\33[34mext2:\33[0m " x)
  59. +#else
  60. +#  define TRACE(x...) ;
  61. +#endif
  62. +
  63. +
  64. +InodeAllocator::InodeAllocator(Volume* volume)
  65. +   :
  66. +   fVolume(volume)
  67. +{
  68. +   mutex_init(&fLock, "ext2 inode allocator");
  69. +}
  70. +
  71. +
  72. +InodeAllocator::~InodeAllocator()
  73. +{
  74. +   mutex_destroy(&fLock);
  75. +}
  76. +
  77. +
  78. +status_t
  79. +InodeAllocator::New(Transaction& transaction, uint32 preferredBlockGroup,
  80. +   ino_t& id)
  81. +{
  82. +   MutexLocker lock(fLock);
  83. +
  84. +   uint32 blockGroup = preferredBlockGroup;
  85. +   uint32 lastBlockGroup = fVolume->NumGroups() - 1;
  86. +
  87. +   for (int i = 0; i < 2; ++i) {
  88. +       for (; blockGroup < lastBlockGroup; ++blockGroup) {
  89. +           ext2_block_group* group;
  90. +
  91. +           status_t status = fVolume->GetBlockGroup(blockGroup, &group);
  92. +           if (status != B_OK)
  93. +               return status;
  94. +
  95. +           if (group->FreeInodes() != 0) {
  96. +               return _MarkInBitmap(transaction, group->InodeBitmap(),
  97. +                   blockGroup, fVolume->InodesPerGroup(), id);
  98. +           }
  99. +       }
  100. +
  101. +       if (i == 0) {
  102. +           ext2_block_group* group;
  103. +
  104. +           status_t status = fVolume->GetBlockGroup(blockGroup, &group);
  105. +           if (status != B_OK)
  106. +               return status;
  107. +
  108. +           if (group->FreeInodes() != 0) {
  109. +               return _MarkInBitmap(transaction, group->InodeBitmap(),
  110. +                   blockGroup, fVolume->NumInodes()
  111. +                       - blockGroup * fVolume->InodesPerGroup(), id);
  112. +           }
  113. +       }
  114. +
  115. +       blockGroup = 0;
  116. +       lastBlockGroup = preferredBlockGroup;
  117. +   }
  118. +
  119. +   return B_DEVICE_FULL;
  120. +}
  121. +
  122. +
  123. +status_t
  124. +InodeAllocator::_MarkInBitmap(Transaction& transaction, uint32 bitmapBlock,
  125. +   uint32 blockGroup, uint32 numInodes, ino_t& id)
  126. +{
  127. +   BitmapBlock inodeBitmap(fVolume, numInodes);
  128. +
  129. +   if (!inodeBitmap.SetToWritable(transaction, bitmapBlock)) {
  130. +       TRACE("Unable to open inode bitmap (block number: %lu) for block group "
  131. +           "%lu\n", bitmapBlock, blockGroup);
  132. +       return B_IO_ERROR;
  133. +   }
  134. +
  135. +   uint32 pos = 0;
  136. +   inodeBitmap.FindNextUnmarked(pos);
  137. +
  138. +   if (pos == inodeBitmap.NumBits()) {
  139. +       TRACE("Even though the block group %lu indicates there are free "
  140. +           "inodes, no unmarked bit was found in the inode bitmap at block "
  141. +           "%lu.", blockGroup, bitmapBlock);
  142. +       return B_ERROR;
  143. +   }
  144. +
  145. +   inodeBitmap.Mark(pos, true);
  146. +   id = pos + blockGroup * fVolume->InodesPerGroup();
  147. +
  148. +   return B_OK;
  149. +}
  150.  
  151. Property changes on: src/add-ons/kernel/file_systems/ext2/InodeAllocator.cpp
  152. ___________________________________________________________________
  153. Added: svn:executable
  154.    + *
  155.  
  156. Index: src/add-ons/kernel/file_systems/ext2/BlockAllocator.h
  157. ===================================================================
  158. --- src/add-ons/kernel/file_systems/ext2/BlockAllocator.h   (revision 0)
  159. +++ src/add-ons/kernel/file_systems/ext2/BlockAllocator.h   (revision 0)
  160. @@ -0,0 +1,53 @@
  161. +/*
  162. + * Copyright 2001-2010, Haiku Inc. All rights reserved.
  163. + * This file may be used under the terms of the MIT License.
  164. + *
  165. + * Authors:
  166. + *     Janito V. Ferreira Filho
  167. + */
  168. +#ifndef BLOCKALLOCATOR_H
  169. +#define BLOCKALLOCATOR_H
  170. +
  171. +#include <lock.h>
  172. +
  173. +#include "Transaction.h"
  174. +
  175. +
  176. +class AllocationBlockGroup;
  177. +class Inode;
  178. +class Volume;
  179. +
  180. +
  181. +class BlockAllocator {
  182. +public:
  183. +                       BlockAllocator(Volume* volume);
  184. +                       ~BlockAllocator();
  185. +
  186. +           status_t    Initialize();
  187. +
  188. +           status_t    AllocateBlocks(Transaction& transaction,
  189. +                           uint32 minimum, uint32 maximum, uint32& blockGroup,
  190. +                           uint32& start, uint32& length);
  191. +           status_t    Allocate(Transaction& transaction, Inode* inode,
  192. +                           off_t numBlocks, uint32 minimum, uint32& start,
  193. +                           uint32& length);
  194. +           status_t    Free(Transaction& transaction, uint32 start,
  195. +                           uint32 length);
  196. +
  197. +           uint32      FreeBlocks();
  198. +
  199. +protected:
  200. +   static  status_t    _Initialize(BlockAllocator* allocator);
  201. +
  202. +
  203. +           Volume*     fVolume;
  204. +           mutex       fLock;
  205. +
  206. +           AllocationBlockGroup* fGroups;
  207. +           uint32      fBlocksPerGroup;
  208. +           uint32      fNumBlocks;
  209. +           uint32      fNumGroups;
  210. +           uint32      fFirstBlock;
  211. +};
  212. +
  213. +#endif // BLOCKALLOCATOR_H
  214.  
  215. Property changes on: src/add-ons/kernel/file_systems/ext2/BlockAllocator.h
  216. ___________________________________________________________________
  217. Added: svn:executable
  218.    + *
  219.  
  220. Index: src/add-ons/kernel/file_systems/ext2/HTreeEntryIterator.cpp
  221. ===================================================================
  222. --- src/add-ons/kernel/file_systems/ext2/HTreeEntryIterator.cpp (revision 37486)
  223. +++ src/add-ons/kernel/file_systems/ext2/HTreeEntryIterator.cpp (working copy)
  224. @@ -11,6 +11,7 @@
  225.  
  226.  #include <new>
  227.  
  228. +#include "CachedBlock.h"
  229.  #include "HTree.h"
  230.  #include "IndexedDirectoryIterator.h"
  231.  #include "Inode.h"
  232. @@ -27,81 +28,90 @@
  233.  
  234.  HTreeEntryIterator::HTreeEntryIterator(off_t offset, Inode* directory)
  235.     :
  236. +   fDirectory(directory),
  237. +   fVolume(directory->GetVolume()),
  238.     fHasCollision(false),
  239. -   fDirectory(directory),
  240. -   fOffset(offset),
  241. +   fBlockSize(directory->GetVolume()->BlockSize()),
  242.     fParent(NULL),
  243.     fChild(NULL)
  244.  {
  245. -   fBlockSize = fDirectory->GetVolume()->BlockSize();
  246. +   fInitStatus = fDirectory->FindBlock(offset, fBlockNum);
  247. +  
  248. +   if (fInitStatus == B_OK)
  249. +       fCurrentEntry = offset % fBlockSize / sizeof(HTreeEntry);
  250. +
  251. +   TRACE("HTreeEntryIterator::HTreeEntryIterator() block %lu entry no. %lu\n",
  252. +       fBlockNum, (uint32)fCurrentEntry);
  253.  }
  254.  
  255.  
  256.  HTreeEntryIterator::HTreeEntryIterator(uint32 block, uint32 blockSize,
  257.     Inode* directory, HTreeEntryIterator* parent, bool hasCollision)
  258.     :
  259. +   fDirectory(directory),
  260. +   fVolume(directory->GetVolume()),
  261.     fHasCollision(hasCollision),
  262.     fBlockSize(blockSize),
  263. -   fDirectory(directory),
  264. -   fOffset(block * blockSize + sizeof(HTreeFakeDirEntry)),
  265. +   fBlockNum(block),
  266.     fParent(parent),
  267.     fChild(NULL)
  268.  {
  269. -   TRACE("HTreeEntryIterator::HTreeEntryIterator() block %ld offset %Lx\n",
  270. -       block, fOffset);
  271. +   fInitStatus = B_OK;
  272. +
  273. +   TRACE("HTreeEntryIterator::HTreeEntryIterator() block %lu\n", block);
  274.  }
  275.  
  276.  
  277.  status_t
  278.  HTreeEntryIterator::Init()
  279.  {
  280. -   size_t length = sizeof(HTreeCountLimit);
  281. -   HTreeCountLimit countLimit;
  282. +   TRACE("HTreeEntryIterator::Init() current entry: %lu\n",
  283. +       (uint32)fCurrentEntry);
  284.    
  285. -   status_t status = fDirectory->ReadAt(fOffset, (uint8*)&countLimit,
  286. -       &length);
  287. -  
  288. -   if (status != B_OK)
  289. -       return status;
  290. -  
  291. -   if (length != sizeof(HTreeCountLimit)) {
  292. -       ERROR("HTreeEntryIterator::Init() bad length %ld fOffset 0x%Lx\n",
  293. -           length, fOffset);
  294. +   if (fInitStatus != B_OK)
  295. +       return fInitStatus;
  296. +
  297. +   CachedBlock cached(fVolume);
  298. +   const uint8* block = cached.SetTo(fBlockNum);
  299. +   if (block == NULL) {
  300. +       ERROR("Failed to read htree entry block.\n");
  301.         fCount = fLimit = 0;
  302. -       return B_ERROR;
  303. +       return B_IO_ERROR;
  304.     }
  305. -  
  306. -   fCount = countLimit.Count();
  307. -   fLimit = countLimit.Limit();
  308.  
  309. +   HTreeCountLimit* countLimit = (HTreeCountLimit*)(
  310. +       &((HTreeEntry*)block)[fCurrentEntry]);
  311. +
  312. +   fCount = countLimit->Count();
  313. +   fLimit = countLimit->Limit();
  314. +
  315.     if (fCount >= fLimit) {
  316. -       ERROR("HTreeEntryIterator::Init() bad fCount %d fOffset 0x%Lx\n",
  317. -           fCount, fOffset);
  318. +       ERROR("HTreeEntryIterator::Init() bad fCount %lu\n", (uint32)fCount);
  319.         fCount = fLimit = 0;
  320.         return B_ERROR;
  321.     }
  322.  
  323. -   if (fParent != NULL &&
  324. -       fLimit != ((fBlockSize - sizeof(HTreeFakeDirEntry))
  325. -           / sizeof(HTreeEntry)) ) {
  326. -       ERROR("HTreeEntryIterator::Init() bad fLimit %d should be %ld "
  327. -           "fOffset 0x%Lx\n", fLimit, (fBlockSize - sizeof(HTreeFakeDirEntry))
  328. -               / sizeof(HTreeEntry), fOffset);
  329. +   if (fLimit != (fBlockSize - sizeof(HTreeFakeDirEntry))
  330. +           / sizeof(HTreeEntry) - fCurrentEntry) {
  331. +       ERROR("HTreeEntryIterator::Init() bad fLimit %lu should be %lu "
  332. +           "at block %lu\n", (uint32)fLimit,
  333. +           (fBlockSize - sizeof(HTreeFakeDirEntry)) / sizeof(HTreeEntry)
  334. +               - fCurrentEntry,
  335. +           fBlockNum);
  336.         fCount = fLimit = 0;
  337.         return B_ERROR;
  338. -   }
  339. +   }
  340.  
  341. -   TRACE("HTreeEntryIterator::Init() count 0x%x limit 0x%x\n", fCount,
  342. -       fLimit);
  343. +   TRACE("HTreeEntryIterator::Init() count %lu limit %lu\n",
  344. +       (uint32)fCount, (uint32)fLimit);
  345.  
  346. -   fMaxOffset = fOffset + (fCount - 1) * sizeof(HTreeEntry);
  347. -  
  348.     return B_OK;
  349.  }
  350.  
  351.  
  352.  HTreeEntryIterator::~HTreeEntryIterator()
  353.  {
  354. +   delete fChild;
  355.  }
  356.  
  357.  
  358. @@ -109,68 +119,70 @@
  359.  HTreeEntryIterator::Lookup(uint32 hash, int indirections,
  360.     DirectoryIterator** directoryIterator)
  361.  {
  362. -   off_t start = fOffset + sizeof(HTreeEntry);
  363. -   off_t end = fMaxOffset;
  364. -   off_t middle = start;
  365. -   size_t entrySize = sizeof(HTreeEntry);
  366. -   HTreeEntry entry;
  367. -  
  368. +   TRACE("HTreeEntryIterator::Lookup()\n");
  369. +   CachedBlock cached(fVolume);
  370. +   const uint8* block = cached.SetTo(fBlockNum);
  371. +   if (block == NULL) {
  372. +       ERROR("Failed to read htree entry block.\n");
  373. +       // Fallback to linear search
  374. +       *directoryIterator = new(std::nothrow)
  375. +           DirectoryIterator(fDirectory);
  376. +
  377. +       if (*directoryIterator == NULL)
  378. +           return B_NO_MEMORY;
  379. +
  380. +       return B_OK;
  381. +   }
  382. +
  383. +   HTreeEntry* start = (HTreeEntry*)block + fCurrentEntry + 1;
  384. +   HTreeEntry* end = (HTreeEntry*)block + fCount;
  385. +   HTreeEntry* middle = start;
  386. +
  387.     while (start <= end) {
  388. -       middle = (end - start) / 2;
  389. -       middle -= middle % entrySize; // Alignment
  390. -       middle += start;
  391. +       middle = (HTreeEntry*)(((uint8*)end - (uint8*)start) / 2
  392. +           + (uint8*)start);
  393.  
  394. -       TRACE("HTreeEntryIterator::Lookup() %d 0x%Lx 0x%Lx 0x%Lx\n",
  395. +       TRACE("HTreeEntryIterator::Lookup() indirections: %d s:%p m:%p e:%p\n",
  396.             indirections, start, end, middle);
  397. -      
  398. -       status_t status = fDirectory->ReadAt(middle, (uint8*)&entry,
  399. -           &entrySize);
  400.  
  401. -       TRACE("HTreeEntryIterator::Lookup() %lx %lx\n", hash, entry.Hash());
  402. -      
  403. -       if (status != B_OK)
  404. -           return status;
  405. -       else if (entrySize != sizeof(entry)) {
  406. -           // Fallback to linear search
  407. -           *directoryIterator = new(std::nothrow)
  408. -               DirectoryIterator(fDirectory);
  409. -          
  410. -           if (*directoryIterator == NULL)
  411. -               return B_NO_MEMORY;
  412. -          
  413. -           return B_OK;
  414. -       }
  415. -      
  416. -       if (hash >= entry.Hash())
  417. -           start = middle + entrySize;
  418. +       TRACE("HTreeEntryIterator::Lookup() %lx %lx\n", hash, middle->Hash());
  419. +
  420. +       if (hash >= middle->Hash())
  421. +           start = middle++;
  422.         else
  423. -           end = middle - entrySize;
  424. +           end = middle--;
  425.     }
  426.  
  427. -   status_t status = fDirectory->ReadAt(start - entrySize, (uint8*)&entry,
  428. -       &entrySize);
  429. -   if (status != B_OK)
  430. -       return status;
  431. -  
  432. +   --start;
  433. +
  434. +   fCurrentEntry = ((uint8*)start - block) / sizeof(HTreeEntry);
  435. +
  436.     if (indirections == 0) {
  437. +       TRACE("HTreeEntryIterator::Lookup(): Creating an indexed directory "
  438. +           "iterator starting at block: %lu, hash: 0x%lX\n", start->Block(),
  439. +           start->Hash());
  440.         *directoryIterator = new(std::nothrow)
  441. -           IndexedDirectoryIterator(entry.Block() * fBlockSize, fBlockSize,
  442. -           fDirectory, this);
  443. -      
  444. +           IndexedDirectoryIterator(start->Block() * fBlockSize, fDirectory,
  445. +               this);
  446. +
  447.         if (*directoryIterator == NULL)
  448.             return B_NO_MEMORY;
  449.  
  450.         return B_OK;
  451.     }
  452.  
  453. +   TRACE("HTreeEntryIterator::Lookup(): Creating a HTree entry iterator "
  454. +       "starting at block: %lu, hash: 0x%lX\n", start->Block(), start->Hash());
  455. +   uint32 blockNum;
  456. +   status_t status = fDirectory->FindBlock(start->Block() * fBlockSize,
  457. +       blockNum);
  458. +
  459.     delete fChild;
  460.  
  461. -   fChild = new(std::nothrow) HTreeEntryIterator(entry.Block(), fBlockSize,
  462. -       fDirectory, this, entry.Hash() & 1 == 1);
  463. -  
  464. +   fChild = new(std::nothrow) HTreeEntryIterator(blockNum, fBlockSize,
  465. +       fDirectory, this, start->Hash() & 1 == 1);
  466.     if (fChild == NULL)
  467.         return B_NO_MEMORY;
  468. -   fChildDeleter.SetTo(fChild);
  469.    
  470.     status = fChild->Init();
  471.     if (status != B_OK)
  472. @@ -181,40 +193,48 @@
  473.  
  474.  
  475.  status_t
  476. -HTreeEntryIterator::GetNext(off_t& childOffset)
  477. +HTreeEntryIterator::GetNext(uint32& childBlock)
  478.  {
  479. -   size_t entrySize = sizeof(HTreeEntry);
  480. -   fOffset += entrySize;
  481. -   bool firstEntry = fOffset >= fMaxOffset;
  482. -  
  483. +   fCurrentEntry++;
  484. +   TRACE("HTreeEntryIterator::GetNext(): current entry: %lu\n",
  485. +       (uint32)fCurrentEntry);
  486. +   bool firstEntry = fCurrentEntry >= fCount;
  487. +
  488.     if (firstEntry) {
  489. -       if (fParent == NULL)
  490. +       TRACE("HTreeEntryIterator::GetNext(): end of entries in the block\n");
  491. +       if (fParent == NULL) {
  492. +           TRACE("HTreeEntryIterator::GetNext(): block was the root block\n");
  493.             return B_ENTRY_NOT_FOUND;
  494. +       }
  495.        
  496. -       status_t status = fParent->GetNext(fOffset);
  497. +       status_t status = fParent->GetNext(fBlockNum);
  498.         if (status != B_OK)
  499.             return status;
  500.        
  501. +       TRACE("HTreeEntryIterator::GetNext(): moving to next block: %lu\n",
  502. +           fBlockNum);
  503. +
  504. +       fCurrentEntry = 0;
  505.         status = Init();
  506.         if (status != B_OK)
  507.             return status;
  508.  
  509.         fHasCollision = fParent->HasCollision();
  510.     }
  511. -  
  512. -   HTreeEntry entry;
  513. -   status_t status = fDirectory->ReadAt(fOffset, (uint8*)&entry, &entrySize);
  514. -   if (status != B_OK)
  515. -       return status;
  516. -   else if (entrySize != sizeof(entry)) {
  517. -       // Weird error, try to skip it
  518. -       return GetNext(childOffset);
  519. -   }
  520. -  
  521. +
  522. +   CachedBlock cached(fVolume);
  523. +   const uint8* block = cached.SetTo(fBlockNum);
  524. +   if (block == NULL)
  525. +       return B_IO_ERROR;
  526. +
  527. +   HTreeEntry* entry = &((HTreeEntry*)block)[fCurrentEntry];
  528. +
  529.     if (!firstEntry)
  530. -       fHasCollision = (entry.Hash() & 1) == 1;
  531. +       fHasCollision = (entry[fCurrentEntry].Hash() & 1) == 1;
  532.    
  533. -   childOffset = entry.Block() * fBlockSize;
  534. -  
  535. -   return B_OK;
  536. +   TRACE("HTreeEntryIterator::GetNext(): next block: %lu\n",
  537. +       entry[fCurrentEntry].Block());
  538. +
  539. +   return fDirectory->FindBlock(entry[fCurrentEntry].Block() * fBlockSize,
  540. +       childBlock);
  541.  }
  542. Index: src/add-ons/kernel/file_systems/ext2/Inode.h
  543. ===================================================================
  544. --- src/add-ons/kernel/file_systems/ext2/Inode.h    (revision 37486)
  545. +++ src/add-ons/kernel/file_systems/ext2/Inode.h    (working copy)
  546. @@ -23,6 +23,8 @@
  547.  
  548.             rw_lock*    Lock() { return &fLock; }
  549.  
  550. +           status_t    WriteBack(Transaction& transaction);
  551. +
  552.             bool        IsDirectory() const
  553.                             { return S_ISDIR(Mode()); }
  554.             bool        IsFile() const
  555. @@ -32,16 +34,16 @@
  556.  
  557.             status_t    CheckPermissions(int accessMode) const;
  558.  
  559. -           mode_t      Mode() const { return fNode->Mode(); }
  560. -           int32       Flags() const { return fNode->Flags(); }
  561. +           mode_t      Mode() const { return fNode.Mode(); }
  562. +           int32       Flags() const { return fNode.Flags(); }
  563.  
  564. -           off_t       Size() const { return fNode->Size(); }
  565. +           off_t       Size() const { return fNode.Size(); }
  566.             time_t      ModificationTime() const
  567. -                           { return fNode->ModificationTime(); }
  568. +                           { return fNode.ModificationTime(); }
  569.             time_t      CreationTime() const
  570. -                           { return fNode->CreationTime(); }
  571. +                           { return fNode.CreationTime(); }
  572.             time_t      AccessTime() const
  573. -                           { return fNode->AccessTime(); }
  574. +                           { return fNode.AccessTime(); }
  575.  
  576.             //::Volume* _Volume() const { return fVolume; }
  577.             Volume*     GetVolume() const { return fVolume; }
  578. @@ -52,10 +54,19 @@
  579.             status_t    AttributeBlockReadAt(off_t pos, uint8 *buffer,
  580.                             size_t *length);
  581.  
  582. -           ext2_inode& Node() { return *fNode; }
  583. +           ext2_inode& Node() { return fNode; }
  584.  
  585. +   static  status_t    Create(Transaction& transaction, Inode* parent,
  586. +                           const char* name, int32 mode, int openMode,
  587. +                           uint32 type, bool* _created = NULL,
  588. +                           ino_t* _id = NULL, Inode** _inode = NULL,
  589. +                           fs_vnode_ops* vnodeOps = NULL,
  590. +                           uint32 publishFlags = 0);
  591. +
  592.             void*       FileCache() const { return fCache; }
  593.             void*       Map() const { return fMap; }
  594. +           status_t    DisableFileCache();
  595. +           bool        IsFileCacheDisabled() const { return !fCached; }
  596.  
  597.  private:
  598.                         Inode(const Inode&);
  599. @@ -63,13 +74,18 @@
  600.                             // no implementation
  601.  
  602.  private:
  603. -   rw_lock             fLock;
  604. -   ::Volume*           fVolume;
  605. -   ino_t               fID;
  606. -   void*               fCache;
  607. -   void*               fMap;
  608. -   ext2_inode*         fNode;
  609. -   ext2_xattr_header*  fAttributesBlock;
  610. +           rw_lock     fLock;
  611. +           ::Volume*   fVolume;
  612. +           ino_t       fID;
  613. +           void*       fCache;
  614. +           void*       fMap;
  615. +           bool        fCached;
  616. +           ext2_inode  fNode;
  617. +           uint32      fNodeSize;
  618. +               // Inodes have a varible size, but the important
  619. +               // information is always the same size (except in ext4)
  620. +           ext2_xattr_header* fAttributesBlock;
  621. +           status_t    fInitStatus;
  622.  };
  623.  
  624.  #endif // INODE_H
  625. Index: src/add-ons/kernel/file_systems/ext2/Volume.cpp
  626. ===================================================================
  627. --- src/add-ons/kernel/file_systems/ext2/Volume.cpp (revision 37486)
  628. +++ src/add-ons/kernel/file_systems/ext2/Volume.cpp (working copy)
  629. @@ -20,7 +20,10 @@
  630.  
  631.  #include <util/AutoLock.h>
  632.  
  633. +#include "CachedBlock.h"
  634.  #include "Inode.h"
  635. +#include "InodeJournal.h"
  636. +#include "NoJournal.h"
  637.  
  638.  
  639.  //#define TRACE_EXT2
  640. @@ -199,7 +202,7 @@
  641.     // TODO: check some more values!
  642.     if (Magic() != (uint32)EXT2_SUPER_BLOCK_MAGIC)
  643.         return false;
  644. -
  645. +  
  646.     return true;
  647.  }
  648.  
  649. @@ -210,6 +213,9 @@
  650.  Volume::Volume(fs_volume* volume)
  651.     :
  652.     fFSVolume(volume),
  653. +   fBlockAllocator(this),
  654. +   fInodeAllocator(this),
  655. +   fJournalInode(NULL),
  656.     fFlags(0),
  657.     fGroupBlocks(NULL),
  658.     fRootNode(NULL)
  659. @@ -220,6 +226,7 @@
  660.  
  661.  Volume::~Volume()
  662.  {
  663. +   TRACE("Volume destructor.\n");
  664.     if (fGroupBlocks != NULL) {
  665.         uint32 blockCount = (fNumGroups + fGroupsPerBlock - 1)
  666.             / fGroupsPerBlock;
  667. @@ -252,7 +259,7 @@
  668.  status_t
  669.  Volume::Mount(const char* deviceName, uint32 flags)
  670.  {
  671. -   flags |= B_MOUNT_READ_ONLY;
  672. +   // flags |= B_MOUNT_READ_ONLY;
  673.         // we only support read-only for now
  674.  
  675.     DeviceOpener opener(deviceName, (flags & B_MOUNT_READ_ONLY) != 0
  676. @@ -278,10 +285,17 @@
  677.     fBlockSize = 1UL << fSuperBlock.BlockShift();
  678.     fFirstDataBlock = fSuperBlock.FirstDataBlock();
  679.  
  680. +   fFreeBlocks = fSuperBlock.FreeBlocks();
  681. +   fFreeInodes = fSuperBlock.FreeInodes();
  682. +
  683. +   uint32 numBlocks = fSuperBlock.NumBlocks();
  684. +   uint32 blocksPerGroup = fSuperBlock.BlocksPerGroup();
  685. +   fNumGroups = numBlocks / blocksPerGroup;
  686. +   if (numBlocks % blocksPerGroup != 0)
  687. +       fNumGroups++;
  688. +
  689. +   fGroupsPerBlock = fBlockSize / sizeof(ext2_block_group);
  690.     fNumInodes = fSuperBlock.NumInodes();
  691. -   fNumGroups = (fSuperBlock.NumBlocks() - fFirstDataBlock - 1)
  692. -       / fSuperBlock.BlocksPerGroup() + 1;
  693. -   fGroupsPerBlock = fBlockSize / sizeof(ext2_block_group);
  694.  
  695.     TRACE("block size %ld, num groups %ld, groups per block %ld, first %lu\n",
  696.         fBlockSize, fNumGroups, fGroupsPerBlock, fFirstDataBlock);
  697. @@ -309,7 +323,50 @@
  698.     fBlockCache = opener.InitCache(NumBlocks(), fBlockSize);
  699.     if (fBlockCache == NULL)
  700.         return B_ERROR;
  701. +  
  702. +   TRACE("Volume::Mount(): Initialized block cache: %p\n", fBlockCache);
  703.  
  704. +   // initialize journal
  705. +   if ((fSuperBlock.CompatibleFeatures() & EXT2_FEATURE_HAS_JOURNAL) != 0) {
  706. +       // TODO: There should be a mount option to ignore the existent journal
  707. +       if (fSuperBlock.JournalInode() != 0) {
  708. +           fJournalInode = new(std::nothrow) Inode(this,
  709. +               fSuperBlock.JournalInode());
  710. +
  711. +           if (fJournalInode == NULL)
  712. +               return B_NO_MEMORY;
  713. +
  714. +           TRACE("Opening an on disk, inode mapped journal.\n");
  715. +           fJournal = new(std::nothrow) InodeJournal(fJournalInode);
  716. +       } else {
  717. +           // TODO: external journal
  718. +           TRACE("Can not open an external journal.\n");
  719. +           return B_NOT_SUPPORTED;
  720. +       }
  721. +   } else {
  722. +       TRACE("Opening a fake journal (NoJournal).\n");
  723. +       fJournal = new(std::nothrow) NoJournal(this);
  724. +   }
  725. +
  726. +   if (fJournal == NULL) {
  727. +       TRACE("No memory to create the journal\n");
  728. +       return B_NO_MEMORY;
  729. +   }
  730. +
  731. +   status = fJournal->InitCheck();
  732. +   if (status != B_OK)
  733. +       return status;
  734. +
  735. +   // TODO: Only recover if asked to
  736. +   status = fJournal->Recover();
  737. +   if (status != B_OK)
  738. +       return status;
  739. +
  740. +   status = fJournal->StartLog();
  741. +   if (status != B_OK)
  742. +       return status;
  743. +
  744. +   // ready
  745.     status = get_vnode(fFSVolume, EXT2_ROOT_NODE, (void**)&fRootNode);
  746.     if (status != B_OK) {
  747.         TRACE("could not create root node: get_vnode() failed!\n");
  748. @@ -342,10 +399,19 @@
  749.  status_t
  750.  Volume::Unmount()
  751.  {
  752. +   TRACE("Volume::Unmount()\n");
  753. +
  754. +   delete fJournal;
  755. +   delete fJournalInode;
  756. +
  757. +   TRACE("Volume::Unmount(): Putting root node\n");
  758.     put_vnode(fFSVolume, RootNode()->ID());
  759. +   TRACE("Volume::Unmount(): Deleting the block cache\n");
  760.     block_cache_delete(fBlockCache, !IsReadOnly());
  761. +   TRACE("Volume::Unmount(): Closing device\n");
  762.     close(fDevice);
  763.  
  764. +   TRACE("Volume::Unmount(): Done\n");
  765.     return B_OK;
  766.  }
  767.  
  768. @@ -443,6 +509,98 @@
  769.  }
  770.  
  771.  
  772. +status_t
  773. +Volume::AllocateInode(Transaction& transaction, uint32 preferredBlockGroup,
  774. +   ino_t& id)
  775. +{
  776. +   if ((fFlags & VOLUME_READ_ONLY) != 0)
  777. +       return B_READ_ONLY_DEVICE;
  778. +
  779. +   status_t status = fInodeAllocator.New(transaction, preferredBlockGroup, id);
  780. +   if (status == B_OK)
  781. +       fFreeInodes -= 1;
  782. +
  783. +   return status;
  784. +}
  785. +
  786. +
  787. +status_t
  788. +Volume::AllocateBlocks(Transaction& transaction, uint32 blockGroup,
  789. +   uint32 minimum, uint32 maximum, uint32& start, uint32& length)
  790. +{
  791. +   if ((fFlags & VOLUME_READ_ONLY) != 0)
  792. +       return B_READ_ONLY_DEVICE;
  793. +
  794. +   status_t status = fBlockAllocator.AllocateBlocks(transaction, blockGroup,
  795. +       minimum, maximum, start, length);
  796. +   if (status != B_OK)
  797. +       return status;
  798. +
  799. +   fFreeBlocks -= length;
  800. +
  801. +   return WriteSuperBlock(transaction);
  802. +}
  803. +
  804. +
  805. +status_t
  806. +Volume::LoadSuperBlock()
  807. +{
  808. +   CachedBlock cached(this);
  809. +   const uint8* block = cached.SetTo(fFirstDataBlock);
  810. +
  811. +   if (block == NULL)
  812. +       return B_IO_ERROR;
  813. +
  814. +   if (fFirstDataBlock == 0)
  815. +       memcpy(&fSuperBlock, block + 1024, sizeof(fSuperBlock));
  816. +   else
  817. +       memcpy(&fSuperBlock, block, sizeof(fSuperBlock));
  818. +
  819. +   fFreeBlocks = fSuperBlock.FreeBlocks();
  820. +   fFreeInodes = fSuperBlock.FreeInodes();
  821. +
  822. +   return B_OK;
  823. +}
  824. +
  825. +
  826. +status_t
  827. +Volume::WriteSuperBlock(Transaction& transaction)
  828. +{
  829. +   fSuperBlock.SetFreeBlocks(fFreeBlocks);
  830. +   fSuperBlock.SetFreeInodes(fFreeInodes);
  831. +   // TODO: Rest of fields that can be modified
  832. +
  833. +   CachedBlock cached(this);
  834. +   uint8* block = cached.SetToWritable(transaction, fFirstDataBlock);
  835. +
  836. +   if (block == NULL)
  837. +       return B_IO_ERROR;
  838. +
  839. +   if (fFirstDataBlock == 0)
  840. +       memcpy(block + 1024, &fSuperBlock, sizeof(fSuperBlock));
  841. +   else
  842. +       memcpy(block, &fSuperBlock, sizeof(fSuperBlock));
  843. +
  844. +   return B_OK;
  845. +}
  846. +
  847. +
  848. +status_t
  849. +Volume::FlushDevice()
  850. +{
  851. +   TRACE("Volume::FlushDevice()\n");
  852. +   return block_cache_sync(fBlockCache);
  853. +}
  854. +
  855. +
  856. +status_t
  857. +Volume::Sync()
  858. +{
  859. +   TRACE("Volume::Sync()\n");
  860. +   return fJournal->FlushLogAndBlocks();
  861. +}
  862. +
  863. +
  864.  // #pragma mark - Disk scanning and initialization
  865.  
  866.  
  867. @@ -460,3 +618,18 @@
  868.         ? B_OK : B_NOT_SUPPORTED;
  869.  }
  870.  
  871. +
  872. +void
  873. +Volume::TransactionDone(bool success)
  874. +{
  875. +   status_t status = LoadSuperBlock();
  876. +   if (status != B_OK)
  877. +       panic("Failed to relead ext2 superblock.\n");
  878. +}
  879. +
  880. +
  881. +void
  882. +Volume::RemovedFromTransaction()
  883. +{
  884. +   // TODO: Does it make a difference?
  885. +}
  886. Index: src/add-ons/kernel/file_systems/ext2/Journal.cpp
  887. ===================================================================
  888. --- src/add-ons/kernel/file_systems/ext2/Journal.cpp    (revision 0)
  889. +++ src/add-ons/kernel/file_systems/ext2/Journal.cpp    (revision 0)
  890. @@ -0,0 +1,1058 @@
  891. +/*
  892. + * Copyright 2001-2010, Haiku Inc. All rights reserved.
  893. + * This file may be used under the terms of the MIT License.
  894. + *
  895. + * Authors:
  896. + *     Janito V. Ferreira Filho
  897. + */
  898. +
  899. +#include "Journal.h"
  900. +
  901. +#include <new>
  902. +#include <string.h>
  903. +#include <unistd.h>
  904. +
  905. +#include <fs_cache.h>
  906. +
  907. +#include "CachedBlock.h"
  908. +#include "HashRevokeManager.h"
  909. +
  910. +
  911. +//#define TRACE_EXT2
  912. +#ifdef TRACE_EXT2
  913. +#  define TRACE(x...) dprintf("\33[34mext2:\33[0m " x)
  914. +#else
  915. +#  define TRACE(x...) ;
  916. +#endif
  917. +
  918. +
  919. +class LogEntry : public DoublyLinkedListLinkImpl<LogEntry> {
  920. +public:
  921. +                           LogEntry(Journal* journal, uint32 logStart,
  922. +                               uint32 length);
  923. +                           ~LogEntry();
  924. +
  925. +           uint32          Start() const { return fStart; }
  926. +           uint32          CommitID() const { return fCommitID; }
  927. +
  928. +           Journal*        GetJournal() { return fJournal; }
  929. +
  930. +private:
  931. +           Journal*        fJournal;
  932. +           uint32          fStart;
  933. +           uint32          fCommitID;
  934. +};
  935. +
  936. +
  937. +LogEntry::LogEntry(Journal* journal, uint32 logStart, uint32 commitID)
  938. +   :
  939. +   fJournal(journal),
  940. +   fStart(logStart),
  941. +   fCommitID(commitID)
  942. +{
  943. +}
  944. +
  945. +
  946. +LogEntry::~LogEntry()
  947. +{
  948. +}
  949. +
  950. +
  951. +/*void
  952. +add_to_iovec(iovec* vecs, int32& index, int32 max, const void* address,
  953. +   size_t size)
  954. +{
  955. +   if (index > 0 && (addr_t)vecs[index - 1].iov_base
  956. +       + vecs[index - 1].iov_len == (addr_t)address) {
  957. +       // the iovec can be combined with the previous one
  958. +       vecs[index - 1].iov_len += size;
  959. +       return;
  960. +   }
  961. +
  962. +   if (index == max)
  963. +       panic("no more space for iovecs!");
  964. +  
  965. +   // start a new iovec
  966. +   vecs[index].iov_base = const_cast<void*>(address);
  967. +   vecs[index].iov_len = size;
  968. +   index++;
  969. +}*/
  970. +
  971. +
  972. +void
  973. +JournalHeader::MakeDescriptor(uint32 sequence)
  974. +{
  975. +   this->magic = B_HOST_TO_BENDIAN_INT32(JOURNAL_MAGIC);
  976. +   this->sequence = B_HOST_TO_BENDIAN_INT32(sequence);
  977. +   this->block_type = B_HOST_TO_BENDIAN_INT32(JOURNAL_DESCRIPTOR_BLOCK);
  978. +}
  979. +
  980. +
  981. +void
  982. +JournalHeader::MakeCommit(uint32 sequence)
  983. +{
  984. +   this->magic = B_HOST_TO_BENDIAN_INT32(JOURNAL_MAGIC);
  985. +   this->sequence = B_HOST_TO_BENDIAN_INT32(sequence);
  986. +   this->block_type = B_HOST_TO_BENDIAN_INT32(JOURNAL_COMMIT_BLOCK);
  987. +}
  988. +
  989. +
  990. +Journal::Journal(Volume* fsVolume, Volume* jVolume)
  991. +   :
  992. +   fJournalVolume(jVolume),
  993. +   fJournalBlockCache(jVolume->BlockCache()),
  994. +   fFilesystemVolume(fsVolume),
  995. +   fFilesystemBlockCache(fsVolume->BlockCache()),
  996. +   fRevokeManager(NULL),
  997. +   fInitStatus(B_OK),
  998. +   fBlockSize(sizeof(JournalSuperBlock)),
  999. +   fFirstCommitID(0),
  1000. +   fFirstCacheCommitID(0),
  1001. +   fFirstLogBlock(0),
  1002. +   fLogSize(0),
  1003. +   fVersion(0),
  1004. +   fLogStart(0),
  1005. +   fLogEnd(0),
  1006. +   fFreeBlocks(0),
  1007. +   fMaxTransactionSize(0),
  1008. +   fCurrentCommitID(0),
  1009. +   fHasSubTransaction(false),
  1010. +   fSeparateSubTransactions(false),
  1011. +   fUnwrittenTransactions(0),
  1012. +   fTransactionID(0)
  1013. +{
  1014. +   recursive_lock_init(&fLock, "ext2 journal");
  1015. +   mutex_init(&fLogEntriesLock, "ext2 journal log entries");
  1016. +
  1017. +   fRevokeManager = new(std::nothrow) HashRevokeManager;
  1018. +
  1019. +   if (fRevokeManager == NULL)
  1020. +       fInitStatus = B_NO_MEMORY;
  1021. +   else
  1022. +       fInitStatus = _LoadSuperBlock();
  1023. +}
  1024. +
  1025. +
  1026. +Journal::Journal()
  1027. +   :
  1028. +   fJournalVolume(NULL),
  1029. +   fJournalBlockCache(NULL),
  1030. +   fFilesystemVolume(NULL),
  1031. +   fFilesystemBlockCache(NULL),
  1032. +   fRevokeManager(NULL),
  1033. +   fInitStatus(B_OK),
  1034. +   fBlockSize(sizeof(JournalSuperBlock)),
  1035. +   fFirstCommitID(0),
  1036. +   fFirstCacheCommitID(0),
  1037. +   fFirstLogBlock(0),
  1038. +   fLogSize(0),
  1039. +   fVersion(0),
  1040. +   fLogStart(0),
  1041. +   fLogEnd(0),
  1042. +   fFreeBlocks(0),
  1043. +   fMaxTransactionSize(0),
  1044. +   fCurrentCommitID(0),
  1045. +   fHasSubTransaction(false),
  1046. +   fSeparateSubTransactions(false),
  1047. +   fUnwrittenTransactions(0),
  1048. +   fTransactionID(0)
  1049. +{
  1050. +   recursive_lock_init(&fLock, "ext2 journal");
  1051. +   mutex_init(&fLogEntriesLock, "ext2 journal log entries");
  1052. +}
  1053. +
  1054. +
  1055. +Journal::~Journal()
  1056. +{
  1057. +   TRACE("Journal destructor.\n");
  1058. +
  1059. +   FlushLogAndBlocks();
  1060. +
  1061. +   delete fRevokeManager;
  1062. +
  1063. +   recursive_lock_destroy(&fLock);
  1064. +   mutex_destroy(&fLogEntriesLock);
  1065. +}
  1066. +
  1067. +
  1068. +status_t
  1069. +Journal::InitCheck()
  1070. +{
  1071. +   return fInitStatus;
  1072. +}
  1073. +
  1074. +
  1075. +/*virtual*/ status_t
  1076. +Journal::StartLog()
  1077. +{
  1078. +   fLogStart = fFirstLogBlock;
  1079. +   fLogEnd = fFirstLogBlock;
  1080. +   fFreeBlocks = 0;
  1081. +
  1082. +   fCurrentCommitID = fFirstCommitID;
  1083. +   //fNextCommitID = fFirstCommitID;
  1084. +
  1085. +   return _SaveSuperBlock();
  1086. +}
  1087. +
  1088. +
  1089. +status_t
  1090. +Journal::RestartLog()
  1091. +{
  1092. +   fFirstCommitID = 1;
  1093. +
  1094. +   return B_OK;
  1095. +}
  1096. +
  1097. +
  1098. +status_t
  1099. +Journal::Lock(Transaction* owner, bool separateSubTransactions)
  1100. +{
  1101. +   status_t status = recursive_lock_lock(&fLock);
  1102. +   if (status != B_OK)
  1103. +       return status;
  1104. +
  1105. +   if (!fSeparateSubTransactions && recursive_lock_get_recursion(&fLock) > 1) {
  1106. +       // reuse current transaction
  1107. +       return B_OK;
  1108. +   }
  1109. +
  1110. +   if(separateSubTransactions)
  1111. +       fSeparateSubTransactions = true;
  1112. +
  1113. +   if (owner != NULL)
  1114. +       owner->SetParent(fOwner);
  1115. +
  1116. +   fOwner = owner;
  1117. +
  1118. +   if (fOwner != NULL) {
  1119. +       if (fUnwrittenTransactions > 0) {
  1120. +           // start a sub transaction
  1121. +           cache_start_sub_transaction(fFilesystemBlockCache, fTransactionID);
  1122. +           fHasSubTransaction = true;
  1123. +       } else
  1124. +           fTransactionID = cache_start_transaction(fFilesystemBlockCache);
  1125. +
  1126. +       if (fTransactionID < B_OK) {
  1127. +           recursive_lock_unlock(&fLock);
  1128. +           return fTransactionID;
  1129. +       }
  1130. +
  1131. +       cache_add_transaction_listener(fFilesystemBlockCache, fTransactionID,
  1132. +           TRANSACTION_IDLE, _TransactionIdle, this);
  1133. +   }
  1134. +
  1135. +   return B_OK;
  1136. +}
  1137. +
  1138. +
  1139. +status_t
  1140. +Journal::Unlock(Transaction* owner, bool success)
  1141. +{
  1142. +   if (fSeparateSubTransactions
  1143. +       || recursive_lock_get_recursion(&fLock) == 1) {
  1144. +       // we only end the transaction if we unlock it
  1145. +       if (owner != NULL) {
  1146. +           status_t status = _TransactionDone(success);
  1147. +           if (status != B_OK)
  1148. +               return status;
  1149. +
  1150. +           bool separateSubTransactions = fSeparateSubTransactions;
  1151. +           fSeparateSubTransactions = true;
  1152. +           owner->NotifyListeners(success);
  1153. +           fSeparateSubTransactions = separateSubTransactions;
  1154. +
  1155. +           fOwner = owner->Parent();
  1156. +       } else
  1157. +           fOwner = NULL;
  1158. +
  1159. +       if (fSeparateSubTransactions
  1160. +           && recursive_lock_get_recursion(&fLock) == 1)
  1161. +           fSeparateSubTransactions = false;
  1162. +   } else
  1163. +       owner->MoveListenersTo(fOwner);
  1164. +
  1165. +   recursive_lock_unlock(&fLock);
  1166. +   return B_OK;
  1167. +}
  1168. +
  1169. +
  1170. +status_t
  1171. +Journal::MapBlock(uint32 logical, uint32& physical)
  1172. +{
  1173. +   physical = logical;
  1174. +  
  1175. +   return B_OK;
  1176. +}
  1177. +
  1178. +
  1179. +inline uint32
  1180. +Journal::FreeLogBlocks() const
  1181. +{
  1182. +   return fLogStart <= fLogEnd
  1183. +       ? fLogSize - fLogEnd + fLogStart
  1184. +       : fLogStart - fLogEnd;
  1185. +}
  1186. +
  1187. +
  1188. +status_t
  1189. +Journal::FlushLogAndBlocks()
  1190. +{
  1191. +   return _FlushLog(true, true);
  1192. +}
  1193. +
  1194. +
  1195. +int32
  1196. +Journal::TransactionID() const
  1197. +{
  1198. +   return fTransactionID;
  1199. +}
  1200. +
  1201. +
  1202. +status_t
  1203. +Journal::_WriteTransactionToLog()
  1204. +{
  1205. +   TRACE("Journal::_WriteTransactionToLog()\n");
  1206. +   // Transaction enters the Flush state
  1207. +   bool detached = false;
  1208. +   size_t size = _FullTransactionSize();
  1209. +
  1210. +   if (size > fLogSize) {
  1211. +       TRACE("Journal::_WriteTransactionToLog(): not enough free space "
  1212. +           "for the transaction. Attempting to free some space.\n");
  1213. +       size = _MainTransactionSize();
  1214. +
  1215. +       if(fHasSubTransaction && size < fMaxTransactionSize)
  1216. +           detached = true;
  1217. +       else {
  1218. +           // Error: transaction can't fit in log
  1219. +           panic("transaction too large (size: %d, max size: %d)\n",
  1220. +               (int)_MainTransactionSize(), (int)fLogSize);
  1221. +           return B_BUFFER_OVERFLOW;
  1222. +       }
  1223. +   }
  1224. +
  1225. +   if (size > FreeLogBlocks()) {
  1226. +       cache_sync_transaction(fFilesystemBlockCache, fTransactionID);
  1227. +
  1228. +       if (size > FreeLogBlocks()) {
  1229. +           panic("Transaction fits, but sync didn't result in enough"
  1230. +               "free space.\n\tGot %ld when at least %ld was expected.",
  1231. +               (long)FreeLogBlocks(), (long)size);
  1232. +       }
  1233. +   }
  1234. +
  1235. +   fHasSubTransaction = false;
  1236. +
  1237. +   uint32 logBlock = fLogStart + 1;
  1238. +   uint32 physicalBlock;
  1239. +   status_t status = MapBlock(logBlock, physicalBlock);
  1240. +   if (status != B_OK)
  1241. +       return status;
  1242. +
  1243. +   off_t logOffset = physicalBlock * fBlockSize;
  1244. +   off_t blockNumber;
  1245. +   long cookie = 0;
  1246. +
  1247. +   JournalHeader* blockData = NULL;
  1248. +   JournalHeader* descriptorBlock =
  1249. +       (JournalHeader*)new(std::nothrow) uint8[fBlockSize];
  1250. +   descriptorBlock->MakeDescriptor(fCurrentCommitID);
  1251. +
  1252. +   JournalBlockTag* tag = (JournalBlockTag*)descriptorBlock->data;
  1253. +   int32 blockCount = 0;
  1254. +
  1255. +   uint8* escapedData = NULL;
  1256. +   void* finalData = NULL;
  1257. +
  1258. +   // TODO: use iovecs?
  1259. +   /*int maxVecs = detached ? _MainTransactionSize() : _FullTransactionSize();
  1260. +
  1261. +   iovec* vecs = new(std::nothrow) iovecs[maxVecs];
  1262. +   if (vecs == NULL)
  1263. +       return B_NO_MEMORY;
  1264. +
  1265. +   int32 index = 0;*/
  1266. +
  1267. +   while (cache_next_block_in_transaction(fFilesystemBlockCache,
  1268. +           fTransactionID, detached, &cookie, &blockNumber,
  1269. +           &(void*)blockData, NULL) == B_OK) {
  1270. +       tag->SetBlockNumber(blockNumber);
  1271. +       tag->SetFlags(0);
  1272. +
  1273. +       if (blockData == NULL) {
  1274. +           panic("Got a NULL pointer while iterating through transaction "
  1275. +               "blocks.\n");
  1276. +           return B_ERROR;
  1277. +       }
  1278. +
  1279. +       if (blockData->CheckMagic()) {
  1280. +           // The journaled block starts with the magic value
  1281. +           // We must remove it to prevent confusion
  1282. +           tag->SetEscapedFlag();
  1283. +
  1284. +           if (escapedData == NULL) {
  1285. +               escapedData = new(std::nothrow) uint8[fBlockSize];
  1286. +               ((int32*)escapedData)[0] = 0; // Remove magic
  1287. +           }
  1288. +
  1289. +           memcpy(escapedData + 4, blockData->data, fBlockSize - 4);
  1290. +           finalData = escapedData;
  1291. +       } else
  1292. +           finalData = (void*)blockData;
  1293. +
  1294. +       size_t written = write_pos(fJournalVolume->Device(), logOffset,
  1295. +           finalData, fBlockSize);
  1296. +       if (written != fBlockSize) {
  1297. +           TRACE("Failed to write journal block.\n");
  1298. +
  1299. +           delete [] descriptorBlock;
  1300. +          
  1301. +           if (escapedData != NULL)
  1302. +               delete [] escapedData;
  1303. +
  1304. +           return B_IO_ERROR;
  1305. +       }
  1306. +
  1307. +       logBlock = _WrapAroundLog(++logBlock);
  1308. +       status = MapBlock(logBlock, physicalBlock);
  1309. +       if (status != B_OK)
  1310. +           return status;
  1311. +
  1312. +       logOffset = physicalBlock & fBlockSize;
  1313. +
  1314. +       tag++;
  1315. +       blockCount++;
  1316. +   }
  1317. +
  1318. +   // Write descriptor block
  1319. +   --tag;
  1320. +   tag->SetLastTagFlag();
  1321. +  
  1322. +   status = MapBlock(fLogStart, physicalBlock);
  1323. +   if (status != B_OK)
  1324. +       return status;
  1325. +
  1326. +   off_t startOffset = physicalBlock * fBlockSize;
  1327. +
  1328. +   size_t written = write_pos(fJournalVolume->Device(), startOffset,
  1329. +       descriptorBlock, fBlockSize);
  1330. +   if (written != fBlockSize) {
  1331. +       TRACE("Failed to write journal descriptor block.\n");
  1332. +
  1333. +       delete [] descriptorBlock;
  1334. +      
  1335. +       if (escapedData != NULL)
  1336. +           delete [] escapedData;
  1337. +
  1338. +       return B_IO_ERROR;
  1339. +   }
  1340. +  
  1341. +   // Transaction will enter the Commit state
  1342. +   JournalHeader* commitBlock = descriptorBlock;
  1343. +       // Reuse buffer
  1344. +   commitBlock->MakeCommit(fCurrentCommitID);
  1345. +   memset(commitBlock->data, 0, fBlockSize - sizeof(JournalHeader));
  1346. +       // TODO: This probably isn't necessary
  1347. +
  1348. +   written = write_pos(fJournalVolume->Device(), logOffset, commitBlock,
  1349. +       fBlockSize);
  1350. +   if (written != fBlockSize) {
  1351. +       TRACE("Failed to write journal commit block.\n");
  1352. +
  1353. +       delete [] commitBlock;
  1354. +           // Which is aslo descriptorBlock
  1355. +      
  1356. +       if (escapedData != NULL)
  1357. +           delete [] escapedData;
  1358. +
  1359. +       return B_IO_ERROR;
  1360. +   }
  1361. +  
  1362. +   fLogEnd = _WrapAroundLog(fLogEnd + blockCount);
  1363. +
  1364. +   status = _SaveSuperBlock();
  1365. +
  1366. +   delete [] commitBlock;
  1367. +       // Which is aslo descriptorBlock
  1368. +  
  1369. +   if (escapedData != NULL)
  1370. +       delete [] escapedData;
  1371. +
  1372. +   // Transaction will enter Finished state
  1373. +   blockCount += 2;    // Include descriptor and commit blocks
  1374. +   LogEntry *logEntry = new LogEntry(this, fLogEnd, fCurrentCommitID++);
  1375. +   if (logEntry == NULL) {
  1376. +       panic("no memory to allocate log entries!");
  1377. +       return B_NO_MEMORY;
  1378. +   }
  1379. +
  1380. +   mutex_lock(&fLogEntriesLock);
  1381. +   fLogEntries.Add(logEntry);
  1382. +   mutex_unlock(&fLogEntriesLock);
  1383. +
  1384. +   if (detached) {
  1385. +       fTransactionID = cache_detach_sub_transaction(fFilesystemBlockCache,
  1386. +           fTransactionID, _TransactionWritten, logEntry);
  1387. +       fUnwrittenTransactions = 1;
  1388. +
  1389. +       if (status == B_OK && _FullTransactionSize() > fLogSize) {
  1390. +           // If the transaction is too large after writing, there is no way to
  1391. +           // recover, so let this transaction fail.
  1392. +           dprintf("transaction too large (%d blocks, log size %d)!\n",
  1393. +               (int)_FullTransactionSize(), (int)fLogSize);
  1394. +           return B_BUFFER_OVERFLOW;
  1395. +       }
  1396. +   } else {
  1397. +       cache_end_transaction(fFilesystemBlockCache, fTransactionID,
  1398. +           _TransactionWritten, logEntry);
  1399. +       fUnwrittenTransactions = 0;
  1400. +   }
  1401. +
  1402. +   return B_OK;
  1403. +}
  1404. +
  1405. +
  1406. +status_t
  1407. +Journal::_SaveSuperBlock()
  1408. +{
  1409. +   uint32 physicalBlock;
  1410. +   status_t status = MapBlock(0, physicalBlock);
  1411. +   if (status != B_OK)
  1412. +       return status;
  1413. +
  1414. +   off_t superblockPos = physicalBlock * fBlockSize;
  1415. +
  1416. +   JournalSuperBlock superblock;
  1417. +   size_t bytesRead = read_pos(fJournalVolume->Device(), superblockPos,
  1418. +       &superblock, sizeof(superblock));
  1419. +
  1420. +   if (bytesRead != sizeof(superblock))
  1421. +       return B_IO_ERROR;
  1422. +
  1423. +   superblock.SetFirstCommitID(fFirstCommitID);
  1424. +   superblock.SetLogStart(fLogStart);
  1425. +  
  1426. +   size_t bytesWritten = write_pos(fJournalVolume->Device(), superblockPos,
  1427. +       &superblock, sizeof(superblock));
  1428. +
  1429. +   if (bytesWritten != sizeof(superblock))
  1430. +       return B_IO_ERROR;
  1431. +
  1432. +   return B_OK;
  1433. +}
  1434. +
  1435. +
  1436. +status_t
  1437. +Journal::_LoadSuperBlock()
  1438. +{
  1439. +   uint32 superblockPos;
  1440. +
  1441. +   status_t status = MapBlock(0, superblockPos);
  1442. +   if (status != B_OK)
  1443. +       return status;
  1444. +  
  1445. +   JournalSuperBlock superblock;
  1446. +   size_t bytesRead = read_pos(fJournalVolume->Device(), superblockPos,
  1447. +       &superblock, sizeof(superblock));
  1448. +
  1449. +   if (bytesRead != sizeof(superblock))
  1450. +       return B_IO_ERROR;
  1451. +
  1452. +   if (superblock.header.Magic() != JOURNAL_MAGIC)
  1453. +       return B_BAD_VALUE;
  1454. +
  1455. +   if (superblock.header.BlockType() == JOURNAL_SUPERBLOCK_V1)
  1456. +       fVersion = 1;
  1457. +   else if (superblock.header.BlockType() == JOURNAL_SUPERBLOCK_V2)
  1458. +       fVersion = 2;
  1459. +   else
  1460. +       return B_BAD_VALUE;
  1461. +
  1462. +   if (fVersion >= 2) {
  1463. +       status = _CheckFeatures(&superblock);
  1464. +
  1465. +       if (status != B_OK)
  1466. +           return status;
  1467. +   }
  1468. +
  1469. +   fBlockSize = superblock.BlockSize();
  1470. +   fFirstCommitID = superblock.FirstCommitID();
  1471. +   fFirstLogBlock = superblock.FirstLogBlock();
  1472. +   fLogStart = superblock.LogStart();
  1473. +   fLogSize = superblock.NumBlocks();
  1474. +   fMaxTransactionSize = superblock.MaxTransactionData();
  1475. +   //fFirstCacheCommitID = fFirstCommitID - fTransactionID /*+ 1*/;
  1476. +
  1477. +   return B_OK;
  1478. +}
  1479. +
  1480. +
  1481. +status_t
  1482. +Journal::_CheckFeatures(JournalSuperBlock* superblock)
  1483. +{
  1484. +   if ((superblock->ReadOnlyCompatibleFeatures()
  1485. +           & ~JOURNAL_KNOWN_READ_ONLY_COMPATIBLE_FEATURES) != 0
  1486. +       && (superblock->IncompatibleFeatures()
  1487. +           & ~JOURNAL_KNOWN_INCOMPATIBLE_FEATURES) != 0)
  1488. +       return B_NOT_SUPPORTED;
  1489. +
  1490. +   return B_OK;
  1491. +}
  1492. +
  1493. +
  1494. +uint32
  1495. +Journal::_CountTags(JournalHeader* descriptorBlock)
  1496. +{
  1497. +   uint32 count = 0;
  1498. +
  1499. +   JournalBlockTag* tags = (JournalBlockTag*)descriptorBlock->data;
  1500. +       // Skip the header
  1501. +   JournalBlockTag* lastTag = (JournalBlockTag*)
  1502. +       (descriptorBlock + fBlockSize - sizeof(JournalBlockTag));
  1503. +
  1504. +   while (tags < lastTag && (tags->Flags() & JOURNAL_FLAG_LAST_TAG) == 0) {
  1505. +       if ((tags->Flags() & JOURNAL_FLAG_SAME_UUID) == 0) {
  1506. +           // sizeof(UUID) = 16 = 2*sizeof(JournalBlockTag)
  1507. +           tags += 2;  // Skip new UUID
  1508. +       }
  1509. +
  1510. +       tags++; // Go to next tag
  1511. +       count++;
  1512. +   }
  1513. +
  1514. +   return count;
  1515. +}
  1516. +
  1517. +
  1518. +/*virtual*/ status_t
  1519. +Journal::Recover()
  1520. +{
  1521. +   TRACE("Journal::Recover()\n");
  1522. +   if (fLogStart == 0) // Journal was cleanly unmounted
  1523. +       return B_OK;
  1524. +
  1525. +   TRACE("Journal::Recover(): Journal needs recovery\n");
  1526. +
  1527. +   uint32 lastCommitID;
  1528. +
  1529. +   status_t status = _RecoverPassScan(lastCommitID);
  1530. +   if (status != B_OK)
  1531. +       return status;
  1532. +  
  1533. +   status = _RecoverPassRevoke(lastCommitID);
  1534. +   if (status != B_OK)
  1535. +       return status;
  1536. +
  1537. +   return _RecoverPassReplay(lastCommitID);
  1538. +}
  1539. +
  1540. +
  1541. +// First pass: Find the end of the log
  1542. +status_t
  1543. +Journal::_RecoverPassScan(uint32& lastCommitID)
  1544. +{
  1545. +   TRACE("Journal Recover: 1st Pass: Scan\n");
  1546. +
  1547. +   CachedBlock cached(fJournalVolume);
  1548. +   JournalHeader* header;
  1549. +   uint32 nextCommitID = fFirstCommitID;
  1550. +   uint32 nextBlock = fLogStart;
  1551. +   uint32 nextBlockPos;
  1552. +
  1553. +   status_t status = MapBlock(nextBlock, nextBlockPos);
  1554. +   if (status != B_OK)
  1555. +       return status;
  1556. +
  1557. +   header = (JournalHeader*)cached.SetTo(nextBlockPos);
  1558. +
  1559. +   while (header->CheckMagic() && header->Sequence() == nextCommitID) {
  1560. +       uint32 blockType = header->BlockType();
  1561. +
  1562. +       if (blockType == JOURNAL_DESCRIPTOR_BLOCK)
  1563. +           nextBlock = _WrapAroundLog(nextBlock + _CountTags(header));
  1564. +       else if (blockType == JOURNAL_COMMIT_BLOCK)
  1565. +           nextCommitID++;
  1566. +       else if (blockType != JOURNAL_REVOKE_BLOCK) {
  1567. +               // TODO: Warn that we found an unrecognized block
  1568. +           break;
  1569. +       } // If blockType == JOURNAL_REVOKE_BLOCK we just skip it
  1570. +
  1571. +       nextBlock = _WrapAroundLog(nextBlock + 1);
  1572. +
  1573. +       status = MapBlock(nextBlock, nextBlockPos);
  1574. +       if (status != B_OK)
  1575. +           return status;
  1576. +
  1577. +       header = (JournalHeader*)cached.SetTo(nextBlockPos);
  1578. +   }
  1579. +
  1580. +   TRACE("Journal Recovery pass scan: Last detected transaction ID: %lu\n",
  1581. +       nextCommitID);
  1582. +
  1583. +   lastCommitID = nextCommitID;
  1584. +   return B_OK;
  1585. +}
  1586. +
  1587. +
  1588. +// Second pass: Collect all revoked blocks
  1589. +status_t
  1590. +Journal::_RecoverPassRevoke(uint32 lastCommitID)
  1591. +{
  1592. +   TRACE("Journal Recover: 2nd Pass: Revoke\n");
  1593. +
  1594. +   CachedBlock cached(fJournalVolume);
  1595. +   JournalHeader* header;
  1596. +   uint32 nextCommitID = fFirstCommitID;
  1597. +   uint32 nextBlock = fLogStart;
  1598. +   uint32 nextBlockPos;
  1599. +
  1600. +   status_t status = MapBlock(nextBlock, nextBlockPos);
  1601. +   if (status != B_OK)
  1602. +       return status;
  1603. +
  1604. +   header = (JournalHeader*)cached.SetTo(nextBlockPos);
  1605. +
  1606. +   while (nextCommitID < lastCommitID) {
  1607. +       if (!header->CheckMagic() || header->Sequence() != nextCommitID) {
  1608. +           // Somehow the log is different than the expexted
  1609. +           return B_ERROR;
  1610. +       }
  1611. +
  1612. +       uint32 blockType = header->BlockType();
  1613. +
  1614. +       if (blockType == JOURNAL_DESCRIPTOR_BLOCK)
  1615. +           nextBlock = _WrapAroundLog(nextBlock + _CountTags(header));
  1616. +       else if (blockType == JOURNAL_COMMIT_BLOCK)
  1617. +           nextCommitID++;
  1618. +       else if (blockType == JOURNAL_REVOKE_BLOCK) {
  1619. +           status = fRevokeManager->ScanRevokeBlock(
  1620. +               (JournalRevokeHeader*)header, nextCommitID);
  1621. +
  1622. +           if (status != B_OK)
  1623. +               return status;
  1624. +       } else {
  1625. +               // TODO: Warn that we found an unrecognized block
  1626. +           break;
  1627. +       }
  1628. +
  1629. +       nextBlock = _WrapAroundLog(nextBlock + 1);
  1630. +
  1631. +       status = MapBlock(nextBlock, nextBlockPos);
  1632. +       if (status != B_OK)
  1633. +           return status;
  1634. +
  1635. +       header = (JournalHeader*)cached.SetTo(nextBlockPos);
  1636. +   }
  1637. +
  1638. +   if (nextCommitID != lastCommitID) {
  1639. +       // Possibly because of some sort of IO error
  1640. +       return B_ERROR;
  1641. +   }
  1642. +
  1643. +   TRACE("Journal recovery pass revoke: Revoked blocks: %lu\n",
  1644. +       fRevokeManager->NumRevokes());
  1645. +
  1646. +   return B_OK;
  1647. +}
  1648. +
  1649. +
  1650. +// Third pass: Replay log
  1651. +status_t
  1652. +Journal::_RecoverPassReplay(uint32 lastCommitID)
  1653. +{
  1654. +   TRACE("Journal Recover: 3rd Pass: Replay\n");
  1655. +
  1656. +   uint32 nextCommitID = fFirstCommitID;
  1657. +   uint32 nextBlock = fLogStart;
  1658. +   uint32 nextBlockPos;
  1659. +
  1660. +   status_t status = MapBlock(nextBlock, nextBlockPos);
  1661. +   if (status != B_OK)
  1662. +       return status;
  1663. +
  1664. +   CachedBlock cached(fJournalVolume);
  1665. +   JournalHeader* header = (JournalHeader*)cached.SetTo(nextBlockPos);
  1666. +
  1667. +   int count = 0;
  1668. +
  1669. +   uint8* data = new(std::nothrow) uint8[fBlockSize];
  1670. +
  1671. +   while (nextCommitID < lastCommitID) {
  1672. +       if (!header->CheckMagic() || header->Sequence() != nextCommitID) {
  1673. +           // Somehow the log is different than the expexted
  1674. +           return B_ERROR;
  1675. +       }
  1676. +
  1677. +       uint32 blockType = header->BlockType();
  1678. +
  1679. +       if (blockType == JOURNAL_DESCRIPTOR_BLOCK) {
  1680. +           JournalBlockTag* last_tag = (JournalBlockTag*)((uint8*)header
  1681. +               + fBlockSize - sizeof(JournalBlockTag));
  1682. +
  1683. +           for (JournalBlockTag* tag = (JournalBlockTag*)header->data;
  1684. +               tag <= last_tag; ++tag) {
  1685. +               nextBlock = _WrapAroundLog(nextBlock + 1);
  1686. +
  1687. +               status = MapBlock(nextBlock, nextBlockPos);
  1688. +               if (status != B_OK) {
  1689. +                   delete [] data;
  1690. +                   return status;
  1691. +               }
  1692. +
  1693. +               size_t read = read_pos(fJournalVolume->Device(),
  1694. +                   nextBlockPos * fBlockSize, data, fBlockSize);
  1695. +               if (read != fBlockSize) {
  1696. +                   delete [] data;
  1697. +                   return B_IO_ERROR;
  1698. +               }
  1699. +
  1700. +               if (!fRevokeManager->Lookup(tag->BlockNumber(),
  1701. +                       nextCommitID)) {
  1702. +                   // Block isn't revoked
  1703. +                   if ((tag->Flags() & JOURNAL_FLAG_ESCAPED) != 0) {
  1704. +                       // Block is escaped
  1705. +                       ((int32*)data)[0]
  1706. +                           = B_HOST_TO_BENDIAN_INT32(JOURNAL_MAGIC);
  1707. +                   }
  1708. +
  1709. +                   size_t written = write_pos(fFilesystemVolume->Device(),
  1710. +                       tag->BlockNumber() * fBlockSize, data, fBlockSize);
  1711. +
  1712. +                   if (written != fBlockSize) {
  1713. +                       delete [] data;
  1714. +                       return B_IO_ERROR;
  1715. +                   }
  1716. +
  1717. +                   ++count;
  1718. +               }
  1719. +
  1720. +               if ((tag->Flags() & JOURNAL_FLAG_LAST_TAG) != 0)
  1721. +                   break;
  1722. +               if ((tag->Flags() & JOURNAL_FLAG_SAME_UUID) == 0) {
  1723. +                   // TODO: Check new UUID with file system UUID
  1724. +                   tag += 2;
  1725. +                       // sizeof(JournalBlockTag) = 8
  1726. +                       // sizeof(UUID) = 16
  1727. +               }
  1728. +           }
  1729. +       }
  1730. +       else if (blockType == JOURNAL_COMMIT_BLOCK)
  1731. +           nextCommitID++;
  1732. +       else if (blockType != JOURNAL_REVOKE_BLOCK) {
  1733. +               // TODO: Warn that we found an unrecognized block
  1734. +           break;
  1735. +       } // If blockType == JOURNAL_REVOKE_BLOCK we just skip it
  1736. +
  1737. +       nextBlock = _WrapAroundLog(nextBlock + 1);
  1738. +
  1739. +       status = MapBlock(nextBlock, nextBlockPos);
  1740. +       if (status != B_OK)
  1741. +           return status;
  1742. +
  1743. +       header = (JournalHeader*)cached.SetTo(nextBlockPos);
  1744. +   }
  1745. +
  1746. +   delete [] data;
  1747. +
  1748. +   if (nextCommitID != lastCommitID) {
  1749. +       // Possibly because of some sort of IO error
  1750. +       return B_ERROR;
  1751. +   }
  1752. +
  1753. +   TRACE("Journal recovery pass replay: Replayed blocks: %u\n", count);
  1754. +
  1755. +   return B_OK;
  1756. +}
  1757. +
  1758. +
  1759. +status_t
  1760. +Journal::_FlushLog(bool canWait, bool flushBlocks)
  1761. +{
  1762. +   TRACE("Journal::_FlushLog()\n");
  1763. +   status_t status = canWait ? recursive_lock_lock(&fLock)
  1764. +       : recursive_lock_trylock(&fLock);
  1765. +   if (status != B_OK)
  1766. +       return status;
  1767. +
  1768. +   TRACE("Journal::_FlushLog(): Acquired fLock, recursion: %ld\n",
  1769. +       recursive_lock_get_recursion(&fLock));
  1770. +
  1771. +   if (recursive_lock_get_recursion(&fLock) > 1) {
  1772. +       // Called from inside a transaction
  1773. +       recursive_lock_unlock(&fLock);
  1774. +       TRACE("Journal::_FlushLog(): Called from a transaction. Leaving...\n");
  1775. +       return B_OK;
  1776. +   }
  1777. +
  1778. +   if (fUnwrittenTransactions != 0 && _FullTransactionSize() != 0) {
  1779. +       status = _WriteTransactionToLog();
  1780. +       if (status < B_OK)
  1781. +           panic("Failed flushing transaction: %s\n", strerror(status));
  1782. +   }
  1783. +
  1784. +   TRACE("Journal::_FlushLog(): Attempting to flush journal volume at %p\n",
  1785. +       fJournalVolume);
  1786. +
  1787. +   // TODO: Not sure this is correct. Need to review...
  1788. +   status = fJournalVolume->FlushDevice();
  1789. +   if (status != B_OK)
  1790. +       return status;
  1791. +
  1792. +   TRACE("Journal::_FlushLog(): Flushed journal volume\n");
  1793. +
  1794. +   if (flushBlocks) {
  1795. +       TRACE("Journal::_FlushLog(): Attempting to flush file system volume "
  1796. +           "at %p\n", fFilesystemVolume);
  1797. +       status = fFilesystemVolume->FlushDevice();
  1798. +       if (status == B_OK)
  1799. +           TRACE("Journal::_FlushLog(): Flushed file system volume\n");
  1800. +   }
  1801. +
  1802. +   TRACE("Journal::_FlushLog(): Finished. Releasing lock\n");
  1803. +
  1804. +   recursive_lock_unlock(&fLock);
  1805. +  
  1806. +   TRACE("Journal::_FlushLog(): Done, final status: %s\n", strerror(status));
  1807. +   return status;
  1808. +}
  1809. +
  1810. +
  1811. +inline uint32
  1812. +Journal::_WrapAroundLog(uint32 block)
  1813. +{
  1814. +   if (block >= fLogSize)
  1815. +       return block - fLogSize + fLogStart;
  1816. +   else
  1817. +       return block;
  1818. +}
  1819. +
  1820. +
  1821. +size_t
  1822. +Journal::_CurrentTransactionSize() const
  1823. +{
  1824. +   TRACE("Journal::_CurrentTransactionSize(): transaction %ld\n",
  1825. +       fTransactionID);
  1826. +
  1827. +   size_t count;
  1828. +
  1829. +   if (fHasSubTransaction) {
  1830. +       count = cache_blocks_in_sub_transaction(fFilesystemBlockCache,
  1831. +           fTransactionID);
  1832. +
  1833. +       TRACE("\tSub transaction size: %ld\n", count);
  1834. +   } else {
  1835. +       count =  cache_blocks_in_transaction(fFilesystemBlockCache,
  1836. +           fTransactionID);
  1837. +
  1838. +       TRACE("\tTransaction size: %ld\n", count);
  1839. +   }
  1840. +
  1841. +   return count;
  1842. +}
  1843. +
  1844. +
  1845. +size_t
  1846. +Journal::_FullTransactionSize() const
  1847. +{
  1848. +   TRACE("Journal::_FullTransactionSize(): transaction %ld\n", fTransactionID);
  1849. +   TRACE("\tFile sytem block cache: %p\n", fFilesystemBlockCache);
  1850. +
  1851. +   size_t count = cache_blocks_in_transaction(fFilesystemBlockCache,
  1852. +        fTransactionID);
  1853. +  
  1854. +   TRACE("\tFull transaction size: %ld\n", count);
  1855. +  
  1856. +   return count;
  1857. +}
  1858. +
  1859. +
  1860. +size_t
  1861. +Journal::_MainTransactionSize() const
  1862. +{
  1863. +   TRACE("Journal::_MainTransactionSize(): transaction %ld\n", fTransactionID);
  1864. +
  1865. +   size_t count =  cache_blocks_in_main_transaction(fFilesystemBlockCache,
  1866. +       fTransactionID);
  1867. +  
  1868. +   TRACE("\tMain transaction size: %ld\n", count);
  1869. +  
  1870. +   return count;
  1871. +}
  1872. +
  1873. +
  1874. +status_t
  1875. +Journal::_TransactionDone(bool success)
  1876. +{
  1877. +   if (!success) {
  1878. +       if (fHasSubTransaction) {
  1879. +           TRACE("_TransactionDone(): transaction %ld failed, aborting "
  1880. +               "subtransaction\n", fTransactionID);
  1881. +           cache_abort_sub_transaction(fFilesystemBlockCache, fTransactionID);
  1882. +           // parent is unaffected
  1883. +       } else {
  1884. +           TRACE("_TransactionDone(): transaction %ld failed, aborting\n",
  1885. +               fTransactionID);
  1886. +           cache_abort_transaction(fFilesystemBlockCache, fTransactionID);
  1887. +           fUnwrittenTransactions = 0;
  1888. +       }
  1889. +
  1890. +       return B_OK;
  1891. +   }
  1892. +  
  1893. +   // If possible, delay flushing the transaction
  1894. +   uint32 size = _FullTransactionSize();
  1895. +   if (size < fMaxTransactionSize) {
  1896. +       TRACE("_TransactionDone(): delaying flush of transaction %ld\n",
  1897. +           fTransactionID);
  1898. +      
  1899. +       // Make sure the transaction fits in the log
  1900. +       if (size < FreeLogBlocks())
  1901. +           cache_sync_transaction(fFilesystemBlockCache, fTransactionID);
  1902. +      
  1903. +       fUnwrittenTransactions++;
  1904. +       return B_OK;
  1905. +   }
  1906. +
  1907. +   return _WriteTransactionToLog();
  1908. +}
  1909. +
  1910. +
  1911. +/*static*/ void
  1912. +Journal::_TransactionWritten(int32 transactionID, int32 event, void* _logEntry)
  1913. +{
  1914. +   LogEntry* logEntry = (LogEntry*)_logEntry;
  1915. +
  1916. +   TRACE("_TransactionWritten(): Transaction %ld checkpointed\n",
  1917. +       transactionID);
  1918. +
  1919. +   Journal* journal = logEntry->GetJournal();
  1920. +
  1921. +   mutex_lock(&journal->fLogEntriesLock);
  1922. +
  1923. +   if (logEntry == journal->fLogEntries.First()) {
  1924. +       LogEntry* next = journal->fLogEntries.GetNext(logEntry);
  1925. +       if (next != NULL)
  1926. +           journal->fLogStart = next->Start();
  1927. +       else {
  1928. +           journal->fLogStart = journal->fLogEnd;
  1929. +           journal->fFirstCommitID = next->CommitID();
  1930. +       }
  1931. +
  1932. +       journal->_SaveSuperBlock();
  1933. +           // TODO: What if this fails?
  1934. +   }
  1935. +
  1936. +   journal->fLogEntries.Remove(logEntry);
  1937. +   mutex_unlock(&journal->fLogEntriesLock);
  1938. +
  1939. +   delete logEntry;
  1940. +}
  1941. +
  1942. +
  1943. +/*static*/ void
  1944. +Journal::_TransactionIdle(int32 transactionID, int32 event, void* _journal)
  1945. +{
  1946. +   Journal* journal = (Journal*)_journal;
  1947. +   journal->_FlushLog(false, false);
  1948. +}
  1949.  
  1950. Property changes on: src/add-ons/kernel/file_systems/ext2/Journal.cpp
  1951. ___________________________________________________________________
  1952. Added: svn:executable
  1953.    + *
  1954.  
  1955. Index: src/add-ons/kernel/file_systems/ext2/NoJournal.h
  1956. ===================================================================
  1957. --- src/add-ons/kernel/file_systems/ext2/NoJournal.h    (revision 0)
  1958. +++ src/add-ons/kernel/file_systems/ext2/NoJournal.h    (revision 0)
  1959. @@ -0,0 +1,30 @@
  1960. +/*
  1961. + * Copyright 2001-2010, Haiku Inc. All rights reserved.
  1962. + * This file may be used under the terms of the MIT License.
  1963. + *
  1964. + * Authors:
  1965. + *     Janito V. Ferreira Filho
  1966. + */
  1967. +#ifndef NOJOURNAL_H
  1968. +#define NOJOURNAL_H
  1969. +
  1970. +
  1971. +#include "Journal.h"
  1972. +
  1973. +
  1974. +class NoJournal : public Journal {
  1975. +public:
  1976. +                       NoJournal(Volume* volume);
  1977. +                       ~NoJournal();
  1978. +
  1979. +           status_t    InitCheck();
  1980. +           status_t    Recover();
  1981. +           status_t    StartLog();
  1982. +private:
  1983. +           status_t    _WriteTransactionToLog();
  1984. +
  1985. +   static  void        _TransactionWritten(int32 transactionID,
  1986. +                           int32 event, void* param);
  1987. +};
  1988. +
  1989. +#endif // NOJOURNAL_H
  1990.  
  1991. Property changes on: src/add-ons/kernel/file_systems/ext2/HTree.h
  1992. ___________________________________________________________________
  1993. Added: svn:executable
  1994.    + *
  1995.  
  1996. Index: src/add-ons/kernel/file_systems/ext2/IndexedDirectoryIterator.cpp
  1997. ===================================================================
  1998. --- src/add-ons/kernel/file_systems/ext2/IndexedDirectoryIterator.cpp   (revision 37486)
  1999. +++ src/add-ons/kernel/file_systems/ext2/IndexedDirectoryIterator.cpp   (working copy)
  2000. @@ -24,17 +24,16 @@
  2001.  
  2002.  
  2003.  IndexedDirectoryIterator::IndexedDirectoryIterator(off_t start,
  2004. -   uint32 blockSize, Inode* directory, HTreeEntryIterator* parent)
  2005. +   Inode* directory, HTreeEntryIterator* parent)
  2006.     :
  2007.     DirectoryIterator(directory),
  2008.     fIndexing(true),
  2009. -  
  2010.     fParent(parent),
  2011. -   fMaxOffset(start + blockSize),
  2012. -   fBlockSize(blockSize),
  2013.     fMaxAttempts(0)
  2014.  {
  2015. -   fOffset = start;
  2016. +   fDisplacement = start % fBlockSize;
  2017. +   fInitStatus = fInode->FindBlock(start / fBlockSize, fBlock);
  2018. +   fPreviousBlock = fBlock;
  2019.  }
  2020.  
  2021.  
  2022. @@ -46,16 +45,27 @@
  2023.  status_t
  2024.  IndexedDirectoryIterator::GetNext(char* name, size_t* nameLength, ino_t* id)
  2025.  {
  2026. -   if (fIndexing && fOffset + sizeof(HTreeFakeDirEntry) >= fMaxOffset) {
  2027. +   TRACE("IndexedDirectoryIterator::GetNext()\n");
  2028. +   if (fIndexing && fBlock != fPreviousBlock) {
  2029.         TRACE("IndexedDirectoryIterator::GetNext() calling next block\n");
  2030. -       status_t status = fParent->GetNext(fOffset);
  2031. +
  2032. +       // TODO: If parent doesn't have collisions, the entry wasn't found
  2033. +
  2034. +       fDisplacement = 0;
  2035. +       status_t status = fParent->GetNext(fBlock);
  2036.         if (status != B_OK)
  2037.             return status;
  2038.  
  2039. -       if (fMaxAttempts++ > 4)
  2040. -           return B_ERROR;
  2041. +       fPreviousBlock = fBlock;
  2042.        
  2043. -       fMaxOffset = fOffset + fBlockSize;
  2044. +       if (!fParent->HasCollision()) {
  2045. +           TRACE("IndexedDirectoryIterator::GetNext(): next block doesn't "
  2046. +               "contain collisions from previous block\n");
  2047. +           return B_ENTRY_NOT_FOUND;
  2048. +       }
  2049. +
  2050. +       /*if (fMaxAttempts++ > 4)
  2051. +           return B_ERROR;*/
  2052.     }
  2053.    
  2054.     return DirectoryIterator::GetNext(name, nameLength, id);
  2055. @@ -67,9 +77,23 @@
  2056.  {
  2057.     // The only way to rewind it is too loose indexing
  2058.    
  2059. -   fOffset = 0;
  2060. -   fMaxOffset = fInode->Size();
  2061. +   fDisplacement = 0;
  2062.     fIndexing = false;
  2063.  
  2064. -   return B_OK;
  2065. +   return fInode->FindBlock(0, fBlock);
  2066.  }
  2067. +
  2068. +
  2069. +status_t
  2070. +IndexedDirectoryIterator::AddEntry(Transaction& transaction, char* name,
  2071. +   size_t _nameLength, ino_t id)
  2072. +{
  2073. +   panic("Adding entries to a HTree is not supported yet.\n");
  2074. +
  2075. +   // TODO: Once the method DirectoryIterator::FindEmptyEntrySpot is
  2076. +   // implemented, we should call it to see if the offset exceeds the
  2077. +   // fMaxOffset. If it does, the current block is full, and we need
  2078. +   // to start splitting nodes.
  2079. +  
  2080. +   return B_NOT_SUPPORTED;
  2081. +}
  2082. Index: src/add-ons/kernel/file_systems/ext2/DirectoryIterator.h
  2083. ===================================================================
  2084. --- src/add-ons/kernel/file_systems/ext2/DirectoryIterator.h    (revision 37486)
  2085. +++ src/add-ons/kernel/file_systems/ext2/DirectoryIterator.h    (working copy)
  2086. @@ -8,7 +8,9 @@
  2087.  
  2088.  #include <SupportDefs.h>
  2089.  
  2090. +#include "Transaction.h"
  2091.  
  2092. +
  2093.  class Inode;
  2094.  
  2095.  class DirectoryIterator {
  2096. @@ -16,10 +18,15 @@
  2097.                         DirectoryIterator(Inode* inode);
  2098.     virtual             ~DirectoryIterator();
  2099.  
  2100. +   virtual status_t    InitCheck();
  2101. +
  2102.     virtual status_t    GetNext(char* name, size_t* _nameLength, ino_t* id);
  2103.  
  2104.     virtual status_t    Rewind();
  2105.  
  2106. +   virtual status_t    AddEntry(Transaction& transaction, char* name,
  2107. +                           size_t nameLength, ino_t id);
  2108. +
  2109.  private:
  2110.                         DirectoryIterator(const DirectoryIterator&);
  2111.                         DirectoryIterator &operator=(const DirectoryIterator&);
  2112. @@ -27,7 +34,11 @@
  2113.  
  2114.  protected:
  2115.     Inode*              fInode;
  2116. -   off_t               fOffset;
  2117. +   uint32              fBlock;
  2118. +   uint32              fDisplacement;
  2119. +   uint32              fBlockSize;
  2120. +   status_t            fInitStatus;
  2121.  };
  2122.  
  2123.  #endif // DIRECTORY_ITERATOR_H
  2124. +
  2125. Index: src/add-ons/kernel/file_systems/ext2/RevokeManager.cpp
  2126. ===================================================================
  2127. --- src/add-ons/kernel/file_systems/ext2/RevokeManager.cpp  (revision 0)
  2128. +++ src/add-ons/kernel/file_systems/ext2/RevokeManager.cpp  (revision 0)
  2129. @@ -0,0 +1,38 @@
  2130. +/*
  2131. + * Copyright 2001-2010, Haiku Inc. All rights reserved.
  2132. + * This file may be used under the terms of the MIT License.
  2133. + *
  2134. + * Authors:
  2135. + *     Janito V. Ferreira Filho
  2136. + */
  2137. +
  2138. +#include "RevokeManager.h"
  2139. +
  2140. +
  2141. +RevokeManager::RevokeManager()
  2142. +   :
  2143. +   fRevokeCount(0)
  2144. +{
  2145. +}
  2146. +
  2147. +
  2148. +RevokeManager::~RevokeManager()
  2149. +{
  2150. +}
  2151. +
  2152. +
  2153. +status_t
  2154. +RevokeManager::ScanRevokeBlock(JournalRevokeHeader* revokeBlock, uint32 commitID)
  2155. +{
  2156. +   int count = revokeBlock->NumBytes() >> 3;
  2157. +  
  2158. +   for (int i = 0; i < count; ++i) {
  2159. +       status_t status = Insert(revokeBlock->RevokeBlock(i), commitID);
  2160. +      
  2161. +       if (status != B_OK)
  2162. +           return status;
  2163. +   }
  2164. +
  2165. +   return B_OK;
  2166. +}
  2167. +
  2168.  
  2169. Property changes on: src/add-ons/kernel/file_systems/ext2/RevokeManager.cpp
  2170. ___________________________________________________________________
  2171. Added: svn:executable
  2172.    + *
  2173.  
  2174. Index: src/add-ons/kernel/file_systems/ext2/Jamfile
  2175. ===================================================================
  2176. --- src/add-ons/kernel/file_systems/ext2/Jamfile    (revision 37486)
  2177. +++ src/add-ons/kernel/file_systems/ext2/Jamfile    (working copy)
  2178. @@ -18,6 +18,15 @@
  2179.     IndexedDirectoryIterator.cpp
  2180.     HTree.cpp
  2181.     HTreeEntryIterator.cpp
  2182. +   RevokeManager.cpp
  2183. +   HashRevokeManager.cpp
  2184. +   Journal.cpp
  2185. +   NoJournal.cpp
  2186. +   InodeJournal.cpp
  2187. +   Transaction.cpp
  2188. +   BitmapBlock.cpp
  2189. +   BlockAllocator.cpp
  2190. +   InodeAllocator.cpp
  2191.  
  2192.     kernel_interface.cpp
  2193.  ;
  2194. Index: src/add-ons/kernel/file_systems/ext2/BitmapBlock.cpp
  2195. ===================================================================
  2196. --- src/add-ons/kernel/file_systems/ext2/BitmapBlock.cpp    (revision 0)
  2197. +++ src/add-ons/kernel/file_systems/ext2/BitmapBlock.cpp    (revision 0)
  2198. @@ -0,0 +1,509 @@
  2199. +/*
  2200. + * Copyright 2001-2010, Haiku Inc. All rights reserved.
  2201. + * This file may be used under the terms of the MIT License.
  2202. + *
  2203. + * Authors:
  2204. + *     Janito V. Ferreira Filho
  2205. + */
  2206. +
  2207. +#include "BitmapBlock.h"
  2208. +
  2209. +
  2210. +BitmapBlock::BitmapBlock(Volume* volume, uint32 numBits)
  2211. +   :
  2212. +   CachedBlock(volume),
  2213. +   fData(NULL),
  2214. +   fReadOnlyData(NULL),
  2215. +   fNumBits(numBits)
  2216. +{
  2217. +}
  2218. +
  2219. +
  2220. +BitmapBlock::~BitmapBlock()
  2221. +{
  2222. +}
  2223. +
  2224. +
  2225. +/*virtual*/ bool
  2226. +BitmapBlock::SetTo(uint32 block)
  2227. +{
  2228. +   fData = NULL;
  2229. +   fReadOnlyData = (uint32*)CachedBlock::SetTo(block);
  2230. +
  2231. +   return fReadOnlyData != NULL;
  2232. +}
  2233. +
  2234. +
  2235. +/*virtual*/ bool
  2236. +BitmapBlock::SetToWritable(Transaction& transaction, uint32 block, bool empty)
  2237. +{
  2238. +   fReadOnlyData = NULL;
  2239. +   fData = (uint32*)CachedBlock::SetToWritable(transaction, block, empty);
  2240. +
  2241. +   return fData != NULL;
  2242. +}
  2243. +
  2244. +
  2245. +/*virtual*/ bool
  2246. +BitmapBlock::CheckUnmarked(uint32 start, uint32 length)
  2247. +{
  2248. +   const uint32* data = fData == NULL ? fReadOnlyData : fData;
  2249. +   if (data == NULL)
  2250. +       return false;
  2251. +
  2252. +   if (start + length > fNumBits)
  2253. +       return false;
  2254. +
  2255. +   uint32 startIndex = start >> 5;
  2256. +   uint32 startBit = start & 0x1F;
  2257. +   uint32 iterations = (length - startBit) >> 5;
  2258. +   uint32 remainingBits = (length - startBit) & 0x1F;
  2259. +
  2260. +   uint32 index = startIndex;
  2261. +   uint32 mask = 0;
  2262. +
  2263. +   if (startBit != 0) {
  2264. +       mask = ~((1 << startBit) - 1);
  2265. +       uint32 bits = B_LENDIAN_TO_HOST_INT32(data[index]);
  2266. +
  2267. +       if ((bits & mask) != 0)
  2268. +           return false;
  2269. +
  2270. +       index += 1;
  2271. +   }
  2272. +
  2273. +   for (; iterations > 0; --iterations) {
  2274. +       if (data[index++] != 0)
  2275. +           return false;
  2276. +   }
  2277. +
  2278. +   if (remainingBits != 0) {
  2279. +       mask = (1 << remainingBits + 1) - 1;
  2280. +
  2281. +       uint32 bits = B_LENDIAN_TO_HOST_INT32(data[index]);
  2282. +       if ((bits & mask) != 0)
  2283. +           return false;
  2284. +   }
  2285. +
  2286. +   return true;
  2287. +}
  2288. +
  2289. +
  2290. +/*virtual*/ bool
  2291. +BitmapBlock::CheckMarked(uint32 start, uint32 length)
  2292. +{
  2293. +   const uint32* data = fData == NULL ? fReadOnlyData : fData;
  2294. +   if (data == NULL)
  2295. +       return false;
  2296. +
  2297. +   if (start + length > fNumBits)
  2298. +       return false;
  2299. +
  2300. +   uint32 startIndex = start >> 5;
  2301. +   uint32 startBit = start & 0x1F;
  2302. +   uint32 iterations = (length - startBit) >> 5;
  2303. +   uint32 remainingBits = (length - startBit) & 0x1F;
  2304. +
  2305. +   uint32 index = startIndex;
  2306. +   uint32 mask = 0;
  2307. +
  2308. +   if (startBit != 0) {
  2309. +       mask = ~((1 << startBit) - 1);
  2310. +       uint32 bits = B_LENDIAN_TO_HOST_INT32(data[index]);
  2311. +
  2312. +       if ((bits & mask) != mask)
  2313. +           return false;
  2314. +
  2315. +       index += 1;
  2316. +   }
  2317. +
  2318. +   mask = 0xFFFFFFFF;
  2319. +   for (; iterations > 0; --iterations) {
  2320. +       if (data[index++] != mask)
  2321. +           return false;
  2322. +   }
  2323. +
  2324. +   if (remainingBits != 0) {
  2325. +       mask = (1 << remainingBits + 1) - 1;
  2326. +       uint32 bits = B_HOST_TO_LENDIAN_INT32(data[index]);
  2327. +
  2328. +       if ((bits & mask) != mask)
  2329. +           return false;
  2330. +   }
  2331. +
  2332. +   return true;
  2333. +}
  2334. +
  2335. +
  2336. +/*virtual*/ bool
  2337. +BitmapBlock::Mark(uint32 start, uint32 length, bool force)
  2338. +{
  2339. +   if (fData != NULL && start + length <= fNumBits)
  2340. +       return false;
  2341. +
  2342. +   uint32 startIndex = start >> 5;
  2343. +   uint32 startBit = start & 0x1F;
  2344. +   uint32 iterations = (length - startBit) >> 5;
  2345. +   uint32 remainingBits = (length - startBit) & 0x1F;
  2346. +
  2347. +   uint32 index = startIndex;
  2348. +   uint32 mask = 0;
  2349. +
  2350. +   if (startBit != 0) {
  2351. +       mask = ~((1 << startBit) - 1);
  2352. +       uint32 bits = B_LENDIAN_TO_HOST_INT32(fData[index]);
  2353. +
  2354. +       if (!force && (bits & mask) != 0)
  2355. +           return false;
  2356. +
  2357. +       bits |= mask;
  2358. +       fData[index] = B_HOST_TO_LENDIAN_INT32(bits);
  2359. +
  2360. +       index += 1;
  2361. +   }
  2362. +
  2363. +   mask = 0xFFFFFFFF;
  2364. +   for (; iterations > 0; --iterations) {
  2365. +       if (!force && fData[startIndex] != 0)
  2366. +           return false;
  2367. +       fData[index++] |= mask;
  2368. +   }
  2369. +
  2370. +   if (remainingBits != 0) {
  2371. +       mask = (1 << remainingBits + 1) - 1;
  2372. +       uint32 bits = B_LENDIAN_TO_HOST_INT32(fData[index]);
  2373. +
  2374. +       if (!force && (bits & mask) != 0)
  2375. +           return false;
  2376. +
  2377. +       bits |= mask;
  2378. +       fData[index] = B_HOST_TO_LENDIAN_INT32(bits);
  2379. +   }
  2380. +
  2381. +   return true;
  2382. +}
  2383. +
  2384. +
  2385. +/*virtual*/ bool
  2386. +BitmapBlock::Unmark(uint32 start, uint32 length, bool force)
  2387. +{
  2388. +   if (fData != NULL && start + length <= fNumBits)
  2389. +       return false;
  2390. +
  2391. +   uint32 startIndex = start >> 5;
  2392. +   uint32 startBit = start & 0x1F;
  2393. +   uint32 iterations = (length - startBit) >> 5;
  2394. +   uint32 remainingBits = (length - startBit) & 0x1F;
  2395. +
  2396. +   uint32 index = startIndex;
  2397. +   uint32 mask = 0;
  2398. +
  2399. +   if (startBit != 0) {
  2400. +       mask = ~((1 << startBit) - 1);
  2401. +       uint32 bits = B_LENDIAN_TO_HOST_INT32(fData[index]);
  2402. +
  2403. +       if (!force && (bits & mask) != mask)
  2404. +           return false;
  2405. +
  2406. +       bits &= ~mask;
  2407. +       fData[index] = B_HOST_TO_LENDIAN_INT32(bits);
  2408. +
  2409. +       index += 1;
  2410. +   }
  2411. +
  2412. +   mask = 0xFFFFFFFF;
  2413. +   for (; iterations > 0; --iterations) {
  2414. +       if (!force && fData[startIndex] != mask)
  2415. +           return false;
  2416. +       fData[index++] = 0;
  2417. +   }
  2418. +
  2419. +   if (remainingBits != 0) {
  2420. +       mask = (1 << remainingBits + 1) - 1;
  2421. +       uint32 bits = B_LENDIAN_TO_HOST_INT32(fData[index]);
  2422. +
  2423. +       if (!force && (bits & mask) != mask)
  2424. +           return false;
  2425. +
  2426. +       bits &= ~mask;
  2427. +       fData[index] = B_HOST_TO_LENDIAN_INT32(bits);
  2428. +   }
  2429. +
  2430. +   return true;
  2431. +}
  2432. +
  2433. +
  2434. +void
  2435. +BitmapBlock::FindNextMarked(uint32& pos)
  2436. +{
  2437. +   const uint32* data = fData == NULL ? fReadOnlyData : fData;
  2438. +   if (data == NULL)
  2439. +       return;
  2440. +
  2441. +   if (pos >= fNumBits) {
  2442. +       pos = fNumBits;
  2443. +       return;
  2444. +   }
  2445. +
  2446. +   uint32 index = pos >> 5;
  2447. +   uint32 bit = pos & 0x1F;
  2448. +
  2449. +   uint32 mask = (1 << bit) - 1;
  2450. +   uint32 bits = B_LENDIAN_TO_HOST_INT32(data[index]);
  2451. +   bits = bits & ~mask;
  2452. +
  2453. +   if (bits == 0) {
  2454. +       // Find an block of 32 bits that has a marked bit
  2455. +       uint32 maxIndex = fNumBits >> 5;
  2456. +
  2457. +       do { index++; }
  2458. +           while (data[index] == 0 && index < maxIndex);
  2459. +
  2460. +       bits = B_LENDIAN_TO_HOST_INT32(data[index]);
  2461. +       if (bits == 0) {
  2462. +           // Not found
  2463. +           pos = fNumBits;
  2464. +           return;
  2465. +       }
  2466. +
  2467. +       bit = 0;
  2468. +   }
  2469. +
  2470. +   for (; bit < 32; ++bit) {
  2471. +       // Find the marked bit
  2472. +       if ((bits >> bit & 1) != 0) {
  2473. +           pos = index << 5 | bit;
  2474. +           return;
  2475. +       }
  2476. +   }
  2477. +
  2478. +   panic("Couldn't find marked bit inside an int32 which is different than "
  2479. +       "zero!?\n");
  2480. +}
  2481. +
  2482. +
  2483. +void
  2484. +BitmapBlock::FindNextUnmarked(uint32& pos)
  2485. +{
  2486. +   const uint32* data = fData == NULL ? fReadOnlyData : fData;
  2487. +   if (data == NULL)
  2488. +       return;
  2489. +
  2490. +   if (pos >= fNumBits) {
  2491. +       pos = fNumBits;
  2492. +       return;
  2493. +   }
  2494. +
  2495. +   uint32 index = pos >> 5;
  2496. +   uint32 bit = pos & 0x1F;
  2497. +
  2498. +   uint32 mask = (1 << bit) - 1;
  2499. +   uint32 bits = B_LENDIAN_TO_HOST_INT32(data[index]);
  2500. +   bits &= ~mask;
  2501. +
  2502. +   if (bits == ~mask) {
  2503. +       // Find an block of 32 bits that has a unmarked bit
  2504. +       uint32 maxIndex = fNumBits >> 5;
  2505. +
  2506. +       do { index++; }
  2507. +           while (data[index] != 0 && index < maxIndex);
  2508. +
  2509. +       bits = B_LENDIAN_TO_HOST_INT32(data[index]);
  2510. +       if (bits != 0) {
  2511. +           // Not found
  2512. +           pos = fNumBits;
  2513. +           return;
  2514. +       }
  2515. +
  2516. +       bit = 0;
  2517. +   }
  2518. +
  2519. +   for (; bit < 32; ++bit) {
  2520. +       // Find the unmarked bit
  2521. +       if ((bits >> bit & 1) == 0) {
  2522. +           pos = index << 5 | bit;
  2523. +           return;
  2524. +       }
  2525. +   }
  2526. +
  2527. +   panic("Couldn't find unmarked bit inside an int32 whith value zero!?\n");
  2528. +}
  2529. +
  2530. +
  2531. +void
  2532. +BitmapBlock::FindPreviousMarked(uint32& pos)
  2533. +{
  2534. +   const uint32* data = fData == NULL ? fReadOnlyData : fData;
  2535. +   if (data == NULL)
  2536. +       return;
  2537. +
  2538. +   if (pos >= fNumBits)
  2539. +       pos = fNumBits;
  2540. +
  2541. +   if (pos == 0)
  2542. +       return;
  2543. +
  2544. +   uint32 index = pos >> 5;
  2545. +   uint32 bit = pos & 0x1F;
  2546. +
  2547. +   uint32 mask = (1 << bit + 1) - 1;
  2548. +   uint32 bits = B_LENDIAN_TO_HOST_INT32(data[index]);
  2549. +   bits = bits & mask;
  2550. +
  2551. +   if (bits == 0) {
  2552. +       // Find an block of 32 bits that has a marked bit
  2553. +       do { index--; }
  2554. +           while (data[index] == 0 && index >= 0);
  2555. +
  2556. +       bits = B_LENDIAN_TO_HOST_INT32(data[index]);
  2557. +       if (bits == 0) {
  2558. +           // Not found
  2559. +           pos = 0;
  2560. +           return;
  2561. +       }
  2562. +
  2563. +       bit = 31;
  2564. +   }
  2565. +
  2566. +   for (; bit >= 0; --bit) {
  2567. +       // Find the unmarked bit
  2568. +       if ((bits >> bit & 1) == 0) {
  2569. +           pos = index << 5 | bit;
  2570. +           return;
  2571. +       }
  2572. +   }
  2573. +
  2574. +   panic("Couldn't find marked bit inside an int32 whith value different than "
  2575. +       "zero!?\n");
  2576. +}
  2577. +
  2578. +
  2579. +void
  2580. +BitmapBlock::FindLargestUnmarkedRange(uint32& start, uint32& length)
  2581. +{
  2582. +   const uint32* data = fData == NULL ? fReadOnlyData : fData;
  2583. +   if (data == NULL)
  2584. +       return;
  2585. +
  2586. +   uint32 wordSpan = length >> 5;
  2587. +   uint32 lastIndex = fNumBits >> 5;
  2588. +   uint32 startIndex = 0;
  2589. +   uint32 index = 0;
  2590. +   uint32 bits = B_LENDIAN_TO_HOST_INT32(data[0]);
  2591. +
  2592. +   if (wordSpan == 0) {
  2593. +       uint32 startPos = 0;
  2594. +       uint32 endPos = 0;
  2595. +
  2596. +       while (endPos < fNumBits) {
  2597. +           FindNextUnmarked(startPos);
  2598. +           endPos = startPos;
  2599. +
  2600. +           if (startPos != fNumBits) {
  2601. +               FindNextMarked(endPos);
  2602. +               if (endPos - startPos >= 32)
  2603. +                   break;
  2604. +               else if (endPos - startPos > length) {
  2605. +                   start = startPos;
  2606. +                   length = endPos - startPos;
  2607. +               }
  2608. +
  2609. +               startPos = endPos;
  2610. +           }
  2611. +       }
  2612. +
  2613. +       if (endPos - startPos < 32) {
  2614. +           if (endPos - startPos > length) {
  2615. +               start = startPos;
  2616. +               length = endPos - startPos;
  2617. +           }
  2618. +
  2619. +           return;
  2620. +       }
  2621. +
  2622. +       start = startPos;
  2623. +       length = endPos - startPos;
  2624. +
  2625. +       wordSpan = length >> 5;
  2626. +       startIndex = startPos >> 5;
  2627. +       index = (endPos >> 5) + 1;
  2628. +       bits = B_LENDIAN_TO_HOST_INT32(data[index]);
  2629. +   }
  2630. +
  2631. +   for (; index < lastIndex; ++index) {
  2632. +       bits = B_LENDIAN_TO_HOST_INT32(data[index]);
  2633. +
  2634. +       if (bits != 0) {
  2635. +           // Contains marked bits
  2636. +           if (index - startIndex >= wordSpan) {
  2637. +               uint32 newLength = index - startIndex << 5;
  2638. +               uint32 newStart = startIndex + 1 << 5;
  2639. +
  2640. +               if (newStart != 0) {
  2641. +                   uint32 startBits =
  2642. +                       B_LENDIAN_TO_HOST_INT32(data[startIndex]);
  2643. +
  2644. +                   for (int32 bit = 31; bit >= 0; --bit) {
  2645. +                       if ((startBits >> bit & 1) != 0)
  2646. +                           break;
  2647. +
  2648. +                       ++newLength;
  2649. +                       --newStart;
  2650. +                   }
  2651. +               }
  2652. +
  2653. +               for (int32 bit = 0; bit < 32; ++bit) {
  2654. +                   if ((bits >> bit & 1) != 0)
  2655. +                       break;
  2656. +
  2657. +                   ++newLength;
  2658. +               }
  2659. +
  2660. +               if (newLength > length) {
  2661. +                   start = newStart;
  2662. +                   length = newLength;
  2663. +                   wordSpan = length >> 5;
  2664. +               }
  2665. +           }
  2666. +
  2667. +           startIndex = index;
  2668. +       }
  2669. +   }
  2670. +
  2671. +   if (index - startIndex >= wordSpan) {
  2672. +       uint32 newLength = index - startIndex << 5;
  2673. +       uint32 newStart = startIndex + 1 << 5;
  2674. +
  2675. +       if (newStart != 0) {
  2676. +           uint32 startBits = B_LENDIAN_TO_HOST_INT32(data[startIndex]);
  2677. +
  2678. +           for (int32 bit = 31; bit >= 0; --bit) {
  2679. +               if ((startBits >> bit & 1) != 0)
  2680. +                   break;
  2681. +
  2682. +               ++newLength;
  2683. +               --newStart;
  2684. +           }
  2685. +       }
  2686. +
  2687. +       for (int32 bit = 0; bit < 32; ++bit) {
  2688. +           if ((bits >> bit & 1) != 0)
  2689. +               break;
  2690. +
  2691. +           ++newLength;
  2692. +       }
  2693. +
  2694. +       if (newLength > length) {
  2695. +           start = newStart;
  2696. +           length = newLength;
  2697. +           wordSpan = length >> 5;
  2698. +       }
  2699. +   }
  2700. +}
  2701. +
  2702. +
  2703. +uint32
  2704. +BitmapBlock::NumBits() const
  2705. +{
  2706. +   return fNumBits;
  2707. +}
  2708.  
  2709. Property changes on: src/add-ons/kernel/file_systems/ext2/BitmapBlock.cpp
  2710. ___________________________________________________________________
  2711. Added: svn:executable
  2712.    + *
  2713.  
  2714. Index: src/add-ons/kernel/file_systems/ext2/InodeJournal.cpp
  2715. ===================================================================
  2716. --- src/add-ons/kernel/file_systems/ext2/InodeJournal.cpp   (revision 0)
  2717. +++ src/add-ons/kernel/file_systems/ext2/InodeJournal.cpp   (revision 0)
  2718. @@ -0,0 +1,62 @@
  2719. +/*
  2720. + * Copyright 2001-2010, Haiku Inc. All rights reserved.
  2721. + * This file may be used under the terms of the MIT License.
  2722. + *
  2723. + * Authors:
  2724. + *     Janito V. Ferreira Filho
  2725. + */
  2726. +
  2727. +#include "InodeJournal.h"
  2728. +
  2729. +#include <fs_cache.h>
  2730. +
  2731. +
  2732. +//#define TRACE_EXT2
  2733. +#ifdef TRACE_EXT2
  2734. +#  define TRACE(x...) dprintf("\33[34mext2:\33[0m " x)
  2735. +#else
  2736. +#  define TRACE(x...) ;
  2737. +#endif
  2738. +
  2739. +
  2740. +InodeJournal::InodeJournal(Inode* inode)
  2741. +   :
  2742. +   Journal(),
  2743. +   fInode(inode)
  2744. +{
  2745. +   if (inode == NULL)
  2746. +       fInitStatus = B_BAD_DATA;
  2747. +   else {
  2748. +       Volume* volume = inode->GetVolume();
  2749. +
  2750. +       fFilesystemVolume = volume;
  2751. +       fFilesystemBlockCache = volume->BlockCache();
  2752. +       fJournalVolume = volume;
  2753. +
  2754. +       if (!inode->IsFileCacheDisabled())
  2755. +           fInitStatus = inode->DisableFileCache();
  2756. +       else
  2757. +           fInitStatus = B_OK;
  2758. +   }
  2759. +}
  2760. +
  2761. +
  2762. +InodeJournal::~InodeJournal()
  2763. +{
  2764. +}
  2765. +
  2766. +
  2767. +status_t
  2768. +InodeJournal::InitCheck()
  2769. +{
  2770. +   if (fInitStatus != B_OK)
  2771. +       TRACE("InodeJournal: Failed to disable the inode's file cache\n");
  2772. +   return fInitStatus;
  2773. +}
  2774. +
  2775. +
  2776. +status_t
  2777. +InodeJournal::MapBlock(uint32 logical, uint32& physical)
  2778. +{
  2779. +   return fInode->FindBlock(logical * fBlockSize, physical);
  2780. +}
  2781. Index: src/add-ons/kernel/file_systems/ext2/Transaction.h
  2782. ===================================================================
  2783. --- src/add-ons/kernel/file_systems/ext2/Transaction.h  (revision 0)
  2784. +++ src/add-ons/kernel/file_systems/ext2/Transaction.h  (revision 0)
  2785. @@ -0,0 +1,72 @@
  2786. +/*
  2787. + * Copyright 2001-2010, Haiku Inc. All rights reserved.
  2788. + * This file may be used under the terms of the MIT License.
  2789. + *
  2790. + * Authors:
  2791. + *     Janito V. Ferreira Filho
  2792. + */
  2793. +#ifndef TRANSACTION_H
  2794. +#define TRANSACTION_H
  2795. +
  2796. +
  2797. +#include <util/DoublyLinkedList.h>
  2798. +
  2799. +
  2800. +class Journal;
  2801. +class Volume;
  2802. +
  2803. +
  2804. +class TransactionListener
  2805. +   : public DoublyLinkedListLinkImpl<TransactionListener> {
  2806. +public:
  2807. +                               TransactionListener();
  2808. +   virtual                     ~TransactionListener();
  2809. +
  2810. +   virtual void                TransactionDone(bool success) = 0;
  2811. +   virtual void                RemovedFromTransaction() = 0;
  2812. +};
  2813. +
  2814. +typedef DoublyLinkedList<TransactionListener> TransactionListeners;
  2815. +
  2816. +
  2817. +class Transaction {
  2818. +public:
  2819. +                                   Transaction();
  2820. +                                   Transaction(Journal* journal);
  2821. +                                   ~Transaction();
  2822. +
  2823. +           status_t                Start(Journal* journal);
  2824. +           status_t                Done();
  2825. +
  2826. +           bool                    IsStarted() const;
  2827. +           bool                    HasParent() const;
  2828. +
  2829. +           status_t                WriteBlocks(off_t blockNumber,
  2830. +                                       const uint8* buffer,
  2831. +                                       size_t numBlocks = 1);
  2832. +
  2833. +           void                    Split();
  2834. +
  2835. +           Volume*                 GetVolume() const;
  2836. +           int32                   ID() const;
  2837. +
  2838. +           void                    AddListener(TransactionListener* listener);
  2839. +           void                    RemoveListener(
  2840. +                                       TransactionListener* listener);
  2841. +
  2842. +           void                    NotifyListeners(bool success);
  2843. +           void                    MoveListenersTo(Transaction* transaction);
  2844. +          
  2845. +           void                    SetParent(Transaction* transaction);
  2846. +           Transaction*            Parent() const;
  2847. +private:
  2848. +                                   Transaction(const Transaction& other);
  2849. +           Transaction&            operator=(const Transaction& other);
  2850. +               // no implementation
  2851. +
  2852. +           Journal*                fJournal;
  2853. +           TransactionListeners    fListeners;
  2854. +           Transaction*            fParent;
  2855. +};
  2856. +
  2857. +#endif // TRANSACTION_H
  2858. Index: src/add-ons/kernel/file_systems/ext2/BlockAllocator.cpp
  2859. ===================================================================
  2860. --- src/add-ons/kernel/file_systems/ext2/BlockAllocator.cpp (revision 0)
  2861. +++ src/add-ons/kernel/file_systems/ext2/BlockAllocator.cpp (revision 0)
  2862. @@ -0,0 +1,606 @@
  2863. +/*
  2864. + * Copyright 2001-2010, Haiku Inc. All rights reserved.
  2865. + * This file may be used under the terms of the MIT License.
  2866. + *
  2867. + * Authors:
  2868. + *     Janito V. Ferreira Filho
  2869. + */
  2870. +
  2871. +#include "BlockAllocator.h"
  2872. +
  2873. +#include <util/AutoLock.h>
  2874. +
  2875. +#include "BitmapBlock.h"
  2876. +#include "Inode.h"
  2877. +
  2878. +
  2879. +//#define TRACE_EXT2
  2880. +#ifdef TRACE_EXT2
  2881. +#  define TRACE(x...) dprintf("\33[34mext2:\33[0m " x)
  2882. +#else
  2883. +#  define TRACE(x...) ;
  2884. +#endif
  2885. +
  2886. +
  2887. +class AllocationBlockGroup : public TransactionListener {
  2888. +public:
  2889. +                       AllocationBlockGroup();
  2890. +                       ~AllocationBlockGroup();
  2891. +
  2892. +           status_t    Initialize(Volume* v, uint32 blockGroup);
  2893. +
  2894. +           status_t    ScanFreeRanges();
  2895. +           bool        IsFull() const;
  2896. +
  2897. +           status_t    Allocate(Transaction& transaction, uint32 start,
  2898. +                           uint32 length);
  2899. +           status_t    Free(Transaction& transaction, uint32 start,
  2900. +                           uint32 length);
  2901. +           status_t    FreeAll(Transaction& transaction);
  2902. +           status_t    Check(uint32 start, uint32 length);
  2903. +
  2904. +           uint32      NumBits() const;
  2905. +           uint32      FreeBits() const;
  2906. +           uint32      Start() const;
  2907. +
  2908. +           uint32      LargestStart() const;
  2909. +           uint32      LargestLength() const;
  2910. +
  2911. +           // TransactionListener implementation
  2912. +           void        TransactionDone(bool success);
  2913. +           void        RemovedFromTransaction();
  2914. +
  2915. +private:
  2916. +           void        _AddFreeRange(uint32 start, uint32 length);
  2917. +
  2918. +
  2919. +           Volume*     fVolume;
  2920. +
  2921. +           uint32      fStart;
  2922. +           uint32      fNumBits;
  2923. +           uint32      fBitmapBlock;
  2924. +
  2925. +           uint32      fFreeBits;
  2926. +           uint32      fFirstFree;
  2927. +           uint32      fLargestStart;
  2928. +           uint32      fLargestLength;
  2929. +          
  2930. +           uint32      fPreviousFreeBits;
  2931. +           uint32      fPreviousFirstFree;
  2932. +           uint32      fPreviousLargestStart;
  2933. +           uint32      fPreviousLargestLength;
  2934. +};
  2935. +
  2936. +
  2937. +class BlockAllocatorTransactionListener : public TransactionListener {
  2938. +public:
  2939. +                       BlockAllocatorTransactionListener(
  2940. +                           BlockAllocator* allocator, uint32 blocks);
  2941. +                       ~BlockAllocatorTransactionListener();
  2942. +
  2943. +           void        TransactionDone(bool success);
  2944. +           void        RemovedFromTransaction();
  2945. +private:
  2946. +           BlockAllocator* fAllocator;
  2947. +           uint32      fBlockAffected;
  2948. +};
  2949. +
  2950. +
  2951. +AllocationBlockGroup::AllocationBlockGroup()
  2952. +   :
  2953. +   fStart(0),
  2954. +   fNumBits(0),
  2955. +   fBitmapBlock(0),
  2956. +   fFreeBits(0),
  2957. +   fFirstFree(0),
  2958. +   fLargestStart(0),
  2959. +   fLargestLength(0),
  2960. +   fPreviousFreeBits(0),
  2961. +   fPreviousFirstFree(0),
  2962. +   fPreviousLargestStart(0),
  2963. +   fPreviousLargestLength(0)
  2964. +{
  2965. +}
  2966. +
  2967. +
  2968. +AllocationBlockGroup::~AllocationBlockGroup()
  2969. +{
  2970. +}
  2971. +
  2972. +
  2973. +status_t
  2974. +AllocationBlockGroup::Initialize(Volume* volume, uint32 blockGroup)
  2975. +{
  2976. +   fVolume = volume;
  2977. +
  2978. +   ext2_block_group* group;
  2979. +   status_t status = fVolume->GetBlockGroup(blockGroup, &group);
  2980. +   if (status != B_OK)
  2981. +       return status;
  2982. +
  2983. +   if (blockGroup == volume->NumGroups()) {
  2984. +       fNumBits = volume->NumBlocks() - volume->BlocksPerGroup() * blockGroup
  2985. +           - volume->FirstDataBlock();
  2986. +   } else
  2987. +       fNumBits = fVolume->BlocksPerGroup();
  2988. +
  2989. +   fBitmapBlock = group->BlockBitmap();
  2990. +
  2991. +   status = ScanFreeRanges();
  2992. +
  2993. +   fPreviousFreeBits = fFreeBits;
  2994. +   fPreviousFirstFree = fFirstFree;
  2995. +   fPreviousLargestStart = fLargestStart;
  2996. +   fPreviousLargestLength = fLargestLength;
  2997. +  
  2998. +   return status;
  2999. +}
  3000. +
  3001. +
  3002. +status_t
  3003. +AllocationBlockGroup::ScanFreeRanges()
  3004. +{
  3005. +   BitmapBlock block(fVolume, fNumBits);
  3006. +
  3007. +   if (!block.SetTo(fBitmapBlock))
  3008. +       return B_ERROR;
  3009. +
  3010. +   uint32 start = 0;
  3011. +   uint32 end = 0;
  3012. +
  3013. +   while (end < fNumBits) {
  3014. +       block.FindNextUnmarked(start);
  3015. +       end = start;
  3016. +
  3017. +       if (start != block.NumBits()) {
  3018. +           block.FindNextMarked(end);
  3019. +           _AddFreeRange(start, end);
  3020. +           start = end;
  3021. +       }
  3022. +   }
  3023. +
  3024. +   return B_OK;
  3025. +}
  3026. +
  3027. +
  3028. +bool
  3029. +AllocationBlockGroup::IsFull() const
  3030. +{
  3031. +   return fFreeBits == 0;
  3032. +}
  3033. +
  3034. +
  3035. +status_t
  3036. +AllocationBlockGroup::Allocate(Transaction& transaction, uint32 start,
  3037. +   uint32 length)
  3038. +{
  3039. +   uint32 end = start + length;
  3040. +   if (end > fLargestLength)
  3041. +       return B_BAD_DATA;
  3042. +
  3043. +   BitmapBlock block(fVolume, fNumBits);
  3044. +
  3045. +   if (!block.SetToWritable(transaction, fBitmapBlock))
  3046. +       return B_ERROR;
  3047. +  
  3048. +   if (!block.Mark(start, length)) {
  3049. +       TRACE("Failed to allocate blocks from %lu to %lu. Some were "
  3050. +           "already allocated.\n", start, start + length);
  3051. +       return B_ERROR;
  3052. +   }
  3053. +
  3054. +   transaction.AddListener(this);
  3055. +
  3056. +   fFreeBits -= length;
  3057. +
  3058. +   if (start == fLargestStart) {
  3059. +       if (fFirstFree == fLargestStart)
  3060. +           fFirstFree += length;
  3061. +
  3062. +       fLargestStart += length;
  3063. +       fLargestLength -= length;
  3064. +   } else if (start + length == fLargestStart + fLargestLength) {
  3065. +       fLargestLength -= length;
  3066. +   } else if (start < fLargestStart + fLargestLength
  3067. +           && start > fLargestStart) {
  3068. +       uint32 firstLength = start - fLargestStart;
  3069. +       uint32 secondLength = fLargestStart + fLargestLength
  3070. +           - (start + length);
  3071. +
  3072. +       if (firstLength >= secondLength) {
  3073. +           fLargestLength = firstLength;
  3074. +       } else {
  3075. +           fLargestLength = secondLength;
  3076. +           fLargestStart = start + length;
  3077. +       }
  3078. +   } else {
  3079. +       // No need to revalidate the largest free range
  3080. +       return B_OK;
  3081. +   }
  3082. +
  3083. +   if (fLargestLength < fNumBits / 2)
  3084. +       block.FindLargestUnmarkedRange(fLargestStart, fLargestLength);
  3085. +
  3086. +   return B_OK;
  3087. +}
  3088. +
  3089. +
  3090. +status_t
  3091. +AllocationBlockGroup::Free(Transaction& transaction, uint32 start,
  3092. +   uint32 length)
  3093. +{
  3094. +   uint32 end = start + length;
  3095. +
  3096. +   if (end > fLargestLength)
  3097. +       return B_BAD_DATA;
  3098. +
  3099. +   BitmapBlock block(fVolume, fNumBits);
  3100. +
  3101. +   if (!block.SetToWritable(transaction, fBitmapBlock))
  3102. +       return B_ERROR;
  3103. +
  3104. +   if (!block.Unmark(start, length)) {
  3105. +       TRACE("Failed to free blocks from %lu to %lu. Some were "
  3106. +           "already freed.\n", start, start + length);
  3107. +       return B_ERROR;
  3108. +   }
  3109. +
  3110. +   transaction.AddListener(this);
  3111. +
  3112. +   if (fFirstFree > start)
  3113. +       fFirstFree = start;
  3114. +
  3115. +   if (start + length == fLargestStart) {
  3116. +       fLargestStart = start;
  3117. +       fLargestLength += length;
  3118. +   } else if (start == fLargestStart + fLargestLength) {
  3119. +       fLargestLength += length;
  3120. +   } else if (fLargestLength >= fNumBits / 2) {
  3121. +       // May have merged with some free blocks, becoming the largest
  3122. +       uint32 newEnd = start + length;
  3123. +       block.FindNextMarked(newEnd);
  3124. +
  3125. +       uint32 newStart = start;
  3126. +       block.FindPreviousMarked(newStart);
  3127. +
  3128. +       if (newEnd - newStart > fLargestLength) {
  3129. +           fLargestLength = newEnd - newStart;
  3130. +           fLargestStart = newStart;
  3131. +       }
  3132. +   }
  3133. +
  3134. +   fFreeBits += length;
  3135. +
  3136. +   return B_OK;
  3137. +}
  3138. +
  3139. +
  3140. +status_t
  3141. +AllocationBlockGroup::FreeAll(Transaction& transaction)
  3142. +{
  3143. +   return Free(transaction, 0, fNumBits);
  3144. +}
  3145. +
  3146. +
  3147. +uint32
  3148. +AllocationBlockGroup::NumBits() const
  3149. +{
  3150. +   return fNumBits;
  3151. +}
  3152. +
  3153. +
  3154. +uint32
  3155. +AllocationBlockGroup::FreeBits() const
  3156. +{
  3157. +   return fFreeBits;
  3158. +}
  3159. +
  3160. +
  3161. +uint32
  3162. +AllocationBlockGroup::Start() const
  3163. +{
  3164. +   return fStart;
  3165. +}
  3166. +
  3167. +
  3168. +uint32
  3169. +AllocationBlockGroup::LargestStart() const
  3170. +{
  3171. +   return fLargestStart;
  3172. +}
  3173. +
  3174. +
  3175. +uint32
  3176. +AllocationBlockGroup::LargestLength() const
  3177. +{
  3178. +   return fLargestLength;
  3179. +}
  3180. +
  3181. +
  3182. +void
  3183. +AllocationBlockGroup::_AddFreeRange(uint32 start, uint32 length)
  3184. +{
  3185. +   if (IsFull()) {
  3186. +       fFirstFree = start;
  3187. +       fLargestStart = start;
  3188. +       fLargestLength = length;
  3189. +   } else if (length > fLargestLength) {
  3190. +       fLargestStart = start;
  3191. +       fLargestLength = length;
  3192. +   }
  3193. +
  3194. +   fFreeBits += length;
  3195. +}
  3196. +
  3197. +
  3198. +void
  3199. +AllocationBlockGroup::TransactionDone(bool success)
  3200. +{
  3201. +   if (success) {
  3202. +       fPreviousFreeBits = fFreeBits;
  3203. +       fPreviousFirstFree = fFirstFree;
  3204. +       fPreviousLargestStart = fLargestStart;
  3205. +       fPreviousLargestLength = fLargestLength;
  3206. +   } else {
  3207. +       fFreeBits = fPreviousFreeBits;
  3208. +       fFirstFree = fPreviousFirstFree;
  3209. +       fLargestStart = fPreviousLargestStart;
  3210. +       fLargestLength = fPreviousLargestLength;
  3211. +   }
  3212. +}
  3213. +
  3214. +
  3215. +void
  3216. +AllocationBlockGroup::RemovedFromTransaction()
  3217. +{
  3218. +   // TODO: What to do here?
  3219. +}
  3220. +
  3221. +
  3222. +BlockAllocator::BlockAllocator(Volume* volume)
  3223. +   :
  3224. +   fVolume(volume),
  3225. +   fGroups(NULL),
  3226. +   fBlocksPerGroup(volume->BlocksPerGroup()),
  3227. +   fNumBlocks(0),
  3228. +   fNumGroups(0)
  3229. +{
  3230. +   mutex_init(&fLock, "ext2 block allocator");
  3231. +}
  3232. +
  3233. +
  3234. +BlockAllocator::~BlockAllocator()
  3235. +{
  3236. +   mutex_destroy(&fLock);
  3237. +
  3238. +   if (fGroups != NULL)
  3239. +       delete [] fGroups;
  3240. +}
  3241. +
  3242. +
  3243. +status_t
  3244. +BlockAllocator::Initialize()
  3245. +{
  3246. +   fNumGroups = fVolume->NumGroups();
  3247. +   fFirstBlock = fVolume->FirstDataBlock();
  3248. +
  3249. +   fGroups = new(std::nothrow) AllocationBlockGroup[fNumGroups];
  3250. +   if (fGroups == NULL)
  3251. +       return B_NO_MEMORY;
  3252. +
  3253. +   mutex_lock(&fLock);
  3254. +       // Released by _Initialize
  3255. +
  3256. +   thread_id id = -1; // spawn_kernel_thread(
  3257. +       // (thread_func)BlockAllocator::_Initialize, "ext2 block allocator",
  3258. +       // B_LOW_PRIORITY, this);
  3259. +   if (id < B_OK)
  3260. +       return _Initialize(this);
  3261. +
  3262. +   // mutex_transfer_lock(&fLock, id);
  3263. +
  3264. +   // return resume_thread(id);
  3265. +   panic("Failed to fall back to synchronous block allocator"
  3266. +       "initialization.\n");
  3267. +   return B_ERROR;
  3268. +}
  3269. +
  3270. +
  3271. +status_t
  3272. +BlockAllocator::AllocateBlocks(Transaction& transaction, uint32 minimum,
  3273. +   uint32 maximum, uint32& blockGroup, uint32& start, uint32& length)
  3274. +{
  3275. +   MutexLocker lock(fLock);
  3276. +
  3277. +   uint32 bestStart = 0;
  3278. +   uint32 bestLength = 0;
  3279. +   uint32 bestGroup = 0;
  3280. +
  3281. +   uint32 groupNum = blockGroup;
  3282. +
  3283. +   AllocationBlockGroup* last = &fGroups[fNumGroups];
  3284. +   AllocationBlockGroup* group = &fGroups[blockGroup];
  3285. +
  3286. +   for (int32 iterations = 0; iterations < 2; iterations++) {
  3287. +       for (; group < last; ++group, ++groupNum) {
  3288. +           if (group->LargestLength() > bestLength) {
  3289. +               if (start < group->LargestStart()) {
  3290. +                   bestStart = group->LargestStart();
  3291. +                   bestLength = group->LargestLength();
  3292. +                   bestGroup = groupNum;
  3293. +
  3294. +                   if (bestLength >= maximum)
  3295. +                       break;
  3296. +               }
  3297. +           }
  3298. +
  3299. +           start = 0;
  3300. +       }
  3301. +
  3302. +       if (bestLength >= maximum)
  3303. +           break;
  3304. +
  3305. +       groupNum = 0;
  3306. +
  3307. +       group = &fGroups[0];
  3308. +       last = &fGroups[blockGroup];
  3309. +   }
  3310. +
  3311. +   if (bestLength < minimum)
  3312. +       return B_DEVICE_FULL;
  3313. +
  3314. +   if (bestLength > maximum)
  3315. +       bestLength = maximum;
  3316. +
  3317. +   status_t status = fGroups[bestGroup].Allocate(transaction, bestStart,
  3318. +       bestLength);
  3319. +   if (status != B_OK) {
  3320. +       TRACE("Failed to allocate %lu blocks inside block group %lu.\n",
  3321. +           bestLength, bestGroup);
  3322. +       return status;
  3323. +   }
  3324. +
  3325. +   start = bestStart;
  3326. +   length = bestLength;
  3327. +   blockGroup = bestGroup;
  3328. +
  3329. +   return B_OK;
  3330. +}
  3331. +
  3332. +
  3333. +status_t
  3334. +BlockAllocator::Allocate(Transaction& transaction, Inode* inode,
  3335. +   off_t numBlocks, uint32 minimum, uint32& start, uint32& allocated)
  3336. +{
  3337. +   if (numBlocks <= 0)
  3338. +       return B_ERROR;
  3339. +
  3340. +   uint32 group = inode->ID() / fVolume->InodesPerGroup();
  3341. +   uint32 preferred = 0;
  3342. +
  3343. +   if (inode->Size() > 0) {
  3344. +       // Try to allocate near it's last blocks
  3345. +       ext2_data_stream* dataStream = &inode->Node().stream;
  3346. +       uint32 numBlocks = inode->Size() / fVolume->BlockSize() + 1;
  3347. +       uint32 lastBlock = 0;
  3348. +
  3349. +       // DANGER! What happens with sparse files?
  3350. +       if (numBlocks < EXT2_DIRECT_BLOCKS) {
  3351. +           // Only direct blocks
  3352. +           lastBlock = dataStream->direct[numBlocks];
  3353. +       } else {
  3354. +           numBlocks -= EXT2_DIRECT_BLOCKS - 1;
  3355. +           uint32 numIndexes = fVolume->BlockSize() / 4;
  3356. +               // block size / sizeof(int32)
  3357. +           uint32 numIndexes2 = numIndexes * numIndexes;
  3358. +           uint32 numIndexes3 = numIndexes2 * numIndexes;
  3359. +           uint32 indexesInIndirect = numIndexes;
  3360. +           uint32 indexesInDoubleIndirect = indexesInIndirect
  3361. +               + numIndexes2;
  3362. +           // uint32 indexesInTripleIndirect = indexesInDoubleIndirect
  3363. +               // + numIndexes3;
  3364. +
  3365. +           uint32 doubleIndirectBlock = EXT2_DIRECT_BLOCKS + 1;
  3366. +           uint32 indirectBlock = EXT2_DIRECT_BLOCKS;
  3367. +
  3368. +           CachedBlock cached(fVolume);
  3369. +           uint32* indirectData;
  3370. +
  3371. +           if (numBlocks > indexesInDoubleIndirect) {
  3372. +               // Triple indirect blocks
  3373. +               indirectData = (uint32*)cached.SetTo(EXT2_DIRECT_BLOCKS + 2);
  3374. +               if (indirectData == NULL)
  3375. +                   return B_IO_ERROR;
  3376. +
  3377. +               uint32 index = (numBlocks - indexesInDoubleIndirect)
  3378. +                   / numIndexes3;
  3379. +               doubleIndirectBlock = indirectData[index];
  3380. +           }
  3381. +
  3382. +           if (numBlocks > indexesInIndirect) {
  3383. +               // Double indirect blocks
  3384. +               indirectData = (uint32*)cached.SetTo(doubleIndirectBlock);
  3385. +               if (indirectData == NULL)
  3386. +                   return B_IO_ERROR;
  3387. +
  3388. +               uint32 index = (numBlocks - indexesInIndirect) / numIndexes2;
  3389. +               indirectBlock = indirectData[index];
  3390. +           }
  3391. +
  3392. +           indirectData = (uint32*)cached.SetTo(indirectBlock);
  3393. +               if (indirectData == NULL)
  3394. +                   return B_IO_ERROR;
  3395. +
  3396. +           uint32 index = numBlocks / numIndexes;
  3397. +           lastBlock = indirectData[index];
  3398. +       }
  3399. +
  3400. +       group = (lastBlock - fFirstBlock) / fBlocksPerGroup;
  3401. +       preferred = (lastBlock - fFirstBlock) % fBlocksPerGroup + 1;
  3402. +   }
  3403. +
  3404. +   // TODO: Apply some more policies
  3405. +
  3406. +   return AllocateBlocks(transaction, minimum, minimum + 8, group, start,
  3407. +       allocated);
  3408. +}
  3409. +
  3410. +
  3411. +status_t
  3412. +BlockAllocator::Free(Transaction& transaction, uint32 start, uint32 length)
  3413. +{
  3414. +   MutexLocker lock(fLock);
  3415. +
  3416. +   uint32 group = (start - fFirstBlock) / fBlocksPerGroup;
  3417. +   start = (start - fFirstBlock) % fBlocksPerGroup;
  3418. +   uint32 lastGroup = (start + length - fFirstBlock) / fBlocksPerGroup;
  3419. +
  3420. +   if (group == lastGroup)
  3421. +       return fGroups[group].Free(transaction, start, length);
  3422. +
  3423. +   status_t status = fGroups[group].Free(transaction, start,
  3424. +       fGroups[group].NumBits());
  3425. +   if (status != B_OK)
  3426. +       return status;
  3427. +
  3428. +   for (++group; group < lastGroup; ++group) {
  3429. +       status = fGroups[group].FreeAll(transaction);
  3430. +       if (status != B_OK)
  3431. +           return status;
  3432. +   }
  3433. +
  3434. +   return fGroups[group].Free(transaction, 0, (start + length - fFirstBlock)
  3435. +       % fBlocksPerGroup);
  3436. +}
  3437. +
  3438. +
  3439. +/*static*/ status_t
  3440. +BlockAllocator::_Initialize(BlockAllocator* allocator)
  3441. +{
  3442. +   // fLock is already heald
  3443. +   Volume* volume = allocator->fVolume;
  3444. +
  3445. +   AllocationBlockGroup* groups = allocator->fGroups;
  3446. +   uint32 numGroups = allocator->fNumGroups;
  3447. +
  3448. +   uint32 freeBlocks = 0;
  3449. +
  3450. +   for (uint32 i = 0; i < numGroups; ++i) {
  3451. +       status_t status = groups[i].Initialize(volume, i);
  3452. +       if (status != B_OK) {
  3453. +           mutex_unlock(&allocator->fLock);
  3454. +           return status;
  3455. +       }
  3456. +
  3457. +       freeBlocks += groups[i].FreeBits();
  3458. +   }
  3459. +
  3460. +   mutex_unlock(&allocator->fLock);
  3461. +
  3462. +   if (freeBlocks != volume->FreeBlocks()) {
  3463. +       TRACE("Counted free blocks doesn't match value in the superblock.\n");
  3464. +       return B_BAD_DATA;
  3465. +   }
  3466. +
  3467. +   return B_OK;
  3468. +}
  3469.  
  3470. Property changes on: src/add-ons/kernel/file_systems/ext2/BlockAllocator.cpp
  3471. ___________________________________________________________________
  3472. Added: svn:executable
  3473.    + *
  3474.  
  3475. Index: src/add-ons/kernel/file_systems/ext2/Inode.cpp
  3476. ===================================================================
  3477. --- src/add-ons/kernel/file_systems/ext2/Inode.cpp  (revision 37486)
  3478. +++ src/add-ons/kernel/file_systems/ext2/Inode.cpp  (working copy)
  3479. @@ -8,6 +8,7 @@
  3480.  
  3481.  #include <fs_cache.h>
  3482.  #include <string.h>
  3483. +#include <util/AutoLock.h>
  3484.  
  3485.  #include "CachedBlock.h"
  3486.  
  3487. @@ -26,56 +27,106 @@
  3488.     fID(id),
  3489.     fCache(NULL),
  3490.     fMap(NULL),
  3491. -   fNode(NULL),
  3492.     fAttributesBlock(NULL)
  3493.  {
  3494.     rw_lock_init(&fLock, "ext2 inode");
  3495.  
  3496.     uint32 block;
  3497. -   if (volume->GetInodeBlock(id, block) == B_OK) {
  3498. -       TRACE("inode %Ld at block %lu\n", ID(), block);
  3499. -       uint8* inodeBlock = (uint8*)block_cache_get(volume->BlockCache(),
  3500. -           block);
  3501. +   fInitStatus = volume->GetInodeBlock(id, block);
  3502. +   if (fInitStatus == B_OK) {
  3503. +       TRACE("inode %Ld at block %lu\n", id, block);
  3504. +
  3505. +       CachedBlock cached(volume);
  3506. +       const uint8* inodeBlock = cached.SetTo(block);
  3507. +       TRACE("Inode table block in memory: %p\n", inodeBlock);
  3508. +      
  3509. +
  3510.         if (inodeBlock != NULL) {
  3511. -           fNode = (ext2_inode*)(inodeBlock + volume->InodeBlockIndex(id)
  3512. -               * volume->InodeSize());
  3513. -       }
  3514. +           TRACE("Inode size: %lu, inode index: %lu\n", volume->InodeSize(),
  3515. +               volume->InodeBlockIndex(id));
  3516. +           ext2_inode* inode = (ext2_inode*)(inodeBlock
  3517. +               + volume->InodeBlockIndex(id) * volume->InodeSize());
  3518. +          
  3519. +           fNodeSize = sizeof(ext2_inode) > volume->InodeSize()
  3520. +               ? volume->InodeSize() : sizeof(ext2_inode);
  3521. +          
  3522. +           TRACE("Attempting to copy inode data from %p to %p, ext2_inode "
  3523. +               "size: %lu\n", inode, &fNode, fNodeSize);
  3524. +          
  3525. +           memcpy(&fNode, inode, fNodeSize);
  3526. +       } else
  3527. +           fInitStatus = B_IO_ERROR;
  3528.     }
  3529.  
  3530. -   if (fNode != NULL) {
  3531. -       // TODO: we don't need a cache for short symlinks
  3532. +   if (fInitStatus == B_OK) {
  3533.         fCache = file_cache_create(fVolume->ID(), ID(), Size());
  3534.         fMap = file_map_create(fVolume->ID(), ID(), Size());
  3535. +       fCached = true;
  3536. +
  3537. +       if (fCache == NULL || Size() == 0 || IsDirectory() || (IsSymLink()
  3538. +               && Size() < 60)) {
  3539. +           fInitStatus = DisableFileCache();
  3540. +       } else
  3541. +           fInitStatus = B_OK;
  3542. +   } else {
  3543. +       TRACE("Inode: Failed initialization\n");
  3544. +       fCached = false;
  3545.     }
  3546.  }
  3547.  
  3548.  
  3549.  Inode::~Inode()
  3550.  {
  3551. -   file_cache_delete(FileCache());
  3552. -   file_map_delete(Map());
  3553. +   TRACE("Inode destructor\n");
  3554.  
  3555. +   if (fCache != NULL) {
  3556. +       TRACE("Deleting the file cache and file map\n");
  3557. +       file_cache_delete(FileCache());
  3558. +       file_map_delete(Map());
  3559. +   }
  3560. +
  3561.     if (fAttributesBlock) {
  3562. +       TRACE("Returning the attributes block\n");
  3563.         uint32 block = B_LENDIAN_TO_HOST_INT32(Node().file_access_control);
  3564.         block_cache_put(fVolume->BlockCache(), block);
  3565.     }
  3566.  
  3567. -   if (fNode != NULL) {
  3568. -       uint32 block;
  3569. -       if (fVolume->GetInodeBlock(ID(), block) == B_OK)
  3570. -           block_cache_put(fVolume->BlockCache(), block);
  3571. -   }
  3572. +   TRACE("Inode destructor: Done\n");
  3573.  }
  3574.  
  3575.  
  3576.  status_t
  3577.  Inode::InitCheck()
  3578.  {
  3579. -   return fNode != NULL ? B_OK : B_ERROR;
  3580. +   return fInitStatus;
  3581.  }
  3582.  
  3583.  
  3584.  status_t
  3585. +Inode::WriteBack(Transaction& transaction)
  3586. +{
  3587. +   WriteLocker lock(fLock);
  3588. +
  3589. +   uint32 inodeBlock;
  3590. +
  3591. +   status_t status = fVolume->GetInodeBlock(fID, inodeBlock);
  3592. +   if (status != B_OK)
  3593. +       return status;
  3594. +
  3595. +   CachedBlock cached(fVolume);
  3596. +   uint8* inodeBlockData = cached.SetToWritable(transaction, inodeBlock);
  3597. +   if (inodeBlockData == NULL)
  3598. +       return B_IO_ERROR;
  3599. +
  3600. +   memcpy(inodeBlockData +
  3601. +           fVolume->InodeBlockIndex(fID) * fVolume->InodeSize(),
  3602. +       (uint8*)&fNode, fNodeSize);
  3603. +
  3604. +   return B_OK;
  3605. +}
  3606. +
  3607. +
  3608. +status_t
  3609.  Inode::CheckPermissions(int accessMode) const
  3610.  {
  3611.     uid_t user = geteuid();
  3612. @@ -95,9 +146,9 @@
  3613.  
  3614.     // shift mode bits, to check directly against accessMode
  3615.     mode_t mode = Mode();
  3616. -   if (user == (uid_t)fNode->UserID())
  3617. +   if (user == (uid_t)fNode.UserID())
  3618.         mode >>= 6;
  3619. -   else if (group == (gid_t)fNode->GroupID())
  3620. +   else if (group == (gid_t)fNode.GroupID())
  3621.         mode >>= 3;
  3622.  
  3623.     if (accessMode & ~(mode & S_IRWXO))
  3624. @@ -114,8 +165,10 @@
  3625.     uint32 perIndirectBlock = perBlock * perBlock;
  3626.     uint32 index = offset >> fVolume->BlockShift();
  3627.  
  3628. -   if (offset >= Size())
  3629. +   if (offset >= Size()) {
  3630. +       TRACE("FindBlock: offset larger than inode size\n");
  3631.         return B_ENTRY_NOT_FOUND;
  3632. +   }
  3633.  
  3634.     // TODO: we could return the size of the sparse range, as this might be more
  3635.     // than just a block
  3636. @@ -203,7 +256,8 @@
  3637.  
  3638.     // set/check boundaries for pos/length
  3639.     if (pos < 0) {
  3640. -       TRACE("inode %Ld: ReadAt failed(pos %Ld, length %lu)\n", ID(), pos, length);
  3641. +       TRACE("inode %Ld: ReadAt failed(pos %Ld, length %lu)\n", ID(), pos,
  3642. +           length);
  3643.         return B_BAD_VALUE;
  3644.     }
  3645.  
  3646. @@ -245,3 +299,38 @@
  3647.     *_length = length;
  3648.     return B_NO_ERROR;
  3649.  }
  3650. +
  3651. +
  3652. +/*static*/ status_t
  3653. +Inode::Create(Transaction& transaction, Inode* parent, const char* name,
  3654. +   int32 mode, int openMode, uint32 type, bool* _created, ino_t* _id,
  3655. +   Inode** _inode, fs_vnode_ops* vnodeOps, uint32 publishFlags)
  3656. +{
  3657. +   //DirectoryIterator* entries = NULL;
  3658. +
  3659. +   if (parent != NULL) {
  3660. +   }
  3661. +
  3662. +   return B_OK;
  3663. +}
  3664. +
  3665. +
  3666. +status_t
  3667. +Inode::DisableFileCache()
  3668. +{
  3669. +   TRACE("Inode::DisableFileCache()\n");
  3670. +
  3671. +   if (fCache == NULL) {
  3672. +       fCached = false;
  3673. +       return B_OK;
  3674. +   }
  3675. +
  3676. +   status_t status = file_cache_disable(fCache);
  3677. +
  3678. +   if (status == B_OK)
  3679. +       fCached = false;
  3680. +   else
  3681. +       TRACE("Inode: Failed to disable the file cache\n");
  3682. +
  3683. +   return B_OK;
  3684. +}
  3685. Index: src/add-ons/kernel/file_systems/ext2/HashRevokeManager.h
  3686. ===================================================================
  3687. --- src/add-ons/kernel/file_systems/ext2/HashRevokeManager.h    (revision 0)
  3688. +++ src/add-ons/kernel/file_systems/ext2/HashRevokeManager.h    (revision 0)
  3689. @@ -0,0 +1,47 @@
  3690. +/*
  3691. + * Copyright 2001-2010, Haiku Inc. All rights reserved.
  3692. + * This file may be used under the terms of the MIT License.
  3693. + *
  3694. + * Authors:
  3695. + *     Janito V. Ferreira Filho
  3696. + */
  3697. +#ifndef HASHREVOKEMANAGER_H
  3698. +#define HASHREVOKEMANAGER_H
  3699. +
  3700. +#include <util/khash.h>
  3701. +
  3702. +#include "RevokeManager.h"
  3703. +
  3704. +
  3705. +struct RevokeElement {
  3706. +   RevokeElement*  next;   // Next in hash
  3707. +   uint32          block;
  3708. +   uint32          commitID;
  3709. +};
  3710. +
  3711. +
  3712. +class HashRevokeManager : public RevokeManager {
  3713. +public:
  3714. +                       HashRevokeManager();
  3715. +   virtual             ~HashRevokeManager();
  3716. +
  3717. +           status_t    Init();
  3718. +
  3719. +   virtual status_t    Insert(uint32 block, uint32 commitID);
  3720. +   virtual status_t    Remove(uint32 block);
  3721. +   virtual bool        Lookup(uint32 block, uint32 commitID);
  3722. +          
  3723. +   static  int         Compare(void* element, const void* key);
  3724. +   static  uint32      Hash(void* element, const void* key, uint32 range);
  3725. +
  3726. +protected:
  3727. +           status_t    _ForceInsert(uint32 block, uint32 commitID);
  3728. +
  3729. +private:
  3730. +           hash_table* fHash;
  3731. +
  3732. +   const   int         kInitialHashSize;
  3733. +};
  3734. +
  3735. +#endif // HASHREVOKEMANAGER_H
  3736. +
  3737.  
  3738. Property changes on: src/add-ons/kernel/file_systems/ext2/HashRevokeManager.h
  3739. ___________________________________________________________________
  3740. Added: svn:executable
  3741.    + *
  3742.  
  3743. Index: src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp
  3744. ===================================================================
  3745. --- src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp   (revision 37486)
  3746. +++ src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp   (working copy)
  3747. @@ -13,6 +13,7 @@
  3748.  #include <fs_info.h>
  3749.  
  3750.  #include "AttributeIterator.h"
  3751. +#include "CachedBlock.h"
  3752.  #include "DirectoryIterator.h"
  3753.  #include "ext2.h"
  3754.  #include "HTree.h"
  3755. @@ -116,6 +117,7 @@
  3756.  
  3757.     status_t status = volume->Mount(device, flags);
  3758.     if (status != B_OK) {
  3759. +       TRACE("Failed mounting the volume. Error: %s\n", strerror(status));
  3760.         delete volume;
  3761.         return status;
  3762.     }
  3763. @@ -339,12 +341,52 @@
  3764.         if (!strcmp(buffer, name))
  3765.             break;
  3766.     }
  3767. -
  3768. +  
  3769.     return get_vnode(volume->FSVolume(), *_vnodeID, NULL);
  3770.  }
  3771.  
  3772.  
  3773.  static status_t
  3774. +ext2_ioctl(fs_volume* _volume, fs_vnode* _node, void* _cookie, uint32 cmd,
  3775. +   void* buffer, size_t bufferLength)
  3776. +{
  3777. +   Volume* volume = (Volume*)_volume->private_volume;
  3778. +   switch (cmd) {
  3779. +       case 56742:
  3780. +       {
  3781. +           // Test the block allocator
  3782. +           Transaction transaction(volume->GetJournal());
  3783. +           CachedBlock cached(volume);
  3784. +           uint32 blocksPerGroup = volume->BlocksPerGroup();
  3785. +           uint32 blockSize  = volume->BlockSize();
  3786. +           uint32 firstBlock = volume->FirstDataBlock();
  3787. +           uint32 start = 0;
  3788. +           uint32 group = 0;
  3789. +           uint32 length;
  3790. +
  3791. +           TRACE("Attempting to test the ext3 block allocator.\n");
  3792. +
  3793. +           while (volume->AllocateBlocks(transaction, 1, 64, group, start,
  3794. +                   length) == B_OK) {
  3795. +               TRACE("Allocated blocks %lu-%lu\n", start, length);
  3796. +               uint32 blockNum = start + group * blocksPerGroup - firstBlock;
  3797. +
  3798. +               for (uint32 i = 0; i < length; ++i) {
  3799. +                   uint8* block = cached.SetToWritable(transaction, blockNum);
  3800. +                   memset(block, 0, blockSize);
  3801. +                   blockNum++;
  3802. +               }
  3803. +           }
  3804. +
  3805. +           return B_OK;
  3806. +       }
  3807. +   }
  3808. +
  3809. +   return B_OK;
  3810. +}
  3811. +
  3812. +
  3813. +static status_t
  3814.  ext2_read_stat(fs_volume* _volume, fs_vnode* _node, struct stat* stat)
  3815.  {
  3816.     Inode* inode = (Inode*)_node->private_node;
  3817. @@ -748,8 +790,8 @@
  3818.  
  3819.     &ext2_get_file_map,
  3820.  
  3821. +   &ext2_ioctl,
  3822.     NULL,
  3823. -   NULL,
  3824.     NULL,   // fs_select
  3825.     NULL,   // fs_deselect
  3826.     NULL,
  3827. Index: src/add-ons/kernel/file_systems/ext2/InodeAllocator.h
  3828. ===================================================================
  3829. --- src/add-ons/kernel/file_systems/ext2/InodeAllocator.h   (revision 0)
  3830. +++ src/add-ons/kernel/file_systems/ext2/InodeAllocator.h   (revision 0)
  3831. @@ -0,0 +1,37 @@
  3832. +/*
  3833. + * Copyright 2001-2010, Haiku Inc. All rights reserved.
  3834. + * This file may be used under the terms of the MIT License.
  3835. + *
  3836. + * Authors:
  3837. + *     Janito V. Ferreira Filho
  3838. + */
  3839. +#ifndef INODEALLOCATOR_H
  3840. +#define INODEALLOCATOR_H
  3841. +
  3842. +#include <lock.h>
  3843. +
  3844. +#include "Transaction.h"
  3845. +
  3846. +
  3847. +class Volume;
  3848. +
  3849. +
  3850. +class InodeAllocator {
  3851. +public:
  3852. +                       InodeAllocator(Volume* volume);
  3853. +                       ~InodeAllocator();
  3854. +
  3855. +           status_t    New(Transaction& transaction,
  3856. +                           uint32 prefferedBlockGroup, ino_t& id);
  3857. +
  3858. +private:
  3859. +           status_t    _MarkInBitmap(Transaction& transaction,
  3860. +                           uint32 bitmapBlock, uint32 blockGroup,
  3861. +                           uint32 numInodes, ino_t& id);
  3862. +
  3863. +
  3864. +           Volume*     fVolume;
  3865. +           mutex       fLock;
  3866. +};
  3867. +
  3868. +#endif // INODEALLOCATOR_H
  3869.  
  3870. Property changes on: src/add-ons/kernel/file_systems/ext2/InodeAllocator.h
  3871. ___________________________________________________________________
  3872. Added: svn:executable
  3873.    + *
  3874.  
  3875. Index: src/add-ons/kernel/file_systems/ext2/NoJournal.cpp
  3876. ===================================================================
  3877. --- src/add-ons/kernel/file_systems/ext2/NoJournal.cpp  (revision 0)
  3878. +++ src/add-ons/kernel/file_systems/ext2/NoJournal.cpp  (revision 0)
  3879. @@ -0,0 +1,76 @@
  3880. +/*
  3881. + * Copyright 2001-2010, Haiku Inc. All rights reserved.
  3882. + * This file may be used under the terms of the MIT License.
  3883. + *
  3884. + * Authors:
  3885. + *     Janito V. Ferreira Filho
  3886. + */
  3887. +
  3888. +#include "NoJournal.h"
  3889. +
  3890. +#include <fs_cache.h>
  3891. +
  3892. +
  3893. +//#define TRACE_EXT2
  3894. +#ifdef TRACE_EXT2
  3895. +#  define TRACE(x...) dprintf("\33[34mext2:\33[0m " x)
  3896. +#else
  3897. +#  define TRACE(x...) ;
  3898. +#endif
  3899. +
  3900. +
  3901. +NoJournal::NoJournal(Volume* volume)
  3902. +   :
  3903. +   Journal()
  3904. +{
  3905. +   fFilesystemVolume = volume;
  3906. +   fFilesystemBlockCache = volume->BlockCache();
  3907. +   fJournalVolume = volume;
  3908. +   fHasSubTransaction = false;
  3909. +   fSeparateSubTransactions = false;
  3910. +}
  3911. +
  3912. +
  3913. +NoJournal::~NoJournal()
  3914. +{
  3915. +}
  3916. +
  3917. +
  3918. +status_t
  3919. +NoJournal::InitCheck()
  3920. +{
  3921. +   return B_OK;
  3922. +}
  3923. +
  3924. +
  3925. +status_t
  3926. +NoJournal::Recover()
  3927. +{
  3928. +   return B_OK;
  3929. +}
  3930. +
  3931. +
  3932. +status_t
  3933. +NoJournal::StartLog()
  3934. +{
  3935. +   return B_OK;
  3936. +}
  3937. +
  3938. +
  3939. +status_t
  3940. +NoJournal::_WriteTransactionToLog()
  3941. +{
  3942. +   TRACE("Ending transaction %ld\n", fTransactionID);
  3943. +
  3944. +   fTransactionID = cache_end_transaction(fFilesystemBlockCache,
  3945. +       fTransactionID, _TransactionWritten, NULL);
  3946. +  
  3947. +   return B_OK;
  3948. +}
  3949. +
  3950. +
  3951. +/*static*/ void
  3952. +NoJournal::_TransactionWritten(int32 transactionID, int32 event, void* param)
  3953. +{
  3954. +   TRACE("Transaction %ld checkpointed\n", transactionID);
  3955. +}
  3956. Index: src/add-ons/kernel/file_systems/ext2/HTree.cpp
  3957. ===================================================================
  3958. --- src/add-ons/kernel/file_systems/ext2/HTree.cpp  (revision 37486)
  3959. +++ src/add-ons/kernel/file_systems/ext2/HTree.cpp  (working copy)
  3960. @@ -7,6 +7,7 @@
  3961.   */
  3962.  
  3963.  
  3964. +#include "CachedBlock.h"
  3965.  #include "HTree.h"
  3966.  
  3967.  #include <new>
  3968. @@ -75,54 +76,68 @@
  3969.  
  3970.  HTree::~HTree()
  3971.  {
  3972. +   delete fRootEntry;
  3973.  }
  3974.  
  3975.  
  3976.  status_t
  3977.  HTree::Lookup(const char* name, DirectoryIterator** iterator)
  3978.  {
  3979. +   TRACE("HTree::Lookup()\n");
  3980.     if (!fIndexed || (name[0] == '.'
  3981.         && (name[1] == '\0' || (name[1] == '.' && name[2] == '0')))) {
  3982.         // No HTree support or looking for trivial directories
  3983.         // TODO: Does these directories get hashed?
  3984.         *iterator = new(std::nothrow) DirectoryIterator(fDirectory);
  3985. +       TRACE("HTree::Lookup(): Falling back to linear iteration\n");
  3986.        
  3987.         if (*iterator == NULL)
  3988.             return B_NO_MEMORY;
  3989.         return B_OK;
  3990.     }
  3991.    
  3992. -   HTreeRoot root;
  3993. -   size_t length = sizeof(root);
  3994. +   uint32 blockNum;
  3995. +   status_t status = fDirectory->FindBlock(0, blockNum);
  3996. +   if (status != B_OK) {
  3997. +       *iterator = new(std::nothrow) DirectoryIterator(fDirectory);
  3998. +       TRACE("HTree::Lookup(): Failed to read block in diretory\n");
  3999. +      
  4000. +       if (*iterator == NULL)
  4001. +           return B_NO_MEMORY;
  4002. +       return B_OK;
  4003. +   }
  4004. +
  4005. +   CachedBlock cached(fDirectory->GetVolume());
  4006. +   const uint8* block = cached.SetTo(blockNum);
  4007. +
  4008. +   HTreeRoot* root = (HTreeRoot*)block;
  4009.    
  4010. -   status_t status = fDirectory->ReadAt(0, (uint8*)&root, &length);
  4011. -   if (status < B_OK)
  4012. -       return status;
  4013. -  
  4014. -   if (length != sizeof(root) || !root.IsValid()) {
  4015. +   if (!root->IsValid()) {
  4016.         // Fallback to linear search
  4017.         *iterator = new(std::nothrow) DirectoryIterator(fDirectory);
  4018. +       TRACE("HTree::Lookup(): Invalide root node\n");
  4019.         if (*iterator == NULL)
  4020.             return B_NO_MEMORY;
  4021.        
  4022.         return B_OK;
  4023.     }
  4024.    
  4025. -   uint32 hash = _Hash(name, root.hash_version);
  4026. +   uint32 hash = _Hash(name, root->hash_version);
  4027.    
  4028. -   off_t start = (off_t)root.root_info_length
  4029. +   off_t start = (off_t)root->root_info_length
  4030.         + 2 * (sizeof(HTreeFakeDirEntry) + 4);
  4031.  
  4032. +   delete fRootEntry;
  4033. +
  4034.     fRootEntry = new(std::nothrow) HTreeEntryIterator(start, fDirectory);
  4035.     if (fRootEntry == NULL)
  4036.         return B_NO_MEMORY;
  4037.    
  4038. -   fRootDeleter.SetTo(fRootEntry);
  4039.     status = fRootEntry->Init();
  4040.     if (status != B_OK)
  4041.         return status;
  4042.    
  4043. -   return fRootEntry->Lookup(hash, (uint32)root.indirection_levels, iterator);
  4044. +   return fRootEntry->Lookup(hash, (uint32)root->indirection_levels, iterator);
  4045.  }
  4046.  
  4047.  
  4048. @@ -146,7 +161,7 @@
  4049.             hash = 0;
  4050.     };
  4051.  
  4052. -   TRACE("Filename hash: %u\n", hash);
  4053. +   TRACE("Filename hash: 0x%lX\n", hash);
  4054.    
  4055.     return hash & ~1;
  4056.  }
  4057. @@ -155,6 +170,7 @@
  4058.  uint32
  4059.  HTree::_HashLegacy(const char* name)
  4060.  {
  4061. +   TRACE("HTree::_HashLegacy()\n");
  4062.     uint32 hash = 0x12a3fe2d;
  4063.     uint32 previous = 0x37abe8f9;
  4064.    
  4065. @@ -269,6 +285,7 @@
  4066.  uint32
  4067.  HTree::_HashHalfMD4(const char* name)
  4068.  {
  4069. +   TRACE("HTree::_HashHalfMD4()\n");
  4070.     uint32 buffer[4];
  4071.  
  4072.     buffer[0] = fHashSeed[0];
  4073. @@ -318,6 +335,7 @@
  4074.  uint32
  4075.  HTree::_HashTEA(const char* name)
  4076.  {
  4077. +   TRACE("HTree::_HashTEA()\n");
  4078.     uint32 buffer[4];
  4079.  
  4080.     buffer[0] = fHashSeed[0];
  4081. @@ -354,7 +372,7 @@
  4082.     int completeIterations = length / 4;
  4083.    
  4084.     for (int i = 0; i < completeIterations; ++i) {
  4085. -       uint32 value = 0 | *(string++);
  4086. +       uint32 value = (padding << 8) | *(string++);
  4087.         value = (value << 8) | *(string++);
  4088.         value = (value << 8) | *(string++);
  4089.         value = (value << 8) | *(string++);
  4090.  
  4091. Property changes on: src/add-ons/kernel/file_systems/ext2/HTree.cpp
  4092. ___________________________________________________________________
  4093. Added: svn:executable
  4094.    + *
  4095.  
  4096. Index: src/add-ons/kernel/file_systems/ext2/HTreeEntryIterator.h
  4097. ===================================================================
  4098. --- src/add-ons/kernel/file_systems/ext2/HTreeEntryIterator.h   (revision 37486)
  4099. +++ src/add-ons/kernel/file_systems/ext2/HTreeEntryIterator.h   (working copy)
  4100. @@ -26,7 +26,7 @@
  4101.                                     DirectoryIterator** iterator);
  4102.             bool                HasCollision() { return fHasCollision; }
  4103.                        
  4104. -           status_t            GetNext(off_t& offset);
  4105. +           status_t            GetNext(uint32& offset);
  4106.  private:
  4107.                                 HTreeEntryIterator(uint32 block,
  4108.                                     uint32 blockSize, Inode* directory,
  4109. @@ -34,17 +34,19 @@
  4110.                                     bool hasCollision);
  4111.  
  4112.  private:
  4113. +           Inode*              fDirectory;
  4114. +           Volume*             fVolume;
  4115. +           status_t            fInitStatus;
  4116. +
  4117.             bool                fHasCollision;
  4118.             uint16              fLimit, fCount;
  4119. +           uint16              fCurrentEntry;
  4120.  
  4121.             uint32              fBlockSize;
  4122. -           Inode*              fDirectory;
  4123. -           off_t               fOffset;
  4124. -           off_t               fMaxOffset;
  4125. +           uint32              fBlockNum;
  4126.  
  4127.             HTreeEntryIterator* fParent;
  4128.             HTreeEntryIterator* fChild;
  4129. -           ObjectDeleter<HTreeEntryIterator> fChildDeleter;
  4130.  };
  4131.  
  4132.  #endif // HTREE_ENTRY_ITERATOR_H
  4133. Index: src/add-ons/kernel/file_systems/ext2/Volume.h
  4134. ===================================================================
  4135. --- src/add-ons/kernel/file_systems/ext2/Volume.h   (revision 37486)
  4136. +++ src/add-ons/kernel/file_systems/ext2/Volume.h   (working copy)
  4137. @@ -9,8 +9,12 @@
  4138.  #include <lock.h>
  4139.  
  4140.  #include "ext2.h"
  4141. +#include "BlockAllocator.h"
  4142. +#include "InodeAllocator.h"
  4143. +#include "Transaction.h"
  4144.  
  4145.  class Inode;
  4146. +class Journal;
  4147.  
  4148.  
  4149.  enum volume_flags {
  4150. @@ -18,7 +22,7 @@
  4151.  };
  4152.  
  4153.  
  4154. -class Volume {
  4155. +class Volume : public TransactionListener {
  4156.  public:
  4157.                                 Volume(fs_volume* volume);
  4158.                                 ~Volume();
  4159. @@ -40,30 +44,58 @@
  4160.  
  4161.             uint32              NumInodes() const
  4162.                                     { return fNumInodes; }
  4163. +           uint32              NumGroups() const
  4164. +                                   { return fNumGroups; }
  4165.             off_t               NumBlocks() const
  4166.                                     { return fSuperBlock.NumBlocks(); }
  4167.             off_t               FreeBlocks() const
  4168.                                     { return fSuperBlock.FreeBlocks(); }
  4169. +           uint32              FirstDataBlock() const
  4170. +                                   { return fFirstDataBlock; }
  4171.  
  4172.             uint32              BlockSize() const { return fBlockSize; }
  4173.             uint32              BlockShift() const { return fBlockShift; }
  4174. +           uint32              BlocksPerGroup() const
  4175. +                                   { return fSuperBlock.BlocksPerGroup(); }
  4176.             uint32              InodeSize() const
  4177.                                     { return fSuperBlock.InodeSize(); }
  4178. +           uint32              InodesPerGroup() const
  4179. +                                   { return fSuperBlock.InodesPerGroup(); }
  4180.             ext2_super_block&   SuperBlock() { return fSuperBlock; }
  4181.  
  4182.             status_t            GetInodeBlock(ino_t id, uint32& block);
  4183.             uint32              InodeBlockIndex(ino_t id) const;
  4184.             status_t            GetBlockGroup(int32 index,
  4185.                                     ext2_block_group** _group);
  4186. -          
  4187. +
  4188. +           Journal*            GetJournal() { return fJournal; }
  4189. +
  4190.             bool                IndexedDirectories() const
  4191.                                     { return (fSuperBlock.CompatibleFeatures()
  4192.                                         & EXT2_FEATURE_DIRECTORY_INDEX) != 0; }
  4193.  
  4194. +           status_t            AllocateInode(Transaction& transaction,
  4195. +                                   uint32 preferredBlockGroup, ino_t& id);
  4196. +
  4197. +           status_t            AllocateBlocks(Transaction& transaction,
  4198. +                                   uint32 blockGroup, uint32 minimum,
  4199. +                                   uint32 maximum, uint32& start,
  4200. +                                   uint32& length);
  4201. +
  4202. +           status_t            LoadSuperBlock();
  4203. +           status_t            WriteSuperBlock(Transaction& transaction);
  4204. +
  4205.             // cache access
  4206.             void*               BlockCache() { return fBlockCache; }
  4207.  
  4208. +           status_t            FlushDevice();
  4209. +           status_t            Sync();
  4210. +  
  4211.     static  status_t            Identify(int fd, ext2_super_block* superBlock);
  4212. +          
  4213. +           // TransactionListener functions
  4214. +           void                TransactionDone(bool success);
  4215. +           void                RemovedFromTransaction();
  4216.  
  4217.  private:
  4218.     static  uint32              _UnsupportedIncompatibleFeatures(
  4219. @@ -76,12 +108,21 @@
  4220.             int                 fDevice;
  4221.             ext2_super_block    fSuperBlock;
  4222.             char                fName[32];
  4223. +
  4224. +           BlockAllocator      fBlockAllocator;
  4225. +           InodeAllocator      fInodeAllocator;
  4226. +           Journal*            fJournal;
  4227. +           Inode*              fJournalInode;
  4228. +
  4229.             uint32              fFlags;
  4230.             uint32              fBlockSize;
  4231.             uint32              fBlockShift;
  4232.             uint32              fFirstDataBlock;
  4233. +
  4234.             uint32              fNumInodes;
  4235.             uint32              fNumGroups;
  4236. +           uint32              fFreeBlocks;
  4237. +           uint32              fFreeInodes;
  4238.             uint32              fGroupsPerBlock;
  4239.             ext2_block_group**  fGroupBlocks;
  4240.             uint32              fInodesPerBlock;
  4241. Index: src/add-ons/kernel/file_systems/ext2/DirectoryIterator.cpp
  4242. ===================================================================
  4243. --- src/add-ons/kernel/file_systems/ext2/DirectoryIterator.cpp  (revision 37486)
  4244. +++ src/add-ons/kernel/file_systems/ext2/DirectoryIterator.cpp  (working copy)
  4245. @@ -8,6 +8,7 @@
  4246.  
  4247.  #include <string.h>
  4248.  
  4249. +#include "CachedBlock.h"
  4250.  #include "HTree.h"
  4251.  #include "Inode.h"
  4252.  
  4253. @@ -23,7 +24,9 @@
  4254.  DirectoryIterator::DirectoryIterator(Inode* inode)
  4255.     :
  4256.     fInode(inode),
  4257. -   fOffset(0)
  4258. +   fBlock(0),
  4259. +   fDisplacement(0),
  4260. +   fBlockSize(inode->GetVolume()->BlockSize())
  4261.  {
  4262.  }
  4263.  
  4264. @@ -34,60 +37,129 @@
  4265.  
  4266.  
  4267.  status_t
  4268. +DirectoryIterator::InitCheck()
  4269. +{
  4270. +   return B_OK;
  4271. +}
  4272. +
  4273. +
  4274. +status_t
  4275.  DirectoryIterator::GetNext(char* name, size_t* _nameLength, ino_t* _id)
  4276.  {
  4277. -   if (fOffset + sizeof(ext2_dir_entry) >= fInode->Size()) {
  4278. +   if (fDisplacement + sizeof(ext2_dir_entry) >= fInode->Size()) {
  4279.         TRACE("DirectoryIterator::GetNext() out of entries\n");
  4280.         return B_ENTRY_NOT_FOUND;
  4281.     }
  4282.  
  4283. -   ext2_dir_entry entry;
  4284. +   CachedBlock cached(fInode->GetVolume());
  4285. +   ext2_dir_entry* entry;
  4286. +   uint32 physicalBlock;
  4287.  
  4288. -   while (true) {
  4289. -       size_t length = ext2_dir_entry::MinimumSize();
  4290. -       status_t status = fInode->ReadAt(fOffset, (uint8*)&entry, &length);
  4291. -       if (status != B_OK)
  4292. -           return status;
  4293. -       if (length < ext2_dir_entry::MinimumSize() || entry.Length() == 0)
  4294. +   status_t status = fInode->FindBlock(fBlock * fBlockSize, physicalBlock);
  4295. +   if (status != B_OK)
  4296. +       return status;
  4297. +
  4298. +   const uint8* block = cached.SetTo(physicalBlock);
  4299. +   if (block == NULL)
  4300. +       return B_IO_ERROR;
  4301. +
  4302. +   bool gotEntry = false;
  4303. +   while (!gotEntry) {
  4304. +       TRACE("Checking entry at block %lu, displacement %lu\n", physicalBlock,
  4305. +           fDisplacement);
  4306. +
  4307. +       entry = (ext2_dir_entry*)(block + fDisplacement);
  4308. +
  4309. +       if (entry->Length() == 0) {
  4310. +           TRACE("empty entry.\n");
  4311.             return B_ENTRY_NOT_FOUND;
  4312. -       if (!entry.IsValid())
  4313. +       }
  4314. +       if (!entry->IsValid()) {
  4315. +           TRACE("invalid entry.\n");
  4316.             return B_BAD_DATA;
  4317. +       }
  4318.  
  4319. -       if (entry.NameLength() != 0)
  4320. -           break;
  4321. +       if (entry->NameLength() != 0) {
  4322. +           // Get name
  4323. +           gotEntry = true;
  4324.  
  4325. -       fOffset += entry.Length();
  4326. -       TRACE("DirectoryIterator::GetNext() skipping entry\n");
  4327. -   }
  4328. +           size_t length = entry->NameLength();
  4329.  
  4330. -   TRACE("offset %Ld: entry ino %lu, length %u, name length %u, type %u\n",
  4331. -       fOffset, entry.InodeID(), entry.Length(), entry.NameLength(),
  4332. -       entry.FileType());
  4333. +           TRACE("block %lu, displacement %lu: entry ino %lu, length %u, "
  4334. +               "name length %lu, type %lu\n", fBlock, fDisplacement,
  4335. +               entry->InodeID(), entry->Length(), (uint32)length,
  4336. +               (uint32)entry->FileType());
  4337.  
  4338. -   // read name
  4339. +           if (*_nameLength < length)
  4340. +               length = *_nameLength - 1;
  4341. +           memcpy(name, entry->name, length);
  4342. +           name[length] = '\0';
  4343.  
  4344. -   size_t length = entry.NameLength();
  4345. -   status_t status = fInode->ReadAt(fOffset + ext2_dir_entry::MinimumSize(),
  4346. -       (uint8*)entry.name, &length);
  4347. -   if (status == B_OK) {
  4348. -       if (*_nameLength < length)
  4349. -           length = *_nameLength - 1;
  4350. -       memcpy(name, entry.name, length);
  4351. -       name[length] = '\0';
  4352. +           *_id = entry->InodeID();
  4353. +           *_nameLength = length;
  4354. +       }
  4355.  
  4356. -       *_id = entry.InodeID();
  4357. -       *_nameLength = length;
  4358. +       fDisplacement += entry->Length();
  4359.  
  4360. -       fOffset += entry.Length();
  4361. +       if (fDisplacement == fBlockSize) {
  4362. +           TRACE("Reached end of block\n");
  4363. +
  4364. +           fDisplacement = 0;
  4365. +           fBlock++;
  4366. +
  4367. +           if (!gotEntry) {
  4368. +               status = fInode->FindBlock(fBlock * fBlockSize, physicalBlock);
  4369. +               if (status != B_OK)
  4370. +                   return status;
  4371. +
  4372. +               block = cached.SetTo(physicalBlock);
  4373. +               if (block == NULL)
  4374. +                   return B_IO_ERROR;
  4375. +           }
  4376. +       } else if (fDisplacement > fBlockSize && !gotEntry) {
  4377. +           TRACE("The entry isn't block aligned.\n");
  4378. +           // TODO: Is block alignment obligatory?
  4379. +           return B_BAD_DATA;
  4380. +       }
  4381. +
  4382. +       TRACE("DirectoryIterator::GetNext() skipping entry\n");
  4383.     }
  4384.  
  4385. -   return status;
  4386. +   return B_OK;
  4387.  }
  4388.  
  4389.  
  4390.  status_t
  4391.  DirectoryIterator::Rewind()
  4392.  {
  4393. -   fOffset = 0;
  4394. +   fDisplacement = 0;
  4395. +   fBlock = 0;
  4396. +
  4397.     return B_OK;
  4398.  }
  4399. +
  4400. +
  4401. +status_t
  4402. +DirectoryIterator::AddEntry(Transaction& transaction, char* name,
  4403. +   size_t _nameLength, ino_t id)
  4404. +{
  4405. +   // TODO: Perhaps we should search for an empty spot with enough space for
  4406. +   // the entry, to try to minimize framgentation
  4407. +
  4408. +   /*off_t offset = fInode->Size();
  4409. +   fBlock = FindBlock(offset,
  4410. +   uint8 nameLength = _nameLength > EXT2_NAME_LENGTH ? EXT2_NAME_LENGTH
  4411. +       : _nameLength;
  4412. +
  4413. +   ext2_dir_entry entry;
  4414. +   entry.SetInodeID(id);
  4415. +   entry.SetLength(nameLength);
  4416. +
  4417. +   status_t status = fInode->WriteAt(transaction, fOffset, (uint8*)&entry,
  4418. +       ext2_dir_entry::MinimumSize());
  4419. +   if (status != B_OK)
  4420. +       return status;
  4421. +   return fInode->WriteAt(transaction, fOffset
  4422. +       + ext2_dir_entry::MinimumSize(), name, (size_t)nameLength);*/
  4423. +   return B_OK;
  4424. +}
  4425. Index: src/add-ons/kernel/file_systems/ext2/Journal.h
  4426. ===================================================================
  4427. --- src/add-ons/kernel/file_systems/ext2/Journal.h  (revision 0)
  4428. +++ src/add-ons/kernel/file_systems/ext2/Journal.h  (revision 0)
  4429. @@ -0,0 +1,241 @@
  4430. +/*
  4431. + * Copyright 2001-2010, Haiku Inc. All rights reserved.
  4432. + * This file may be used under the terms of the MIT License.
  4433. + *
  4434. + * Authors:
  4435. + *     Janito V. Ferreira Filho
  4436. + */
  4437. +#ifndef JOURNAL_H
  4438. +#define JOURNAL_H
  4439. +
  4440. +
  4441. +#define JOURNAL_MAGIC                              0xc03b3998U
  4442. +
  4443. +#define JOURNAL_DESCRIPTOR_BLOCK                   1
  4444. +#define JOURNAL_COMMIT_BLOCK                       2
  4445. +#define JOURNAL_SUPERBLOCK_V1                      3
  4446. +#define JOURNAL_SUPERBLOCK_V2                      4
  4447. +#define JOURNAL_REVOKE_BLOCK                       5
  4448. +
  4449. +#define JOURNAL_FLAG_ESCAPED                       1
  4450. +#define JOURNAL_FLAG_SAME_UUID                     2
  4451. +#define JOURNAL_FLAG_DELETED                       4
  4452. +#define JOURNAL_FLAG_LAST_TAG                      8
  4453. +
  4454. +#define JOURNAL_FEATURE_INCOMPATIBLE_REVOKE            1
  4455. +
  4456. +#define JOURNAL_KNOWN_READ_ONLY_COMPATIBLE_FEATURES    0
  4457. +#define JOURNAL_KNOWN_INCOMPATIBLE_FEATURES            \
  4458. +   JOURNAL_FEATURE_INCOMPATIBLE_REVOKE
  4459. +
  4460. +
  4461. +#include "Volume.h"
  4462. +
  4463. +#include <util/DoublyLinkedList.h>
  4464. +
  4465. +#include "Transaction.h"
  4466. +
  4467. +
  4468. +class RevokeManager;
  4469. +
  4470. +
  4471. +struct JournalHeader {
  4472. +   uint32          magic;
  4473. +   uint32          block_type;
  4474. +   uint32          sequence;
  4475. +   char            data[0];
  4476. +
  4477. +   uint32          Magic()         const  
  4478. +       { return B_BENDIAN_TO_HOST_INT32(magic); }
  4479. +   uint32          BlockType()     const  
  4480. +       { return B_BENDIAN_TO_HOST_INT32(block_type); }
  4481. +   uint32          Sequence()      const  
  4482. +       { return B_BENDIAN_TO_HOST_INT32(sequence); }
  4483. +
  4484. +   bool            CheckMagic()    const
  4485. +       { return Magic() == JOURNAL_MAGIC; }
  4486. +
  4487. +   void            MakeDescriptor(uint32 sequence);
  4488. +   void            MakeCommit(uint32 sequence);
  4489. +} _PACKED;
  4490. +
  4491. +
  4492. +struct JournalBlockTag {
  4493. +   uint32          block_number;
  4494. +   uint32          flags;
  4495. +
  4496. +   uint32          BlockNumber()   const  
  4497. +       { return B_BENDIAN_TO_HOST_INT32(block_number); }
  4498. +   uint32          Flags()         const  
  4499. +       { return B_BENDIAN_TO_HOST_INT32(flags); }
  4500. +
  4501. +   void            SetBlockNumber(uint32 block)
  4502. +       { block_number = B_HOST_TO_BENDIAN_INT32(block); }
  4503. +   void            SetFlags(uint32 new_flags)
  4504. +       { flags = B_HOST_TO_BENDIAN_INT32(new_flags); }
  4505. +   void            SetLastTagFlag()
  4506. +       { flags |= B_HOST_TO_BENDIAN_INT32(JOURNAL_FLAG_LAST_TAG); }
  4507. +   void            SetEscapedFlag()
  4508. +       { flags |= B_HOST_TO_BENDIAN_INT32(JOURNAL_FLAG_ESCAPED); }
  4509. +} _PACKED;
  4510. +
  4511. +
  4512. +struct JournalRevokeHeader {
  4513. +   JournalHeader   header;
  4514. +   uint32          num_bytes;
  4515. +
  4516. +   uint32          revoke_blocks[0];
  4517. +
  4518. +   uint32          NumBytes()      const  
  4519. +       { return B_BENDIAN_TO_HOST_INT32(num_bytes); }
  4520. +   uint32          RevokeBlock(int offset) const  
  4521. +       { return B_BENDIAN_TO_HOST_INT32(revoke_blocks[offset]); }
  4522. +} _PACKED;
  4523. +
  4524. +
  4525. +struct JournalSuperBlock {
  4526. +   JournalHeader   header;
  4527. +  
  4528. +   uint32          block_size;
  4529. +   uint32          num_blocks;
  4530. +   uint32          first_log_block;
  4531. +
  4532. +   uint32          first_commit_id;
  4533. +   uint32          log_start;
  4534. +
  4535. +   uint32          error;
  4536. +
  4537. +   uint32          compatible_features;
  4538. +   uint32          incompatible_features;
  4539. +   uint32          read_only_compatible_features;
  4540. +
  4541. +   uint8           uuid[16];
  4542. +
  4543. +   uint32          num_users;
  4544. +   uint32          dynamic_superblock;
  4545. +
  4546. +   uint32          max_transaction_blocks;
  4547. +   uint32          max_transaction_data;
  4548. +
  4549. +   uint32          padding[44];
  4550. +
  4551. +   uint8           user_ids[16*48];
  4552. +
  4553. +   uint32          BlockSize() const
  4554. +       { return B_BENDIAN_TO_HOST_INT32(block_size); }
  4555. +   uint32          NumBlocks() const
  4556. +       { return B_BENDIAN_TO_HOST_INT32(num_blocks); }
  4557. +   uint32          FirstLogBlock() const
  4558. +       { return B_BENDIAN_TO_HOST_INT32(first_log_block); }
  4559. +   uint32          FirstCommitID() const
  4560. +       { return B_BENDIAN_TO_HOST_INT32(first_commit_id); }
  4561. +   uint32          LogStart() const
  4562. +       { return B_BENDIAN_TO_HOST_INT32(compatible_features); }
  4563. +   uint32          IncompatibleFeatures() const
  4564. +       { return B_BENDIAN_TO_HOST_INT32(incompatible_features); }
  4565. +   uint32          ReadOnlyCompatibleFeatures() const
  4566. +       { return B_BENDIAN_TO_HOST_INT32(read_only_compatible_features); }
  4567. +   uint32          MaxTransactionData() const
  4568. +       { return B_BENDIAN_TO_HOST_INT32(max_transaction_data); }
  4569. +
  4570. +   void            SetLogStart(uint32 logStart)
  4571. +       { log_start = B_HOST_TO_BENDIAN_INT32(logStart); }
  4572. +   void            SetFirstCommitID(uint32 firstCommitID)
  4573. +       { first_commit_id = B_HOST_TO_BENDIAN_INT32(firstCommitID); }
  4574. +} _PACKED;
  4575. +
  4576. +class LogEntry;
  4577. +class Transaction;
  4578. +typedef DoublyLinkedList<LogEntry> LogEntryList;
  4579. +
  4580. +
  4581. +class Journal {
  4582. +public:
  4583. +                               Journal(Volume *fsVolume, Volume *jVolume);
  4584. +   virtual                     ~Journal();
  4585. +
  4586. +   virtual status_t            InitCheck();
  4587. +   virtual status_t            Recover();
  4588. +   virtual status_t            StartLog();
  4589. +           status_t            RestartLog();
  4590. +
  4591. +           status_t            Lock(Transaction* owner,
  4592. +                                   bool separateSubTransactions);
  4593. +           status_t            Unlock(Transaction* owner, bool success);
  4594. +
  4595. +   virtual status_t            MapBlock(uint32 logical, uint32& physical);
  4596. +   inline  uint32              FreeLogBlocks() const;
  4597. +          
  4598. +           status_t            FlushLogAndBlocks();
  4599. +
  4600. +           int32               TransactionID() const;
  4601. +
  4602. +           Volume*             GetFilesystemVolume()
  4603. +               { return fFilesystemVolume; }
  4604. +protected:
  4605. +                               Journal();
  4606. +  
  4607. +   virtual status_t            _WriteTransactionToLog();
  4608. +
  4609. +
  4610. +           Volume*             fJournalVolume;
  4611. +           void*               fJournalBlockCache;
  4612. +           Volume*             fFilesystemVolume;
  4613. +           void*               fFilesystemBlockCache;
  4614. +
  4615. +           recursive_lock      fLock;
  4616. +           Transaction*        fOwner;
  4617. +
  4618. +           RevokeManager*      fRevokeManager;
  4619. +
  4620. +           status_t            fInitStatus;
  4621. +           uint32              fBlockSize;
  4622. +           uint32              fFirstCommitID;
  4623. +           uint32              fFirstCacheCommitID;
  4624. +           uint32              fFirstLogBlock;
  4625. +           uint32              fLogSize;
  4626. +           uint32              fVersion;
  4627. +          
  4628. +           uint32              fLogStart;
  4629. +           uint32              fLogEnd;
  4630. +           uint32              fFreeBlocks;
  4631. +           uint32              fMaxTransactionSize;
  4632. +
  4633. +           uint32              fCurrentCommitID;
  4634. +           //uint32                fNextCommitID;
  4635. +
  4636. +           LogEntryList        fLogEntries;
  4637. +           mutex               fLogEntriesLock;
  4638. +           bool                fHasSubTransaction;
  4639. +           bool                fSeparateSubTransactions;
  4640. +           int32               fUnwrittenTransactions;
  4641. +           int32               fTransactionID;
  4642. +
  4643. +private:
  4644. +           status_t            _SaveSuperBlock();
  4645. +           status_t            _LoadSuperBlock();
  4646. +           status_t            _CheckFeatures(JournalSuperBlock* superblock);
  4647. +
  4648. +           uint32              _CountTags(JournalHeader *descriptorBlock);
  4649. +           status_t            _RecoverPassScan(uint32& lastCommitID);
  4650. +           status_t            _RecoverPassRevoke(uint32 lastCommitID);
  4651. +           status_t            _RecoverPassReplay(uint32 lastCommitID);
  4652. +
  4653. +           status_t            _FlushLog(bool canWait, bool flushBlocks);
  4654. +
  4655. +   inline  uint32              _WrapAroundLog(uint32 block);
  4656. +          
  4657. +           size_t              _CurrentTransactionSize() const;
  4658. +           size_t              _FullTransactionSize() const;
  4659. +           size_t              _MainTransactionSize() const;
  4660. +          
  4661. +   virtual status_t            _TransactionDone(bool success);
  4662. +
  4663. +   static  void                _TransactionWritten(int32 transactionID,
  4664. +                                   int32 event, void* _logEntry);
  4665. +   static  void                _TransactionIdle(int32 transactionID,
  4666. +                                   int32 event, void* _journal);
  4667. +};
  4668. +
  4669. +#endif // JOURNAL_H
  4670. +
  4671.  
  4672. Property changes on: src/add-ons/kernel/file_systems/ext2/Journal.h
  4673. ___________________________________________________________________
  4674. Added: svn:executable
  4675.    + *
  4676.  
  4677. Index: src/add-ons/kernel/file_systems/ext2/IndexedDirectoryIterator.h
  4678. ===================================================================
  4679. --- src/add-ons/kernel/file_systems/ext2/IndexedDirectoryIterator.h (revision 37486)
  4680. +++ src/add-ons/kernel/file_systems/ext2/IndexedDirectoryIterator.h (working copy)
  4681. @@ -17,7 +17,7 @@
  4682.  class IndexedDirectoryIterator : public DirectoryIterator {
  4683.  public:
  4684.                                 IndexedDirectoryIterator(off_t start,
  4685. -                                   uint32 blockSize, Inode* directory,
  4686. +                                   Inode* directory,
  4687.                                     HTreeEntryIterator* parent);
  4688.     virtual                     ~IndexedDirectoryIterator();
  4689.    
  4690. @@ -25,12 +25,15 @@
  4691.                                     ino_t* id);
  4692.            
  4693.             status_t            Rewind();
  4694. +
  4695. +           status_t            AddEntry(Transaction& transaction, char* name,
  4696. +                                   size_t _nameLength, ino_t id);
  4697. +
  4698.  private:
  4699.             bool                fIndexing;
  4700.             HTreeEntryIterator* fParent;
  4701. -           off_t               fMaxOffset;
  4702. -           uint32              fBlockSize;
  4703.             uint32              fMaxAttempts;
  4704. +           uint32              fPreviousBlock;
  4705.  };
  4706.  
  4707.  #endif // INDEXED_DIRECTORY_ITERATOR_H
  4708. Index: src/add-ons/kernel/file_systems/ext2/Transaction.cpp
  4709. ===================================================================
  4710. --- src/add-ons/kernel/file_systems/ext2/Transaction.cpp    (revision 0)
  4711. +++ src/add-ons/kernel/file_systems/ext2/Transaction.cpp    (revision 0)
  4712. @@ -0,0 +1,201 @@
  4713. +/*
  4714. + * Copyright 2001-2010, Haiku Inc. All rights reserved.
  4715. + * This file may be used under the terms of the MIT License.
  4716. + *
  4717. + * Authors:
  4718. + *     Janito V. Ferreira Filho
  4719. + */
  4720. +
  4721. +#include "Transaction.h"
  4722. +
  4723. +#include <string.h>
  4724. +
  4725. +#include <fs_cache.h>
  4726. +
  4727. +#include "Journal.h"
  4728. +
  4729. +
  4730. +TransactionListener::TransactionListener()
  4731. +{
  4732. +}
  4733. +
  4734. +
  4735. +TransactionListener::~TransactionListener()
  4736. +{
  4737. +}
  4738. +
  4739. +
  4740. +Transaction::Transaction()
  4741. +   :
  4742. +   fJournal(NULL),
  4743. +   fParent(NULL)
  4744. +{
  4745. +}
  4746. +
  4747. +
  4748. +Transaction::Transaction(Journal* journal)
  4749. +   :
  4750. +   fJournal(NULL),
  4751. +   fParent(NULL)
  4752. +{
  4753. +   Start(journal);
  4754. +}
  4755. +
  4756. +
  4757. +Transaction::~Transaction()
  4758. +{
  4759. +   if (IsStarted())
  4760. +       fJournal->Unlock(this, false);
  4761. +}
  4762. +
  4763. +status_t
  4764. +Transaction::Start(Journal* journal)
  4765. +{
  4766. +   if (IsStarted())
  4767. +       return B_OK;
  4768. +
  4769. +   fJournal = journal;
  4770. +   if (fJournal == NULL)
  4771. +       return B_ERROR;
  4772. +  
  4773. +   status_t status = fJournal->Lock(this, false);
  4774. +   if (status != B_OK)
  4775. +       fJournal = NULL;
  4776. +
  4777. +   return status;
  4778. +}
  4779. +
  4780. +
  4781. +status_t
  4782. +Transaction::Done()
  4783. +{
  4784. +   if (!IsStarted())
  4785. +       return B_OK;
  4786. +
  4787. +   status_t status = fJournal->Unlock(this, true);
  4788. +  
  4789. +   if (status == B_OK)
  4790. +       fJournal = NULL;
  4791. +
  4792. +   return status;
  4793. +}
  4794. +
  4795. +
  4796. +int32
  4797. +Transaction::ID() const
  4798. +{
  4799. +   if (!IsStarted())
  4800. +       return -1;
  4801. +
  4802. +   return fJournal->TransactionID();
  4803. +}
  4804. +
  4805. +
  4806. +bool
  4807. +Transaction::IsStarted() const
  4808. +{
  4809. +   return fJournal != NULL;
  4810. +}
  4811. +
  4812. +
  4813. +bool
  4814. +Transaction::HasParent() const
  4815. +{
  4816. +   return fParent != NULL;
  4817. +}
  4818. +
  4819. +
  4820. +status_t
  4821. +Transaction::WriteBlocks(off_t blockNumber, const uint8* buffer,
  4822. +   size_t numBlocks)
  4823. +{
  4824. +   if (!IsStarted())
  4825. +       return B_NO_INIT;
  4826. +
  4827. +   void* cache = GetVolume()->BlockCache();
  4828. +   size_t blockSize = GetVolume()->BlockSize();
  4829. +
  4830. +   for (size_t i = 0; i < numBlocks; ++i) {
  4831. +       void* block = block_cache_get_empty(cache, blockNumber + i, ID());
  4832. +       if (block == NULL)
  4833. +           return B_ERROR;
  4834. +      
  4835. +       memcpy(block, buffer, blockSize);
  4836. +       buffer += blockSize;
  4837. +
  4838. +       block_cache_put(cache, blockNumber + i);
  4839. +   }
  4840. +
  4841. +   return B_OK;
  4842. +}
  4843. +
  4844. +
  4845. +void
  4846. +Transaction::Split()
  4847. +{
  4848. +   cache_start_sub_transaction(fJournal->GetFilesystemVolume()->BlockCache(),
  4849. +       ID());
  4850. +}
  4851. +
  4852. +
  4853. +Volume*
  4854. +Transaction::GetVolume() const
  4855. +{
  4856. +   if (!IsStarted())
  4857. +       return NULL;
  4858. +
  4859. +   return fJournal->GetFilesystemVolume();
  4860. +}
  4861. +
  4862. +
  4863. +void
  4864. +Transaction::AddListener(TransactionListener* listener)
  4865. +{
  4866. +   if (!IsStarted())
  4867. +       panic("Transaction is not running!");
  4868. +
  4869. +   fListeners.Add(listener);
  4870. +}
  4871. +
  4872. +
  4873. +void
  4874. +Transaction::RemoveListener(TransactionListener* listener)
  4875. +{
  4876. +   if (!IsStarted())
  4877. +       panic("Transaction is not running!");
  4878. +
  4879. +   fListeners.Remove(listener);
  4880. +   listener->RemovedFromTransaction();
  4881. +}
  4882. +
  4883. +
  4884. +void
  4885. +Transaction::NotifyListeners(bool success)
  4886. +{
  4887. +   while (TransactionListener* listener = fListeners.RemoveHead()) {
  4888. +       listener->TransactionDone(success);
  4889. +       listener->RemovedFromTransaction();
  4890. +   }
  4891. +}
  4892. +
  4893. +
  4894. +void
  4895. +Transaction::MoveListenersTo(Transaction* transaction)
  4896. +{
  4897. +   while (TransactionListener* listener = fListeners.RemoveHead())
  4898. +       transaction->fListeners.Add(listener);
  4899. +}
  4900. +
  4901. +
  4902. +void
  4903. +Transaction::SetParent(Transaction* transaction)
  4904. +{
  4905. +   fParent = transaction;
  4906. +}
  4907. +
  4908. +
  4909. +Transaction*
  4910. +Transaction::Parent() const
  4911. +{
  4912. +   return fParent;
  4913. +}
  4914. Index: src/add-ons/kernel/file_systems/ext2/ext2.h
  4915. ===================================================================
  4916. --- src/add-ons/kernel/file_systems/ext2/ext2.h (revision 37486)
  4917. +++ src/add-ons/kernel/file_systems/ext2/ext2.h (working copy)
  4918. @@ -13,6 +13,8 @@
  4919.  #include <KernelExport.h>
  4920.  
  4921.  
  4922. +#define TRACE_EXT2
  4923. +
  4924.  #define EXT2_SUPER_BLOCK_OFFSET    1024
  4925.  
  4926.  struct ext2_super_block {
  4927. @@ -108,9 +110,16 @@
  4928.         { return B_LENDIAN_TO_HOST_INT32(read_only_features); }
  4929.     uint32 IncompatibleFeatures() const
  4930.         { return B_LENDIAN_TO_HOST_INT32(incompatible_features); }
  4931. +   ino_t  JournalInode() const
  4932. +       { return B_LENDIAN_TO_HOST_INT32(journal_inode); }
  4933.     uint32 HashSeed(uint8 i) const
  4934.         { return B_LENDIAN_TO_HOST_INT32(hash_seed[i]); }
  4935.  
  4936. +   void SetFreeInodes(uint32 freeInodes)
  4937. +       { free_inodes = B_HOST_TO_LENDIAN_INT32(freeInodes); }
  4938. +   void SetFreeBlocks(uint32 freeBlocks)
  4939. +       { free_blocks = B_HOST_TO_LENDIAN_INT32(freeBlocks); }
  4940. +
  4941.     bool IsValid();
  4942.         // implemented in Volume.cpp
  4943.  } _PACKED;
  4944. @@ -162,8 +171,16 @@
  4945.     uint16  _padding;
  4946.     uint32  _reserved[3];
  4947.  
  4948. +   uint32 BlockBitmap() const
  4949. +       { return B_LENDIAN_TO_HOST_INT32(block_bitmap); }
  4950. +   uint32 InodeBitmap() const
  4951. +       { return B_LENDIAN_TO_HOST_INT32(inode_bitmap); }
  4952.     uint32 InodeTable() const
  4953.         { return B_LENDIAN_TO_HOST_INT32(inode_table); }
  4954. +   uint16 FreeBlocks() const
  4955. +       { return B_LENDIAN_TO_HOST_INT16(free_blocks); }
  4956. +   uint16 FreeInodes() const
  4957. +       { return B_LENDIAN_TO_HOST_INT16(free_inodes); }
  4958.  } _PACKED;
  4959.  
  4960.  #define EXT2_DIRECT_BLOCKS         12
  4961. @@ -214,6 +231,7 @@
  4962.     uint16 Mode() const { return B_LENDIAN_TO_HOST_INT16(mode); }
  4963.     uint32 Flags() const { return B_LENDIAN_TO_HOST_INT32(flags); }
  4964.     uint16 NumLinks() const { return B_LENDIAN_TO_HOST_INT16(num_links); }
  4965. +   uint32 NumBlocks() const { return B_LENDIAN_TO_HOST_INT32(num_blocks); }
  4966.  
  4967.     time_t AccessTime() const { return B_LENDIAN_TO_HOST_INT32(access_time); }
  4968.     time_t CreationTime() const { return B_LENDIAN_TO_HOST_INT32(creation_time); }
  4969. @@ -270,11 +288,26 @@
  4970.     uint8   file_type;
  4971.     char    name[EXT2_NAME_LENGTH];
  4972.  
  4973. -   uint32 InodeID() const { return B_LENDIAN_TO_HOST_INT32(inode_id); }
  4974. -   uint16 Length() const { return B_LENDIAN_TO_HOST_INT16(length); }
  4975. -   uint8 NameLength() const { return name_length; }
  4976. -   uint8 FileType() const { return file_type; }
  4977. +   uint32  InodeID() const { return B_LENDIAN_TO_HOST_INT32(inode_id); }
  4978. +   uint16  Length() const { return B_LENDIAN_TO_HOST_INT16(length); }
  4979. +   uint8   NameLength() const { return name_length; }
  4980. +   uint8   FileType() const { return file_type; }
  4981.  
  4982. +   void    SetInodeID(uint32 id) { inode_id = B_HOST_TO_LENDIAN_INT32(id); }
  4983. +
  4984. +   void    SetLength(uint8 nameLength)
  4985. +   {
  4986. +       name_length = nameLength;
  4987. +
  4988. +       if (nameLength % 4 == 0) {
  4989. +           length = B_HOST_TO_LENDIAN_INT16(
  4990. +               (short)(nameLength + MinimumSize()));
  4991. +       } else {
  4992. +           length = B_HOST_TO_LENDIAN_INT16(
  4993. +               (short)(nameLength % 4 + 1 + MinimumSize()));
  4994. +       }
  4995. +   }
  4996. +
  4997.     bool IsValid() const
  4998.     {
  4999.         return Length() > MinimumSize();
  5000. Index: src/add-ons/kernel/file_systems/ext2/CachedBlock.h
  5001. ===================================================================
  5002. --- src/add-ons/kernel/file_systems/ext2/CachedBlock.h  (revision 37486)
  5003. +++ src/add-ons/kernel/file_systems/ext2/CachedBlock.h  (working copy)
  5004. @@ -9,32 +9,40 @@
  5005.  
  5006.  #include <fs_cache.h>
  5007.  
  5008. +#include "Transaction.h"
  5009.  #include "Volume.h"
  5010.  
  5011.  
  5012.  class CachedBlock {
  5013.  public:
  5014. -                   CachedBlock(Volume* volume);
  5015. -                   CachedBlock(Volume* volume, uint32 block);
  5016. -                   ~CachedBlock();
  5017. +                           CachedBlock(Volume* volume);
  5018. +                           CachedBlock(Volume* volume, uint32 block);
  5019. +                           ~CachedBlock();
  5020.  
  5021. -           void    Keep();
  5022. -           void    Unset();
  5023. +           void            Keep();
  5024. +           void            Unset();
  5025.  
  5026. -   const   uint8*  SetTo(uint32 block);
  5027. +           const uint8*    SetTo(uint32 block);
  5028. +           uint8*          SetToWritable(Transaction& transaction,
  5029. +                               uint32 block, bool empty = false);
  5030. +           uint8*          SetToWritableWithoutTransaction(uint32 block,
  5031. +                               bool empty = false);
  5032.  
  5033. -   const   uint8*  Block() const { return fBlock; }
  5034. -           off_t   BlockNumber() const { return fBlockNumber; }
  5035. +           const uint8*    Block() const { return fBlock; }
  5036. +           off_t           BlockNumber() const { return fBlockNumber; }
  5037.  
  5038.  private:
  5039. -                   CachedBlock(const CachedBlock &);
  5040. -                   CachedBlock &operator=(const CachedBlock &);
  5041. -                       // no implementation
  5042. +                           CachedBlock(const CachedBlock &);
  5043. +                           CachedBlock &operator=(const CachedBlock &);
  5044. +                               // no implementation
  5045. +                      
  5046. +           uint8*          _SetToWritableEtc(int32 transaction, uint32 block,
  5047. +                               bool empty);
  5048.  
  5049.  protected:
  5050. -   Volume*         fVolume;
  5051. -   uint32          fBlockNumber;
  5052. -   uint8*          fBlock;
  5053. +           Volume*         fVolume;
  5054. +           uint32          fBlockNumber;
  5055. +           uint8*          fBlock;
  5056.  };
  5057.  
  5058.  
  5059. @@ -94,4 +102,35 @@
  5060.     return fBlock = (uint8 *)block_cache_get(fVolume->BlockCache(), block);
  5061.  }
  5062.  
  5063. +
  5064. +inline uint8*
  5065. +CachedBlock::SetToWritable(Transaction& transaction, uint32 block, bool empty)
  5066. +{
  5067. +   return _SetToWritableEtc(transaction.ID(), block, empty);
  5068. +}
  5069. +
  5070. +
  5071. +inline uint8*
  5072. +CachedBlock::SetToWritableWithoutTransaction(uint32 block, bool empty)
  5073. +{
  5074. +   return _SetToWritableEtc((int32)-1, block, empty);
  5075. +}
  5076. +
  5077. +inline uint8*
  5078. +CachedBlock::_SetToWritableEtc(int32 transaction, uint32 block, bool empty)
  5079. +{
  5080. +   Unset();
  5081. +   fBlockNumber = block;
  5082. +
  5083. +   if (empty) {
  5084. +       fBlock = (uint8*)block_cache_get_empty(fVolume->BlockCache(),
  5085. +           block, transaction);
  5086. +   } else {
  5087. +       fBlock = (uint8*)block_cache_get_writable(fVolume->BlockCache(),
  5088. +           block, transaction);
  5089. +   }
  5090. +
  5091. +   return fBlock;
  5092. +}
  5093. +
  5094.  #endif // CACHED_BLOCK_H
  5095. Index: src/add-ons/kernel/file_systems/ext2/HashRevokeManager.cpp
  5096. ===================================================================
  5097. --- src/add-ons/kernel/file_systems/ext2/HashRevokeManager.cpp  (revision 0)
  5098. +++ src/add-ons/kernel/file_systems/ext2/HashRevokeManager.cpp  (revision 0)
  5099. @@ -0,0 +1,141 @@
  5100. +/*
  5101. + * Copyright 2001-2010, Haiku Inc. All rights reserved.
  5102. + * This file may be used under the terms of the MIT License.
  5103. + *
  5104. + * Authors:
  5105. + *     Janito V. Ferreira Filho
  5106. + */
  5107. +
  5108. +#include "HashRevokeManager.h"
  5109. +
  5110. +#include <new>
  5111. +
  5112. +
  5113. +HashRevokeManager::HashRevokeManager()
  5114. +   :
  5115. +   kInitialHashSize(128)
  5116. +       // TODO: Benchmark and find an optimal value
  5117. +{
  5118. +}
  5119. +
  5120. +
  5121. +HashRevokeManager::~HashRevokeManager()
  5122. +{
  5123. +   hash_uninit(fHash);
  5124. +}
  5125. +
  5126. +
  5127. +status_t
  5128. +HashRevokeManager::Init()
  5129. +{
  5130. +   RevokeElement dummyElement;
  5131. +  
  5132. +   fHash = hash_init(kInitialHashSize, offset_of_member(dummyElement, next),
  5133. +       &HashRevokeManager::Compare,
  5134. +       &HashRevokeManager::Hash);
  5135. +
  5136. +   if (fHash == NULL)
  5137. +       return B_NO_MEMORY;
  5138. +
  5139. +   return B_OK;
  5140. +}
  5141. +
  5142. +
  5143. +status_t
  5144. +HashRevokeManager::Insert(uint32 block, uint32 commitID)
  5145. +{
  5146. +   RevokeElement* element = (RevokeElement*)hash_lookup(fHash, &block);
  5147. +  
  5148. +   if (element != NULL) {
  5149. +       if (element->commitID < commitID) {
  5150. +           status_t retValue = hash_remove(fHash, element);
  5151. +          
  5152. +           if (retValue != B_OK)
  5153. +               return retValue;
  5154. +
  5155. +           delete element;
  5156. +       }
  5157. +       else {
  5158. +           return B_OK;
  5159. +               // We already have a newer version of the block
  5160. +       }
  5161. +   }
  5162. +
  5163. +   return _ForceInsert(block, commitID);
  5164. +}
  5165. +
  5166. +
  5167. +status_t
  5168. +HashRevokeManager::Remove(uint32 block)
  5169. +{
  5170. +   RevokeElement* element = (RevokeElement*)hash_lookup(fHash, &block);
  5171. +
  5172. +   if (element == NULL)
  5173. +       return B_ERROR; // TODO: Perhaps we should just ignore?
  5174. +
  5175. +   status_t retValue = hash_remove(fHash, element);
  5176. +  
  5177. +   if (retValue == B_OK)
  5178. +       delete element;
  5179. +
  5180. +   return retValue;
  5181. +}
  5182. +
  5183. +
  5184. +bool
  5185. +HashRevokeManager::Lookup(uint32 block, uint32 commitID)
  5186. +{
  5187. +   RevokeElement* element = (RevokeElement*)hash_lookup(fHash, &block);
  5188. +
  5189. +   if (element == NULL)
  5190. +       return false;
  5191. +
  5192. +   return element->commitID >= commitID;
  5193. +}
  5194. +
  5195. +
  5196. +/*static*/ int
  5197. +HashRevokeManager::Compare(void* _revoked, const void *_block)
  5198. +{
  5199. +   RevokeElement* revoked = (RevokeElement*)_revoked;
  5200. +   uint32 block = *(uint32*)_block;
  5201. +
  5202. +   if (revoked->block == block)
  5203. +       return 0;
  5204. +
  5205. +   return (revoked->block > block) ? 1 : -1;
  5206. +}
  5207. +
  5208. +
  5209. +/*static*/ uint32
  5210. +HashRevokeManager::Hash(void* _revoked, const void* _block, uint32 range)
  5211. +{
  5212. +   RevokeElement* revoked = (RevokeElement*)revoked;
  5213. +   uint32 block = *(uint32*)_block;
  5214. +
  5215. +   if (revoked != NULL)
  5216. +       return revoked->block % range;
  5217. +
  5218. +   return block % range;
  5219. +}
  5220. +
  5221. +
  5222. +status_t
  5223. +HashRevokeManager::_ForceInsert(uint32 block, uint32 commitID)
  5224. +{
  5225. +   RevokeElement* element = new(std::nothrow) RevokeElement;
  5226. +
  5227. +   if (element == NULL)
  5228. +       return B_NO_MEMORY;
  5229. +
  5230. +   element->block = block;
  5231. +   element->commitID = commitID;
  5232. +
  5233. +   status_t retValue = hash_insert_grow(fHash, element);
  5234. +
  5235. +   if (retValue == B_OK)
  5236. +       fRevokeCount++;
  5237. +
  5238. +   return retValue;
  5239. +}
  5240. +
  5241.  
  5242. Property changes on: src/add-ons/kernel/file_systems/ext2/HashRevokeManager.cpp
  5243. ___________________________________________________________________
  5244. Added: svn:executable
  5245.    + *
  5246.  
  5247. Index: src/add-ons/kernel/file_systems/ext2/RevokeManager.h
  5248. ===================================================================
  5249. --- src/add-ons/kernel/file_systems/ext2/RevokeManager.h    (revision 0)
  5250. +++ src/add-ons/kernel/file_systems/ext2/RevokeManager.h    (revision 0)
  5251. @@ -0,0 +1,35 @@
  5252. +/*
  5253. + * Copyright 2001-2010, Haiku Inc. All rights reserved.
  5254. + * This file may be used under the terms of the MIT License.
  5255. + *
  5256. + * Authors:
  5257. + *     Janito V. Ferreira Filho
  5258. + */
  5259. +#ifndef REVOKEMANAGER_H
  5260. +#define REVOKEMANAGER_H
  5261. +
  5262. +#include "Journal.h"
  5263. +
  5264. +
  5265. +struct JournalRevokeHeader;
  5266. +
  5267. +class RevokeManager {
  5268. +public:
  5269. +                       RevokeManager();
  5270. +   virtual             ~RevokeManager() = 0;
  5271. +
  5272. +   virtual status_t    Insert(uint32 block, uint32 commitID) = 0;
  5273. +   virtual status_t    Remove(uint32 block) = 0;
  5274. +   virtual bool        Lookup(uint32 block, uint32 commitID) = 0;
  5275. +          
  5276. +           uint32      NumRevokes() { return fRevokeCount; }
  5277. +
  5278. +           status_t    ScanRevokeBlock(JournalRevokeHeader* revokeBlock,
  5279. +                           uint32 commitID);
  5280. +
  5281. +protected:
  5282. +           uint32      fRevokeCount;
  5283. +};
  5284. +
  5285. +#endif // REVOKEMANAGER_H
  5286. +
  5287.  
  5288. Property changes on: src/add-ons/kernel/file_systems/ext2/RevokeManager.h
  5289. ___________________________________________________________________
  5290. Added: svn:executable
  5291.    + *
  5292.  
  5293. Index: src/add-ons/kernel/file_systems/ext2/BitmapBlock.h
  5294. ===================================================================
  5295. --- src/add-ons/kernel/file_systems/ext2/BitmapBlock.h  (revision 0)
  5296. +++ src/add-ons/kernel/file_systems/ext2/BitmapBlock.h  (revision 0)
  5297. @@ -0,0 +1,48 @@
  5298. +/*
  5299. + * Copyright 2001-2010, Haiku Inc. All rights reserved.
  5300. + * This file may be used under the terms of the MIT License.
  5301. + *
  5302. + * Authors:
  5303. + *     Janito V. Ferreira Filho
  5304. + */
  5305. +#ifndef BITMAPBLOCK_H
  5306. +#define BITMAPBLOCK_H
  5307. +
  5308. +#include "CachedBlock.h"
  5309. +
  5310. +
  5311. +class BitmapBlock : public CachedBlock {
  5312. +public:
  5313. +                           BitmapBlock(Volume* volume, uint32 numBits);
  5314. +                           ~BitmapBlock();
  5315. +
  5316. +           bool            SetTo(uint32 block);
  5317. +           bool            SetToWritable(Transaction& transaction,
  5318. +                               uint32 block, bool empty = false);
  5319. +
  5320. +           bool            CheckMarked(uint32 start, uint32 length);
  5321. +           bool            CheckUnmarked(uint32 start, uint32 length);
  5322. +
  5323. +           bool            Mark(uint32 start, uint32 length,
  5324. +                               bool force = false);
  5325. +           bool            Unmark(uint32 start, uint32 length,
  5326. +                               bool force = false);
  5327. +
  5328. +           void            FindNextMarked(uint32& pos);
  5329. +           void            FindNextUnmarked(uint32& pos);
  5330. +
  5331. +           void            FindPreviousMarked(uint32& pos);
  5332. +
  5333. +           void            FindLargestUnmarkedRange(uint32& start,
  5334. +                               uint32& length);
  5335. +
  5336. +           uint32          NumBits() const;
  5337. +
  5338. +protected:
  5339. +           uint32*         fData;
  5340. +           const uint32*   fReadOnlyData;
  5341. +
  5342. +           uint32          fNumBits;
  5343. +};
  5344. +
  5345. +#endif // BITMAPBLOCK_H
  5346.  
  5347. Property changes on: src/add-ons/kernel/file_systems/ext2/BitmapBlock.h
  5348. ___________________________________________________________________
  5349. Added: svn:executable
  5350.    + *
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement