Advertisement
Guest User

Untitled

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