Advertisement
Guest User

Untitled

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