Advertisement
Guest User

Untitled

a guest
Jun 9th, 2017
80
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 215.06 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,123 @@
  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 "Inode.h"
  54. +#include "Volume.h"
  55. +
  56. +
  57. +//#define TRACE_EXT2
  58. +#ifdef TRACE_EXT2
  59. +#  define TRACE(x...) dprintf("\33[34mext2:\33[0m " x)
  60. +#else
  61. +#  define TRACE(x...) ;
  62. +#endif
  63. +
  64. +
  65. +InodeAllocator::InodeAllocator(Volume* volume)
  66. +   :
  67. +   fVolume(volume)
  68. +{
  69. +   mutex_init(&fLock, "ext2 inode allocator");
  70. +}
  71. +
  72. +
  73. +InodeAllocator::~InodeAllocator()
  74. +{
  75. +   mutex_destroy(&fLock);
  76. +}
  77. +
  78. +
  79. +/*virtual*/ status_t
  80. +InodeAllocator::New(Transaction& transaction, Inode* parent, int32 mode,
  81. +   ino_t& id)
  82. +{
  83. +   // Apply allocation policy
  84. +   uint32 preferredBlockGroup = parent == NULL ? parent->ID()
  85. +       / parent->GetVolume()->InodesPerGroup() : 0;
  86. +  
  87. +   return _Allocate(transaction, preferredBlockGroup, id);
  88. +}
  89. +
  90. +
  91. +status_t
  92. +InodeAllocator::_Allocate(Transaction& transaction, uint32 preferredBlockGroup,
  93. +   ino_t& id)
  94. +{
  95. +   MutexLocker lock(fLock);
  96. +
  97. +   uint32 blockGroup = preferredBlockGroup;
  98. +   uint32 lastBlockGroup = fVolume->NumGroups() - 1;
  99. +
  100. +   for (int i = 0; i < 2; ++i) {
  101. +       for (; blockGroup < lastBlockGroup; ++blockGroup) {
  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->InodesPerGroup(), id);
  111. +           }
  112. +       }
  113. +
  114. +       if (i == 0) {
  115. +           ext2_block_group* group;
  116. +
  117. +           status_t status = fVolume->GetBlockGroup(blockGroup, &group);
  118. +           if (status != B_OK)
  119. +               return status;
  120. +
  121. +           if (group->FreeInodes() != 0) {
  122. +               return _MarkInBitmap(transaction, group->InodeBitmap(),
  123. +                   blockGroup, fVolume->NumInodes()
  124. +                       - blockGroup * fVolume->InodesPerGroup(), id);
  125. +           }
  126. +       }
  127. +
  128. +       blockGroup = 0;
  129. +       lastBlockGroup = preferredBlockGroup;
  130. +   }
  131. +
  132. +   return B_DEVICE_FULL;
  133. +}
  134. +
  135. +
  136. +status_t
  137. +InodeAllocator::_MarkInBitmap(Transaction& transaction, uint32 bitmapBlock,
  138. +   uint32 blockGroup, uint32 numInodes, ino_t& id)
  139. +{
  140. +   BitmapBlock inodeBitmap(fVolume, numInodes);
  141. +
  142. +   if (!inodeBitmap.SetToWritable(transaction, bitmapBlock)) {
  143. +       TRACE("Unable to open inode bitmap (block number: %lu) for block group "
  144. +           "%lu\n", bitmapBlock, blockGroup);
  145. +       return B_IO_ERROR;
  146. +   }
  147. +
  148. +   uint32 pos = 0;
  149. +   inodeBitmap.FindNextUnmarked(pos);
  150. +
  151. +   if (pos == inodeBitmap.NumBits()) {
  152. +       TRACE("Even though the block group %lu indicates there are free "
  153. +           "inodes, no unmarked bit was found in the inode bitmap at block "
  154. +           "%lu.", blockGroup, bitmapBlock);
  155. +       return B_ERROR;
  156. +   }
  157. +
  158. +   inodeBitmap.Mark(pos, true);
  159. +   id = pos + blockGroup * fVolume->InodesPerGroup();
  160. +
  161. +   return B_OK;
  162. +}
  163.  
  164. Property changes on: src/add-ons/kernel/file_systems/ext2/InodeAllocator.cpp
  165. ___________________________________________________________________
  166. Added: svn:executable
  167.    + *
  168.  
  169. Index: src/add-ons/kernel/file_systems/ext2/BlockAllocator.h
  170. ===================================================================
  171. --- src/add-ons/kernel/file_systems/ext2/BlockAllocator.h   (revision 0)
  172. +++ src/add-ons/kernel/file_systems/ext2/BlockAllocator.h   (revision 0)
  173. @@ -0,0 +1,53 @@
  174. +/*
  175. + * Copyright 2001-2010, Haiku Inc. All rights reserved.
  176. + * This file may be used under the terms of the MIT License.
  177. + *
  178. + * Authors:
  179. + *     Janito V. Ferreira Filho
  180. + */
  181. +#ifndef BLOCKALLOCATOR_H
  182. +#define BLOCKALLOCATOR_H
  183. +
  184. +#include <lock.h>
  185. +
  186. +#include "Transaction.h"
  187. +
  188. +
  189. +class AllocationBlockGroup;
  190. +class Inode;
  191. +class Volume;
  192. +
  193. +
  194. +class BlockAllocator {
  195. +public:
  196. +                       BlockAllocator(Volume* volume);
  197. +                       ~BlockAllocator();
  198. +
  199. +           status_t    Initialize();
  200. +
  201. +           status_t    AllocateBlocks(Transaction& transaction,
  202. +                           uint32 minimum, uint32 maximum, uint32& blockGroup,
  203. +                           uint32& start, uint32& length);
  204. +           status_t    Allocate(Transaction& transaction, Inode* inode,
  205. +                           off_t numBlocks, uint32 minimum, uint32& start,
  206. +                           uint32& length);
  207. +           status_t    Free(Transaction& transaction, uint32 start,
  208. +                           uint32 length);
  209. +
  210. +           uint32      FreeBlocks();
  211. +
  212. +protected:
  213. +   static  status_t    _Initialize(BlockAllocator* allocator);
  214. +
  215. +
  216. +           Volume*     fVolume;
  217. +           mutex       fLock;
  218. +
  219. +           AllocationBlockGroup* fGroups;
  220. +           uint32      fBlocksPerGroup;
  221. +           uint32      fNumBlocks;
  222. +           uint32      fNumGroups;
  223. +           uint32      fFirstBlock;
  224. +};
  225. +
  226. +#endif // BLOCKALLOCATOR_H
  227.  
  228. Property changes on: src/add-ons/kernel/file_systems/ext2/BlockAllocator.h
  229. ___________________________________________________________________
  230. Added: svn:executable
  231.    + *
  232.  
  233. Index: src/add-ons/kernel/file_systems/ext2/HTreeEntryIterator.cpp
  234. ===================================================================
  235. --- src/add-ons/kernel/file_systems/ext2/HTreeEntryIterator.cpp (revision 37957)
  236. +++ src/add-ons/kernel/file_systems/ext2/HTreeEntryIterator.cpp (working copy)
  237. @@ -11,8 +11,8 @@
  238.  
  239.  #include <new>
  240.  
  241. +#include "CachedBlock.h"
  242.  #include "HTree.h"
  243. -#include "IndexedDirectoryIterator.h"
  244.  #include "Inode.h"
  245.  
  246.  
  247. @@ -27,81 +27,92 @@
  248.  
  249.  HTreeEntryIterator::HTreeEntryIterator(off_t offset, Inode* directory)
  250.     :
  251. +   fDirectory(directory),
  252. +   fVolume(directory->GetVolume()),
  253.     fHasCollision(false),
  254. -   fDirectory(directory),
  255. -   fOffset(offset),
  256. +   fBlockSize(directory->GetVolume()->BlockSize()),
  257.     fParent(NULL),
  258.     fChild(NULL)
  259.  {
  260. -   fBlockSize = fDirectory->GetVolume()->BlockSize();
  261. +   fInitStatus = fDirectory->FindBlock(offset, fBlockNum);
  262. +  
  263. +   if (fInitStatus == B_OK) {
  264. +       fFirstEntry = offset % fBlockSize / sizeof(HTreeEntry);
  265. +       fCurrentEntry = fFirstEntry;
  266. +   }
  267. +
  268. +   TRACE("HTreeEntryIterator::HTreeEntryIterator() block %lu entry no. %lu\n",
  269. +       fBlockNum, (uint32)fCurrentEntry);
  270.  }
  271.  
  272.  
  273.  HTreeEntryIterator::HTreeEntryIterator(uint32 block, uint32 blockSize,
  274.     Inode* directory, HTreeEntryIterator* parent, bool hasCollision)
  275.     :
  276. +   fDirectory(directory),
  277. +   fVolume(directory->GetVolume()),
  278.     fHasCollision(hasCollision),
  279. +   fFirstEntry(1),
  280. +   fCurrentEntry(1),
  281.     fBlockSize(blockSize),
  282. -   fDirectory(directory),
  283. -   fOffset(block * blockSize + sizeof(HTreeFakeDirEntry)),
  284. +   fBlockNum(block),
  285.     fParent(parent),
  286.     fChild(NULL)
  287.  {
  288. -   TRACE("HTreeEntryIterator::HTreeEntryIterator() block %ld offset %Lx\n",
  289. -       block, fOffset);
  290. +   // fCurrentEntry is initialized to 1 to skip the fake directory entry
  291. +   fInitStatus = B_OK;
  292. +
  293. +   TRACE("HTreeEntryIterator::HTreeEntryIterator() block %lu\n", block);
  294.  }
  295.  
  296.  
  297.  status_t
  298.  HTreeEntryIterator::Init()
  299.  {
  300. -   size_t length = sizeof(HTreeCountLimit);
  301. -   HTreeCountLimit countLimit;
  302. +   TRACE("HTreeEntryIterator::Init() first entry: %lu\n",
  303. +       (uint32)fFirstEntry);
  304.    
  305. -   status_t status = fDirectory->ReadAt(fOffset, (uint8*)&countLimit,
  306. -       &length);
  307. -  
  308. -   if (status != B_OK)
  309. -       return status;
  310. -  
  311. -   if (length != sizeof(HTreeCountLimit)) {
  312. -       ERROR("HTreeEntryIterator::Init() bad length %ld fOffset 0x%Lx\n",
  313. -           length, fOffset);
  314. +   if (fInitStatus != B_OK)
  315. +       return fInitStatus;
  316. +
  317. +   CachedBlock cached(fVolume);
  318. +   const uint8* block = cached.SetTo(fBlockNum);
  319. +   if (block == NULL) {
  320. +       ERROR("Failed to read htree entry block.\n");
  321.         fCount = fLimit = 0;
  322. -       return B_ERROR;
  323. +       return B_IO_ERROR;
  324.     }
  325. -  
  326. -   fCount = countLimit.Count();
  327. -   fLimit = countLimit.Limit();
  328.  
  329. +   HTreeCountLimit* countLimit = (HTreeCountLimit*)(
  330. +       &((HTreeEntry*)block)[fFirstEntry]);
  331. +
  332. +   fCount = countLimit->Count();
  333. +   fLimit = countLimit->Limit();
  334. +
  335.     if (fCount >= fLimit) {
  336. -       ERROR("HTreeEntryIterator::Init() bad fCount %d fOffset 0x%Lx\n",
  337. -           fCount, fOffset);
  338. +       ERROR("HTreeEntryIterator::Init() bad fCount %lu\n", (uint32)fCount);
  339.         fCount = fLimit = 0;
  340.         return B_ERROR;
  341.     }
  342.  
  343. -   if (fParent != NULL &&
  344. -       fLimit != ((fBlockSize - sizeof(HTreeFakeDirEntry))
  345. -           / sizeof(HTreeEntry)) ) {
  346. -       ERROR("HTreeEntryIterator::Init() bad fLimit %d should be %ld "
  347. -           "fOffset 0x%Lx\n", fLimit, (fBlockSize - sizeof(HTreeFakeDirEntry))
  348. -               / sizeof(HTreeEntry), fOffset);
  349. +   if (fLimit != fBlockSize / sizeof(HTreeEntry) - fFirstEntry) {
  350. +       ERROR("HTreeEntryIterator::Init() bad fLimit %lu should be %lu "
  351. +           "at block %lu\n", (uint32)fLimit, fBlockSize / sizeof(HTreeEntry)
  352. +               - fFirstEntry, fBlockNum);
  353.         fCount = fLimit = 0;
  354.         return B_ERROR;
  355. -   }
  356. +   }
  357.  
  358. -   TRACE("HTreeEntryIterator::Init() count 0x%x limit 0x%x\n", fCount,
  359. -       fLimit);
  360. +   TRACE("HTreeEntryIterator::Init() count %lu limit %lu\n",
  361. +       (uint32)fCount, (uint32)fLimit);
  362.  
  363. -   fMaxOffset = fOffset + (fCount - 1) * sizeof(HTreeEntry);
  364. -  
  365.     return B_OK;
  366.  }
  367.  
  368.  
  369.  HTreeEntryIterator::~HTreeEntryIterator()
  370.  {
  371. +   delete fChild;
  372.  }
  373.  
  374.  
  375. @@ -109,68 +120,80 @@
  376.  HTreeEntryIterator::Lookup(uint32 hash, int indirections,
  377.     DirectoryIterator** directoryIterator)
  378.  {
  379. -   off_t start = fOffset + sizeof(HTreeEntry);
  380. -   off_t end = fMaxOffset;
  381. -   off_t middle = start;
  382. -   size_t entrySize = sizeof(HTreeEntry);
  383. -   HTreeEntry entry;
  384. +   TRACE("HTreeEntryIterator::Lookup()\n");
  385. +
  386. +   if (fCount == 0)
  387. +       return B_ENTRY_NOT_FOUND;
  388. +
  389. +   CachedBlock cached(fVolume);
  390. +   const uint8* block = cached.SetTo(fBlockNum);
  391. +   if (block == NULL) {
  392. +       ERROR("Failed to read htree entry block.\n");
  393. +       // Fallback to linear search
  394. +       *directoryIterator = new(std::nothrow)
  395. +           DirectoryIterator(fDirectory);
  396. +
  397. +       if (*directoryIterator == NULL)
  398. +           return B_NO_MEMORY;
  399. +
  400. +       return B_OK;
  401. +   }
  402. +
  403. +   HTreeEntry* start = (HTreeEntry*)block + fCurrentEntry + 1;
  404. +   HTreeEntry* end = (HTreeEntry*)block + fCount + fFirstEntry - 1;
  405. +   HTreeEntry* middle = start;
  406.    
  407. +   TRACE("HTreeEntryIterator::Lookup() current entry: %lu\n",
  408. +       (uint32)fCurrentEntry);
  409. +   TRACE("HTreeEntryIterator::Lookup() indirections: %d s:%p m:%p e:%p\n",
  410. +       indirections, start, middle, end);
  411. +
  412.     while (start <= end) {
  413. -       middle = (end - start) / 2;
  414. -       middle -= middle % entrySize; // Alignment
  415. -       middle += start;
  416. +       middle = (HTreeEntry*)((end - start) / 2
  417. +           + start);
  418.  
  419. -       TRACE("HTreeEntryIterator::Lookup() %d 0x%Lx 0x%Lx 0x%Lx\n",
  420. -           indirections, start, end, middle);
  421. -      
  422. -       status_t status = fDirectory->ReadAt(middle, (uint8*)&entry,
  423. -           &entrySize);
  424. +       TRACE("HTreeEntryIterator::Lookup() indirections: %d s:%p m:%p e:%p\n",
  425. +           indirections, start, middle, end);
  426.  
  427. -       TRACE("HTreeEntryIterator::Lookup() %lx %lx\n", hash, entry.Hash());
  428. -      
  429. -       if (status != B_OK)
  430. -           return status;
  431. -       else if (entrySize != sizeof(entry)) {
  432. -           // Fallback to linear search
  433. -           *directoryIterator = new(std::nothrow)
  434. -               DirectoryIterator(fDirectory);
  435. -          
  436. -           if (*directoryIterator == NULL)
  437. -               return B_NO_MEMORY;
  438. -          
  439. -           return B_OK;
  440. -       }
  441. -      
  442. -       if (hash >= entry.Hash())
  443. -           start = middle + entrySize;
  444. +       TRACE("HTreeEntryIterator::Lookup() %lx %lx\n", hash, middle->Hash());
  445. +
  446. +       if (hash >= middle->Hash())
  447. +           start = middle + 1;
  448.         else
  449. -           end = middle - entrySize;
  450. +           end = middle - 1;
  451.     }
  452.  
  453. -   status_t status = fDirectory->ReadAt(start - entrySize, (uint8*)&entry,
  454. -       &entrySize);
  455. -   if (status != B_OK)
  456. -       return status;
  457. -  
  458. +   --start;
  459. +
  460. +   fCurrentEntry = ((uint8*)start - block) / sizeof(HTreeEntry);
  461. +
  462.     if (indirections == 0) {
  463. +       TRACE("HTreeEntryIterator::Lookup(): Creating an indexed directory "
  464. +           "iterator starting at block: %lu, hash: 0x%lX\n", start->Block(),
  465. +           start->Hash());
  466.         *directoryIterator = new(std::nothrow)
  467. -           IndexedDirectoryIterator(entry.Block() * fBlockSize, fBlockSize,
  468. -           fDirectory, this);
  469. -      
  470. +           DirectoryIterator(fDirectory, start->Block() * fBlockSize, this);
  471. +
  472.         if (*directoryIterator == NULL)
  473.             return B_NO_MEMORY;
  474.  
  475.         return B_OK;
  476.     }
  477.  
  478. +   TRACE("HTreeEntryIterator::Lookup(): Creating a HTree entry iterator "
  479. +       "starting at block: %lu, hash: 0x%lX\n", start->Block(), start->Hash());
  480. +   uint32 blockNum;
  481. +   status_t status = fDirectory->FindBlock(start->Block() * fBlockSize,
  482. +       blockNum);
  483. +   if (status != B_OK)
  484. +       return status;
  485. +
  486.     delete fChild;
  487.  
  488. -   fChild = new(std::nothrow) HTreeEntryIterator(entry.Block(), fBlockSize,
  489. -       fDirectory, this, entry.Hash() & 1 == 1);
  490. -  
  491. +   fChild = new(std::nothrow) HTreeEntryIterator(blockNum, fBlockSize,
  492. +       fDirectory, this, start->Hash() & 1 == 1);
  493.     if (fChild == NULL)
  494.         return B_NO_MEMORY;
  495. -   fChildDeleter.SetTo(fChild);
  496.    
  497.     status = fChild->Init();
  498.     if (status != B_OK)
  499. @@ -181,40 +204,62 @@
  500.  
  501.  
  502.  status_t
  503. -HTreeEntryIterator::GetNext(off_t& childOffset)
  504. +HTreeEntryIterator::GetNext(uint32& childBlock)
  505.  {
  506. -   size_t entrySize = sizeof(HTreeEntry);
  507. -   fOffset += entrySize;
  508. -   bool firstEntry = fOffset >= fMaxOffset;
  509. -  
  510. -   if (firstEntry) {
  511. -       if (fParent == NULL)
  512. +   fCurrentEntry++;
  513. +   TRACE("HTreeEntryIterator::GetNext(): current entry: %lu\n",
  514. +       (uint32)fCurrentEntry);
  515. +   bool endOfBlock = fCurrentEntry >= (fCount + fFirstEntry);
  516. +
  517. +   if (endOfBlock) {
  518. +       TRACE("HTreeEntryIterator::GetNext(): end of entries in the block\n");
  519. +       if (fParent == NULL) {
  520. +           TRACE("HTreeEntryIterator::GetNext(): block was the root block\n");
  521.             return B_ENTRY_NOT_FOUND;
  522. +       }
  523.        
  524. -       status_t status = fParent->GetNext(fOffset);
  525. +       uint32 logicalBlock;
  526. +       status_t status = fParent->GetNext(logicalBlock);
  527.         if (status != B_OK)
  528.             return status;
  529.        
  530. +       TRACE("HTreeEntryIterator::GetNext(): moving to next block: %lu\n",
  531. +           logicalBlock);
  532. +      
  533. +       status = fDirectory->FindBlock(logicalBlock * fBlockSize, fBlockNum);
  534. +       if (status != B_OK)
  535. +           return status;
  536. +      
  537. +       fFirstEntry = 1; // Skip fake directory entry
  538. +       fCurrentEntry = 1;
  539.         status = Init();
  540.         if (status != B_OK)
  541.             return status;
  542.  
  543.         fHasCollision = fParent->HasCollision();
  544.     }
  545. +
  546. +   CachedBlock cached(fVolume);
  547. +   const uint8* block = cached.SetTo(fBlockNum);
  548. +   if (block == NULL)
  549. +       return B_IO_ERROR;
  550. +
  551. +   HTreeEntry* entry = &((HTreeEntry*)block)[fCurrentEntry];
  552. +
  553. +   if (!endOfBlock)
  554. +       fHasCollision = (entry[fCurrentEntry].Hash() & 1) == 1;
  555.    
  556. -   HTreeEntry entry;
  557. -   status_t status = fDirectory->ReadAt(fOffset, (uint8*)&entry, &entrySize);
  558. -   if (status != B_OK)
  559. -       return status;
  560. -   else if (entrySize != sizeof(entry)) {
  561. -       // Weird error, try to skip it
  562. -       return GetNext(childOffset);
  563. -   }
  564. +   TRACE("HTreeEntryIterator::GetNext(): next block: %lu\n",
  565. +       entry->Block());
  566. +
  567. +   childBlock = entry->Block();
  568.    
  569. -   if (!firstEntry)
  570. -       fHasCollision = (entry.Hash() & 1) == 1;
  571. -  
  572. -   childOffset = entry.Block() * fBlockSize;
  573. -  
  574.     return B_OK;
  575.  }
  576. +
  577. +
  578. +status_t
  579. +HTreeEntryIterator::InsertEntry(uint32 hash, uint32 block, bool hasCollision)
  580. +{
  581. +   return B_OK;
  582. +}
  583. Index: src/add-ons/kernel/file_systems/ext2/Inode.h
  584. ===================================================================
  585. --- src/add-ons/kernel/file_systems/ext2/Inode.h    (revision 37957)
  586. +++ src/add-ons/kernel/file_systems/ext2/Inode.h    (working copy)
  587. @@ -12,7 +12,7 @@
  588.  #include "Volume.h"
  589.  
  590.  
  591. -class Inode {
  592. +class Inode : public TransactionListener {
  593.  public:
  594.                         Inode(Volume* volume, ino_t id);
  595.                         ~Inode();
  596. @@ -22,7 +22,11 @@
  597.             ino_t       ID() const { return fID; }
  598.  
  599.             rw_lock*    Lock() { return &fLock; }
  600. +           void        WriteLockInTransaction(Transaction& transaction);
  601.  
  602. +           status_t    UpdateNodeFromDisk();
  603. +           status_t    WriteBack(Transaction& transaction);
  604. +
  605.             bool        IsDirectory() const
  606.                             { return S_ISDIR(Mode()); }
  607.             bool        IsFile() const
  608. @@ -32,44 +36,166 @@
  609.  
  610.             status_t    CheckPermissions(int accessMode) const;
  611.  
  612. -           mode_t      Mode() const { return fNode->Mode(); }
  613. -           int32       Flags() const { return fNode->Flags(); }
  614. +           mode_t      Mode() const { return fNode.Mode(); }
  615. +           int32       Flags() const { return fNode.Flags(); }
  616.  
  617. -           off_t       Size() const { return fNode->Size(); }
  618. +           off_t       Size() const { return fNode.Size(); }
  619.             time_t      ModificationTime() const
  620. -                           { return fNode->ModificationTime(); }
  621. +                           { return fNode.ModificationTime(); }
  622.             time_t      CreationTime() const
  623. -                           { return fNode->CreationTime(); }
  624. +                           { return fNode.CreationTime(); }
  625.             time_t      AccessTime() const
  626. -                           { return fNode->AccessTime(); }
  627. +                           { return fNode.AccessTime(); }
  628.  
  629.             //::Volume* _Volume() const { return fVolume; }
  630.             Volume*     GetVolume() const { return fVolume; }
  631.  
  632.             status_t    FindBlock(off_t offset, uint32& block);
  633.             status_t    ReadAt(off_t pos, uint8 *buffer, size_t *length);
  634. +           status_t    WriteAt(Transaction& transaction, off_t pos, uint8* buffer, size_t* length);
  635. +           status_t    FillGapWithZeros(off_t start, off_t end);
  636.  
  637. +           status_t    Resize(Transaction& transaction, off_t size);
  638. +
  639.             status_t    AttributeBlockReadAt(off_t pos, uint8 *buffer,
  640.                             size_t *length);
  641.  
  642. -           ext2_inode& Node() { return *fNode; }
  643. +           ext2_inode& Node() { return fNode; }
  644.  
  645. +           status_t    InitDirectory(Transaction& transaction, Inode* parent);
  646. +
  647. +   static  status_t    Create(Transaction& transaction, Inode* parent,
  648. +                           const char* name, int32 mode, int openMode,
  649. +                           uint32 type, bool* _created = NULL,
  650. +                           ino_t* _id = NULL, Inode** _inode = NULL,
  651. +                           fs_vnode_ops* vnodeOps = NULL,
  652. +                           uint32 publishFlags = 0);
  653. +
  654.             void*       FileCache() const { return fCache; }
  655.             void*       Map() const { return fMap; }
  656. +           status_t    DisableFileCache();
  657. +           bool        IsFileCacheDisabled() const { return !fCached; }
  658.  
  659. +protected:
  660. +   virtual void        TransactionDone(bool success);
  661. +   virtual void        RemovedFromTransaction();
  662. +
  663. +
  664.  private:
  665. +                       Inode(Volume* volume);
  666.                         Inode(const Inode&);
  667.                         Inode &operator=(const Inode&);
  668.                             // no implementation
  669.  
  670. +           status_t    _EnlargeDataStream(Transaction& transaction,
  671. +                           off_t size);
  672. +           status_t    _ShrinkDataStream(Transaction& transaction, off_t size);
  673. +
  674. +           status_t    _FreeDirectBlocks(Transaction& transaction,
  675. +                           uint32* block, uint32* maxPos);
  676. +           status_t    _FreeIndirectBlock(Transaction& transaction,
  677. +                           uint32* indirectBlock, uint32* maxIndirectPos);
  678. +           status_t    _FreeDoubleIndirectBlock(Transaction& transaction,
  679. +                           uint32* doubleIndirectBlock,
  680. +                           uint32* maxDoubleIndirectPos);
  681. +           status_t    _FreeTripleIndirectBlock(Transaction& transaction,
  682. +                           uint32* tripleIndirectBlock,
  683. +                           uint32* maxTripleIndirectPos);
  684. +
  685. +           status_t    _GetBlockFromAllocation(Transaction& transaction,
  686. +                           uint32& blocksNeeded, uint32& allocated,
  687. +                           uint32& allocatedPos, uint32& block);
  688. +           void        _MapBlocksInIndirectBlock(uint32* block,
  689. +                           uint32* maxPos, uint32 increment, uint32& length,
  690. +                           uint32& rangePos);
  691. +           status_t    _MapBlocksInDoubleIndirectBlock(
  692. +                           Transaction& transaction,
  693. +                           uint32* doubleIndirectBlock,
  694. +                           uint32* maxDoubleIndirectPos, uint32* indirectBlock,
  695. +                           uint32* maxIndirectPos, uint32 increment,
  696. +                           uint32& blocksNeeded, uint32& allocated,
  697. +                           uint32& allocatedPos, uint32& length,
  698. +                           uint32& rangePos);
  699. +           status_t    _MapBlocksInDataStream(Transaction& transaction,
  700. +                           uint32 mapPos, uint32 rangePos, uint32 length,
  701. +                           uint32 preferredBlockGroup);
  702. +
  703. +
  704. +           rw_lock     fLock;
  705. +           ::Volume*   fVolume;
  706. +           ino_t       fID;
  707. +           void*       fCache;
  708. +           void*       fMap;
  709. +           bool        fCached;
  710. +           ext2_inode  fNode;
  711. +           uint32      fNodeSize;
  712. +               // Inodes have a varible size, but the important
  713. +               // information is always the same size (except in ext4)
  714. +           ext2_xattr_header* fAttributesBlock;
  715. +           status_t    fInitStatus;
  716. +};
  717. +
  718. +
  719. +// The Vnode class provides a convenience layer upon get_vnode(), so that
  720. +// you don't have to call put_vnode() anymore, which may make code more
  721. +// readable in some cases
  722. +
  723. +class Vnode {
  724. +public:
  725. +   Vnode(Volume* volume, ino_t id)
  726. +       :
  727. +       fInode(NULL)
  728. +   {
  729. +       SetTo(volume, id);
  730. +   }
  731. +
  732. +   Vnode()
  733. +       :
  734. +       fStatus(B_NO_INIT),
  735. +       fInode(NULL)
  736. +   {
  737. +   }
  738. +
  739. +   ~Vnode()
  740. +   {
  741. +       Unset();
  742. +   }
  743. +
  744. +   status_t InitCheck()
  745. +   {
  746. +       return fStatus;
  747. +   }
  748. +
  749. +   void Unset()
  750. +   {
  751. +       if (fInode != NULL) {
  752. +           put_vnode(fInode->GetVolume()->FSVolume(), fInode->ID());
  753. +           fInode = NULL;
  754. +           fStatus = B_NO_INIT;
  755. +       }
  756. +   }
  757. +
  758. +   status_t SetTo(Volume* volume, ino_t id)
  759. +   {
  760. +       Unset();
  761. +
  762. +       return fStatus = get_vnode(volume->FSVolume(), id, (void**)&fInode);
  763. +   }
  764. +
  765. +   status_t Get(Inode** _inode)
  766. +   {
  767. +       *_inode = fInode;
  768. +       return fStatus;
  769. +   }
  770. +
  771. +   void Keep()
  772. +   {
  773. +       fInode = NULL;
  774. +   }
  775. +
  776.  private:
  777. -   rw_lock             fLock;
  778. -   ::Volume*           fVolume;
  779. -   ino_t               fID;
  780. -   void*               fCache;
  781. -   void*               fMap;
  782. -   ext2_inode*         fNode;
  783. -   ext2_xattr_header*  fAttributesBlock;
  784. +   status_t    fStatus;
  785. +   Inode*      fInode;
  786.  };
  787.  
  788.  #endif // INODE_H
  789. Index: src/add-ons/kernel/file_systems/ext2/Volume.cpp
  790. ===================================================================
  791. --- src/add-ons/kernel/file_systems/ext2/Volume.cpp (revision 37957)
  792. +++ src/add-ons/kernel/file_systems/ext2/Volume.cpp (working copy)
  793. @@ -20,7 +20,10 @@
  794.  
  795.  #include <util/AutoLock.h>
  796.  
  797. +#include "CachedBlock.h"
  798.  #include "Inode.h"
  799. +#include "InodeJournal.h"
  800. +#include "NoJournal.h"
  801.  
  802.  
  803.  //#define TRACE_EXT2
  804. @@ -199,7 +202,7 @@
  805.     // TODO: check some more values!
  806.     if (Magic() != (uint32)EXT2_SUPER_BLOCK_MAGIC)
  807.         return false;
  808. -
  809. +  
  810.     return true;
  811.  }
  812.  
  813. @@ -210,6 +213,9 @@
  814.  Volume::Volume(fs_volume* volume)
  815.     :
  816.     fFSVolume(volume),
  817. +   fBlockAllocator(this),
  818. +   fInodeAllocator(this),
  819. +   fJournalInode(NULL),
  820.     fFlags(0),
  821.     fGroupBlocks(NULL),
  822.     fRootNode(NULL)
  823. @@ -220,6 +226,7 @@
  824.  
  825.  Volume::~Volume()
  826.  {
  827. +   TRACE("Volume destructor.\n");
  828.     if (fGroupBlocks != NULL) {
  829.         uint32 blockCount = (fNumGroups + fGroupsPerBlock - 1)
  830.             / fGroupsPerBlock;
  831. @@ -252,8 +259,14 @@
  832.  status_t
  833.  Volume::Mount(const char* deviceName, uint32 flags)
  834.  {
  835. -   flags |= B_MOUNT_READ_ONLY;
  836. +   // flags |= B_MOUNT_READ_ONLY;
  837.         // we only support read-only for now
  838. +  
  839. +   if ((flags & B_MOUNT_READ_ONLY) != 0) {
  840. +       TRACE("Volume::Mount(): Read only\n");
  841. +   } else {
  842. +       TRACE("Volume::Mount(): Read write\n");
  843. +   }
  844.  
  845.     DeviceOpener opener(deviceName, (flags & B_MOUNT_READ_ONLY) != 0
  846.         ? O_RDONLY : O_RDWR);
  847. @@ -278,10 +291,17 @@
  848.     fBlockSize = 1UL << fSuperBlock.BlockShift();
  849.     fFirstDataBlock = fSuperBlock.FirstDataBlock();
  850.  
  851. +   fFreeBlocks = fSuperBlock.FreeBlocks();
  852. +   fFreeInodes = fSuperBlock.FreeInodes();
  853. +
  854. +   uint32 numBlocks = fSuperBlock.NumBlocks() - fFirstDataBlock;
  855. +   uint32 blocksPerGroup = fSuperBlock.BlocksPerGroup();
  856. +   fNumGroups = numBlocks / blocksPerGroup;
  857. +   if (numBlocks % blocksPerGroup != 0)
  858. +       fNumGroups++;
  859. +
  860. +   fGroupsPerBlock = fBlockSize / sizeof(ext2_block_group);
  861.     fNumInodes = fSuperBlock.NumInodes();
  862. -   fNumGroups = (fSuperBlock.NumBlocks() - fFirstDataBlock - 1)
  863. -       / fSuperBlock.BlocksPerGroup() + 1;
  864. -   fGroupsPerBlock = fBlockSize / sizeof(ext2_block_group);
  865.  
  866.     TRACE("block size %ld, num groups %ld, groups per block %ld, first %lu\n",
  867.         fBlockSize, fNumGroups, fGroupsPerBlock, fFirstDataBlock);
  868. @@ -309,7 +329,55 @@
  869.     fBlockCache = opener.InitCache(NumBlocks(), fBlockSize);
  870.     if (fBlockCache == NULL)
  871.         return B_ERROR;
  872. +  
  873. +   TRACE("Volume::Mount(): Initialized block cache: %p\n", fBlockCache);
  874.  
  875. +   // initialize journal
  876. +   if ((fSuperBlock.CompatibleFeatures() & EXT2_FEATURE_HAS_JOURNAL) != 0) {
  877. +       // TODO: There should be a mount option to ignore the existent journal
  878. +       if (fSuperBlock.JournalInode() != 0) {
  879. +           fJournalInode = new(std::nothrow) Inode(this,
  880. +               fSuperBlock.JournalInode());
  881. +
  882. +           if (fJournalInode == NULL)
  883. +               return B_NO_MEMORY;
  884. +
  885. +           TRACE("Opening an on disk, inode mapped journal.\n");
  886. +           fJournal = new(std::nothrow) InodeJournal(fJournalInode);
  887. +       } else {
  888. +           // TODO: external journal
  889. +           TRACE("Can not open an external journal.\n");
  890. +           return B_NOT_SUPPORTED;
  891. +       }
  892. +   } else {
  893. +       TRACE("Opening a fake journal (NoJournal).\n");
  894. +       fJournal = new(std::nothrow) NoJournal(this);
  895. +   }
  896. +
  897. +   if (fJournal == NULL) {
  898. +       TRACE("No memory to create the journal\n");
  899. +       return B_NO_MEMORY;
  900. +   }
  901. +
  902. +   status = fJournal->InitCheck();
  903. +   if (status != B_OK)
  904. +       return status;
  905. +
  906. +   // TODO: Only recover if asked to
  907. +   status = fJournal->Recover();
  908. +   if (status != B_OK)
  909. +       return status;
  910. +
  911. +   status = fJournal->StartLog();
  912. +   if (status != B_OK)
  913. +       return status;
  914. +
  915. +   // Initialize allocators
  916. +   status = fBlockAllocator.Initialize();
  917. +   if (status != B_OK)
  918. +       return status;
  919. +
  920. +   // ready
  921.     status = get_vnode(fFSVolume, EXT2_ROOT_NODE, (void**)&fRootNode);
  922.     if (status != B_OK) {
  923.         TRACE("could not create root node: get_vnode() failed!\n");
  924. @@ -342,11 +410,22 @@
  925.  status_t
  926.  Volume::Unmount()
  927.  {
  928. +   TRACE("Volume::Unmount()\n");
  929. +
  930. +   status_t status = fJournal->Deinit();
  931. +
  932. +   delete fJournal;
  933. +   delete fJournalInode;
  934. +
  935. +   TRACE("Volume::Unmount(): Putting root node\n");
  936.     put_vnode(fFSVolume, RootNode()->ID());
  937. +   TRACE("Volume::Unmount(): Deleting the block cache\n");
  938.     block_cache_delete(fBlockCache, !IsReadOnly());
  939. +   TRACE("Volume::Unmount(): Closing device\n");
  940.     close(fDevice);
  941.  
  942. -   return B_OK;
  943. +   TRACE("Volume::Unmount(): Done\n");
  944. +   return status;
  945.  }
  946.  
  947.  
  948. @@ -443,6 +522,122 @@
  949.  }
  950.  
  951.  
  952. +status_t
  953. +Volume::AllocateInode(Transaction& transaction, Inode* parent, int32 mode,
  954. +   ino_t& id)
  955. +{
  956. +   if (IsReadOnly())
  957. +       return B_READ_ONLY_DEVICE;
  958. +
  959. +   status_t status = fInodeAllocator.New(transaction, parent, mode, id);
  960. +   if (status == B_OK)
  961. +       --fFreeInodes;
  962. +
  963. +   return status;
  964. +}
  965. +
  966. +
  967. +status_t
  968. +Volume::AllocateBlocks(Transaction& transaction, uint32 minimum, uint32 maximum,
  969. +   uint32& blockGroup, uint32& start, uint32& length)
  970. +{
  971. +   TRACE("Volume::AllocateBlocks()\n");
  972. +   if (IsReadOnly())
  973. +       return B_READ_ONLY_DEVICE;
  974. +
  975. +   TRACE("Volume::AllocateBlocks(): Calling the block allocator\n");
  976. +
  977. +   status_t status = fBlockAllocator.AllocateBlocks(transaction, minimum,
  978. +       maximum, blockGroup, start, length);
  979. +   if (status != B_OK)
  980. +       return status;
  981. +
  982. +   TRACE("Volume::AllocateBlocks(): Allocated %lu blocks\n", length);
  983. +
  984. +   fFreeBlocks -= length;
  985. +
  986. +   return WriteSuperBlock(transaction);
  987. +}
  988. +
  989. +
  990. +status_t
  991. +Volume::FreeBlocks(Transaction& transaction, uint32 start, uint32 length)
  992. +{
  993. +   if (IsReadOnly())
  994. +       return B_READ_ONLY_DEVICE;
  995. +
  996. +   status_t status = fBlockAllocator.Free(transaction, start, length);
  997. +   if (status != B_OK)
  998. +       return status;
  999. +
  1000. +   fFreeBlocks += length;
  1001. +
  1002. +   return WriteSuperBlock(transaction);
  1003. +}
  1004. +
  1005. +
  1006. +status_t
  1007. +Volume::LoadSuperBlock()
  1008. +{
  1009. +   CachedBlock cached(this);
  1010. +   const uint8* block = cached.SetTo(fFirstDataBlock);
  1011. +
  1012. +   if (block == NULL)
  1013. +       return B_IO_ERROR;
  1014. +
  1015. +   if (fFirstDataBlock == 0)
  1016. +       memcpy(&fSuperBlock, block + 1024, sizeof(fSuperBlock));
  1017. +   else
  1018. +       memcpy(&fSuperBlock, block, sizeof(fSuperBlock));
  1019. +
  1020. +   fFreeBlocks = fSuperBlock.FreeBlocks();
  1021. +   fFreeInodes = fSuperBlock.FreeInodes();
  1022. +
  1023. +   return B_OK;
  1024. +}
  1025. +
  1026. +
  1027. +status_t
  1028. +Volume::WriteSuperBlock(Transaction& transaction)
  1029. +{
  1030. +   TRACE("Volume::WriteSuperBlock()\n");
  1031. +   fSuperBlock.SetFreeBlocks(fFreeBlocks);
  1032. +   fSuperBlock.SetFreeInodes(fFreeInodes);
  1033. +   // TODO: Rest of fields that can be modified
  1034. +
  1035. +   CachedBlock cached(this);
  1036. +   uint8* block = cached.SetToWritable(transaction, fFirstDataBlock);
  1037. +
  1038. +   if (block == NULL)
  1039. +       return B_IO_ERROR;
  1040. +
  1041. +   if (fFirstDataBlock == 0)
  1042. +       memcpy(block + 1024, &fSuperBlock, sizeof(fSuperBlock));
  1043. +   else
  1044. +       memcpy(block, &fSuperBlock, sizeof(fSuperBlock));
  1045. +
  1046. +   TRACE("Volume::WriteSuperBlock(): Done\n");
  1047. +
  1048. +   return B_OK;
  1049. +}
  1050. +
  1051. +
  1052. +status_t
  1053. +Volume::FlushDevice()
  1054. +{
  1055. +   TRACE("Volume::FlushDevice(): %p, %p\n", this, fBlockCache);
  1056. +   return block_cache_sync(fBlockCache);
  1057. +}
  1058. +
  1059. +
  1060. +status_t
  1061. +Volume::Sync()
  1062. +{
  1063. +   TRACE("Volume::Sync()\n");
  1064. +   return fJournal->FlushLogAndBlocks();
  1065. +}
  1066. +
  1067. +
  1068.  // #pragma mark - Disk scanning and initialization
  1069.  
  1070.  
  1071. @@ -460,3 +655,18 @@
  1072.         ? B_OK : B_NOT_SUPPORTED;
  1073.  }
  1074.  
  1075. +
  1076. +void
  1077. +Volume::TransactionDone(bool success)
  1078. +{
  1079. +   status_t status = LoadSuperBlock();
  1080. +   if (status != B_OK)
  1081. +       panic("Failed to relead ext2 superblock.\n");
  1082. +}
  1083. +
  1084. +
  1085. +void
  1086. +Volume::RemovedFromTransaction()
  1087. +{
  1088. +   // TODO: Does it make a difference?
  1089. +}
  1090. Index: src/add-ons/kernel/file_systems/ext2/Journal.cpp
  1091. ===================================================================
  1092. --- src/add-ons/kernel/file_systems/ext2/Journal.cpp    (revision 0)
  1093. +++ src/add-ons/kernel/file_systems/ext2/Journal.cpp    (revision 0)
  1094. @@ -0,0 +1,1256 @@
  1095. +/*
  1096. + * Copyright 2001-2010, Haiku Inc. All rights reserved.
  1097. + * This file may be used under the terms of the MIT License.
  1098. + *
  1099. + * Authors:
  1100. + *     Janito V. Ferreira Filho
  1101. + */
  1102. +
  1103. +#include "Journal.h"
  1104. +
  1105. +#include <new>
  1106. +#include <string.h>
  1107. +#include <unistd.h>
  1108. +
  1109. +#include <fs_cache.h>
  1110. +
  1111. +#include "CachedBlock.h"
  1112. +#include "HashRevokeManager.h"
  1113. +
  1114. +
  1115. +//#define TRACE_EXT2
  1116. +#ifdef TRACE_EXT2
  1117. +#  define TRACE(x...) dprintf("\33[34mext2:\33[0m " x)
  1118. +#else
  1119. +#  define TRACE(x...) ;
  1120. +#endif
  1121. +
  1122. +
  1123. +class LogEntry : public DoublyLinkedListLinkImpl<LogEntry> {
  1124. +public:
  1125. +                           LogEntry(Journal* journal, uint32 logStart,
  1126. +                               uint32 length);
  1127. +                           ~LogEntry();
  1128. +
  1129. +           uint32          Start() const { return fStart; }
  1130. +           uint32          CommitID() const { return fCommitID; }
  1131. +
  1132. +           Journal*        GetJournal() { return fJournal; }
  1133. +
  1134. +private:
  1135. +           Journal*        fJournal;
  1136. +           uint32          fStart;
  1137. +           uint32          fCommitID;
  1138. +};
  1139. +
  1140. +
  1141. +LogEntry::LogEntry(Journal* journal, uint32 logStart, uint32 commitID)
  1142. +   :
  1143. +   fJournal(journal),
  1144. +   fStart(logStart),
  1145. +   fCommitID(commitID)
  1146. +{
  1147. +}
  1148. +
  1149. +
  1150. +LogEntry::~LogEntry()
  1151. +{
  1152. +}
  1153. +
  1154. +
  1155. +/*void
  1156. +add_to_iovec(iovec* vecs, int32& index, int32 max, const void* address,
  1157. +   size_t size)
  1158. +{
  1159. +   if (index > 0 && (addr_t)vecs[index - 1].iov_base
  1160. +       + vecs[index - 1].iov_len == (addr_t)address) {
  1161. +       // the iovec can be combined with the previous one
  1162. +       vecs[index - 1].iov_len += size;
  1163. +       return;
  1164. +   }
  1165. +
  1166. +   if (index == max)
  1167. +       panic("no more space for iovecs!");
  1168. +  
  1169. +   // start a new iovec
  1170. +   vecs[index].iov_base = const_cast<void*>(address);
  1171. +   vecs[index].iov_len = size;
  1172. +   index++;
  1173. +}*/
  1174. +
  1175. +
  1176. +void
  1177. +JournalHeader::MakeDescriptor(uint32 sequence)
  1178. +{
  1179. +   this->magic = B_HOST_TO_BENDIAN_INT32(JOURNAL_MAGIC);
  1180. +   this->sequence = B_HOST_TO_BENDIAN_INT32(sequence);
  1181. +   this->block_type = B_HOST_TO_BENDIAN_INT32(JOURNAL_DESCRIPTOR_BLOCK);
  1182. +}
  1183. +
  1184. +
  1185. +void
  1186. +JournalHeader::MakeCommit(uint32 sequence)
  1187. +{
  1188. +   this->magic = B_HOST_TO_BENDIAN_INT32(JOURNAL_MAGIC);
  1189. +   this->sequence = B_HOST_TO_BENDIAN_INT32(sequence);
  1190. +   this->block_type = B_HOST_TO_BENDIAN_INT32(JOURNAL_COMMIT_BLOCK);
  1191. +}
  1192. +
  1193. +
  1194. +Journal::Journal(Volume* fsVolume, Volume* jVolume)
  1195. +   :
  1196. +   fJournalVolume(jVolume),
  1197. +   fJournalBlockCache(jVolume->BlockCache()),
  1198. +   fFilesystemVolume(fsVolume),
  1199. +   fFilesystemBlockCache(fsVolume->BlockCache()),
  1200. +   fRevokeManager(NULL),
  1201. +   fInitStatus(B_OK),
  1202. +   fBlockSize(sizeof(JournalSuperBlock)),
  1203. +   fFirstCommitID(0),
  1204. +   fFirstCacheCommitID(0),
  1205. +   fFirstLogBlock(1),
  1206. +   fLogSize(0),
  1207. +   fVersion(0),
  1208. +   fLogStart(0),
  1209. +   fLogEnd(0),
  1210. +   fFreeBlocks(0),
  1211. +   fMaxTransactionSize(0),
  1212. +   fCurrentCommitID(0),
  1213. +   fHasSubTransaction(false),
  1214. +   fSeparateSubTransactions(false),
  1215. +   fUnwrittenTransactions(0),
  1216. +   fTransactionID(0)
  1217. +{
  1218. +   recursive_lock_init(&fLock, "ext2 journal");
  1219. +   mutex_init(&fLogEntriesLock, "ext2 journal log entries");
  1220. +
  1221. +   HashRevokeManager* revokeManager = new(std::nothrow) HashRevokeManager;
  1222. +   TRACE("Journal::Journal(): Allocated a hash revoke manager at %p\n",
  1223. +       revokeManager);
  1224. +
  1225. +   if (revokeManager == NULL)
  1226. +       fInitStatus = B_NO_MEMORY;
  1227. +   else {
  1228. +       fInitStatus = revokeManager->Init();
  1229. +      
  1230. +       if (fInitStatus == B_OK) {
  1231. +           fRevokeManager = revokeManager;
  1232. +           fInitStatus = _LoadSuperBlock();
  1233. +       }
  1234. +   }
  1235. +}
  1236. +
  1237. +
  1238. +Journal::Journal()
  1239. +   :
  1240. +   fJournalVolume(NULL),
  1241. +   fJournalBlockCache(NULL),
  1242. +   fFilesystemVolume(NULL),
  1243. +   fFilesystemBlockCache(NULL),
  1244. +   fRevokeManager(NULL),
  1245. +   fInitStatus(B_OK),
  1246. +   fBlockSize(sizeof(JournalSuperBlock)),
  1247. +   fFirstCommitID(0),
  1248. +   fFirstCacheCommitID(0),
  1249. +   fFirstLogBlock(1),
  1250. +   fLogSize(0),
  1251. +   fVersion(0),
  1252. +   fLogStart(0),
  1253. +   fLogEnd(0),
  1254. +   fFreeBlocks(0),
  1255. +   fMaxTransactionSize(0),
  1256. +   fCurrentCommitID(0),
  1257. +   fHasSubTransaction(false),
  1258. +   fSeparateSubTransactions(false),
  1259. +   fUnwrittenTransactions(0),
  1260. +   fTransactionID(0)
  1261. +{
  1262. +   recursive_lock_init(&fLock, "ext2 journal");
  1263. +   mutex_init(&fLogEntriesLock, "ext2 journal log entries");
  1264. +}
  1265. +
  1266. +
  1267. +Journal::~Journal()
  1268. +{
  1269. +   TRACE("Journal destructor.\n");
  1270. +
  1271. +   TRACE("Journal::~Journal(): Attempting to delete revoke manager at %p\n",
  1272. +       fRevokeManager);
  1273. +   delete fRevokeManager;
  1274. +
  1275. +   recursive_lock_destroy(&fLock);
  1276. +   mutex_destroy(&fLogEntriesLock);
  1277. +}
  1278. +
  1279. +
  1280. +status_t
  1281. +Journal::InitCheck()
  1282. +{
  1283. +   return fInitStatus;
  1284. +}
  1285. +
  1286. +
  1287. +status_t
  1288. +Journal::Deinit()
  1289. +{
  1290. +   return FlushLogAndBlocks();
  1291. +}
  1292. +
  1293. +
  1294. +/*virtual*/ status_t
  1295. +Journal::StartLog()
  1296. +{
  1297. +   fLogStart = fFirstLogBlock;
  1298. +   fLogEnd = fFirstLogBlock;
  1299. +   fFreeBlocks = 0;
  1300. +
  1301. +   fCurrentCommitID = fFirstCommitID;
  1302. +   //fNextCommitID = fFirstCommitID;
  1303. +
  1304. +   return _SaveSuperBlock();
  1305. +}
  1306. +
  1307. +
  1308. +status_t
  1309. +Journal::RestartLog()
  1310. +{
  1311. +   fFirstCommitID = 1;
  1312. +
  1313. +   return B_OK;
  1314. +}
  1315. +
  1316. +
  1317. +/*virtual*/ status_t
  1318. +Journal::Lock(Transaction* owner, bool separateSubTransactions)
  1319. +{
  1320. +   TRACE("Journal::Lock()\n");
  1321. +   status_t status = recursive_lock_lock(&fLock);
  1322. +   if (status != B_OK)
  1323. +       return status;
  1324. +
  1325. +   TRACE("Journal::Lock(): Aquired lock\n");
  1326. +
  1327. +   if (!fSeparateSubTransactions && recursive_lock_get_recursion(&fLock) > 1) {
  1328. +       // reuse current transaction
  1329. +       TRACE("Journal::Lock(): Reusing current transaction\n");
  1330. +       return B_OK;
  1331. +   }
  1332. +
  1333. +   if(separateSubTransactions)
  1334. +       fSeparateSubTransactions = true;
  1335. +
  1336. +   if (owner != NULL)
  1337. +       owner->SetParent(fOwner);
  1338. +
  1339. +   fOwner = owner;
  1340. +
  1341. +   if (fOwner != NULL) {
  1342. +       if (fUnwrittenTransactions > 0) {
  1343. +           // start a sub transaction
  1344. +           TRACE("Journal::Lock(): Starting sub transaction\n");
  1345. +           cache_start_sub_transaction(fFilesystemBlockCache, fTransactionID);
  1346. +           fHasSubTransaction = true;
  1347. +       } else {
  1348. +           TRACE("Journal::Lock(): Starting new transaction\n");
  1349. +           fTransactionID = cache_start_transaction(fFilesystemBlockCache);
  1350. +       }
  1351. +
  1352. +       if (fTransactionID < B_OK) {
  1353. +           recursive_lock_unlock(&fLock);
  1354. +           return fTransactionID;
  1355. +       }
  1356. +
  1357. +       cache_add_transaction_listener(fFilesystemBlockCache, fTransactionID,
  1358. +           TRANSACTION_IDLE, _TransactionIdle, this);
  1359. +   }
  1360. +
  1361. +   return B_OK;
  1362. +}
  1363. +
  1364. +
  1365. +/*virtual*/ status_t
  1366. +Journal::Unlock(Transaction* owner, bool success)
  1367. +{
  1368. +   TRACE("Journal::Unlock()\n");
  1369. +   if (fSeparateSubTransactions
  1370. +       || recursive_lock_get_recursion(&fLock) == 1) {
  1371. +       // we only end the transaction if we unlock it
  1372. +       TRACE("Journal::Unlock(): Last lock holder\n");
  1373. +       if (owner != NULL) {
  1374. +           TRACE("Journal::Unlock(): Calling _TransactionDone\n");
  1375. +           status_t status = _TransactionDone(success);
  1376. +           if (status != B_OK)
  1377. +               return status;
  1378. +
  1379. +           bool separateSubTransactions = fSeparateSubTransactions;
  1380. +           fSeparateSubTransactions = true;
  1381. +           owner->NotifyListeners(success);
  1382. +           fSeparateSubTransactions = separateSubTransactions;
  1383. +
  1384. +           fOwner = owner->Parent();
  1385. +       } else
  1386. +           fOwner = NULL;
  1387. +
  1388. +       if (fSeparateSubTransactions
  1389. +           && recursive_lock_get_recursion(&fLock) == 1)
  1390. +           fSeparateSubTransactions = false;
  1391. +   } else
  1392. +       owner->MoveListenersTo(fOwner);
  1393. +
  1394. +   recursive_lock_unlock(&fLock);
  1395. +   return B_OK;
  1396. +}
  1397. +
  1398. +
  1399. +status_t
  1400. +Journal::MapBlock(uint32 logical, uint32& physical)
  1401. +{
  1402. +   TRACE("Journal::MapBlock()\n");
  1403. +   physical = logical;
  1404. +  
  1405. +   return B_OK;
  1406. +}
  1407. +
  1408. +
  1409. +inline uint32
  1410. +Journal::FreeLogBlocks() const
  1411. +{
  1412. +   TRACE("Journal::FreeLogBlocks(): start: %lu, end: %lu, size: %lu\n",
  1413. +       fLogStart, fLogEnd, fLogSize);
  1414. +   return fLogStart <= fLogEnd
  1415. +       ? fLogSize - fLogEnd + fLogStart - 1
  1416. +       : fLogStart - fLogEnd;
  1417. +}
  1418. +
  1419. +
  1420. +status_t
  1421. +Journal::FlushLogAndBlocks()
  1422. +{
  1423. +   return _FlushLog(true, true);
  1424. +}
  1425. +
  1426. +
  1427. +int32
  1428. +Journal::TransactionID() const
  1429. +{
  1430. +   return fTransactionID;
  1431. +}
  1432. +
  1433. +
  1434. +status_t
  1435. +Journal::_WritePartialTransactionToLog(JournalHeader* descriptorBlock,
  1436. +   bool detached, uint8** _escapedData, uint32 &logBlock, off_t& blockNumber,
  1437. +   long& cookie, ArrayDeleter<uint8>& escapedDataDeleter, uint32& blockCount,
  1438. +   bool& finished)
  1439. +{
  1440. +   TRACE("Journal::_WritePartialTransactionToLog()\n");
  1441. +
  1442. +   uint32 descriptorBlockPos = logBlock;
  1443. +   uint8* escapedData = *_escapedData;
  1444. +
  1445. +   JournalBlockTag* tag = (JournalBlockTag*)descriptorBlock->data;
  1446. +   JournalBlockTag* lastTag = (JournalBlockTag*)((uint8*)descriptorBlock
  1447. +       + fBlockSize - sizeof(JournalHeader));
  1448. +  
  1449. +   finished = false;
  1450. +   status_t status = B_OK;
  1451. +
  1452. +   while (tag < lastTag && status == B_OK) {
  1453. +       tag->SetBlockNumber(blockNumber);
  1454. +       tag->SetFlags(0);
  1455. +
  1456. +       CachedBlock data(fFilesystemVolume);
  1457. +       const JournalHeader* blockData = (JournalHeader*)data.SetTo(
  1458. +           blockNumber);
  1459. +       if (blockData == NULL) {
  1460. +           panic("Got a NULL pointer while iterating through transaction "
  1461. +               "blocks.\n");
  1462. +           return B_ERROR;
  1463. +       }
  1464. +
  1465. +       void* finalData;
  1466. +
  1467. +       if (blockData->CheckMagic()) {
  1468. +           // The journaled block starts with the magic value
  1469. +           // We must remove it to prevent confusion
  1470. +           TRACE("Journal::_WritePartialTransactionToLog(): Block starts with "
  1471. +               "magic number. Escaping it\n");
  1472. +           tag->SetEscapedFlag();
  1473. +
  1474. +           if (escapedData == NULL) {
  1475. +               TRACE("Journal::_WritePartialTransactionToLog(): Allocating "
  1476. +                   "space for escaped block (%lu)\n", fBlockSize);
  1477. +               escapedData = new(std::nothrow) uint8[fBlockSize];
  1478. +               if (escapedData == NULL) {
  1479. +                   TRACE("Journal::_WritePartialTransactionToLof(): Failed to "
  1480. +                       "allocate buffer for escaped data block\n");
  1481. +                   return B_NO_MEMORY;
  1482. +               }
  1483. +               escapedDataDeleter.SetTo(escapedData);
  1484. +               *_escapedData = escapedData;
  1485. +
  1486. +               ((int32*)escapedData)[0] = 0; // Remove magic
  1487. +           }
  1488. +
  1489. +           memcpy(escapedData + 4, blockData->data, fBlockSize - 4);
  1490. +           finalData = escapedData;
  1491. +       } else
  1492. +           finalData = (void*)blockData;
  1493. +
  1494. +       // TODO: use iovecs?
  1495. +
  1496. +       logBlock = _WrapAroundLog(logBlock + 1);
  1497. +
  1498. +       uint32 physicalBlock;
  1499. +       status = MapBlock(logBlock, physicalBlock);
  1500. +       if (status != B_OK)
  1501. +           return status;
  1502. +
  1503. +       off_t logOffset = physicalBlock * fBlockSize;
  1504. +
  1505. +       TRACE("Journal::_WritePartialTransactionToLog(): Writing from memory: "
  1506. +           "%p, to disk: %ld\n", finalData, (long)logOffset);
  1507. +       size_t written = write_pos(fJournalVolume->Device(), logOffset,
  1508. +           finalData, fBlockSize);
  1509. +       if (written != fBlockSize) {
  1510. +           TRACE("Failed to write journal block.\n");
  1511. +           return B_IO_ERROR;
  1512. +       }
  1513. +
  1514. +       TRACE("Journal::_WritePartialTransactionToLog(): Wrote a journal block "
  1515. +           "at: %lu\n", logBlock);
  1516. +
  1517. +       blockCount++;
  1518. +       tag++;
  1519. +
  1520. +       status = cache_next_block_in_transaction(fFilesystemBlockCache,
  1521. +           fTransactionID, detached, &cookie, &blockNumber, NULL, NULL);
  1522. +   }
  1523. +
  1524. +   finished = status != B_OK;
  1525. +  
  1526. +   // Write descriptor block
  1527. +   --tag;
  1528. +   tag->SetLastTagFlag();
  1529. +  
  1530. +   uint32 physicalBlock;
  1531. +   status = MapBlock(descriptorBlockPos, physicalBlock);
  1532. +   if (status != B_OK)
  1533. +       return status;
  1534. +
  1535. +   off_t descriptorBlockOffset = physicalBlock * fBlockSize;
  1536. +
  1537. +   TRACE("Journal::_WritePartialTransactionToLog(): Writing to: %ld\n",
  1538. +       (long)descriptorBlockOffset);
  1539. +   size_t written = write_pos(fJournalVolume->Device(),
  1540. +       descriptorBlockOffset, descriptorBlock, fBlockSize);
  1541. +   if (written != fBlockSize) {
  1542. +       TRACE("Failed to write journal descriptor block.\n");
  1543. +       return B_IO_ERROR;
  1544. +   }
  1545. +
  1546. +   blockCount++;
  1547. +   logBlock = _WrapAroundLog(logBlock + 1);
  1548. +
  1549. +   return B_OK;
  1550. +}
  1551. +
  1552. +
  1553. +status_t
  1554. +Journal::_WriteTransactionToLog()
  1555. +{
  1556. +   TRACE("Journal::_WriteTransactionToLog()\n");
  1557. +   // Transaction enters the Flush state
  1558. +   bool detached = false;
  1559. +   TRACE("Journal::_WriteTransactionToLog(): Attempting to get transaction "
  1560. +       "size\n");
  1561. +   size_t size = _FullTransactionSize();
  1562. +   TRACE("Journal::_WriteTransactionToLog(): transaction size: %lu\n", size);
  1563. +
  1564. +   if (size > fMaxTransactionSize) {
  1565. +       TRACE("Journal::_WriteTransactionToLog(): not enough free space "
  1566. +           "for the transaction. Attempting to free some space.\n");
  1567. +       size = _MainTransactionSize();
  1568. +       TRACE("Journal::_WriteTransactionToLog(): main transaction size: %lu\n",
  1569. +           size);
  1570. +
  1571. +       if(fHasSubTransaction && size < fMaxTransactionSize) {
  1572. +           TRACE("Journal::_WriteTransactionToLog(): transaction doesn't fit, "
  1573. +               "but it can be separated\n");
  1574. +           detached = true;
  1575. +       } else {
  1576. +           // Error: transaction can't fit in log
  1577. +           panic("transaction too large (size: %lu, max size: %lu, log size: "
  1578. +               "%lu)\n", size, fMaxTransactionSize, fLogSize);
  1579. +           return B_BUFFER_OVERFLOW;
  1580. +       }
  1581. +   }
  1582. +
  1583. +   TRACE("Journal::_WriteTransactionToLog(): free log blocks: %lu\n",
  1584. +       FreeLogBlocks());
  1585. +   if (size > FreeLogBlocks()) {
  1586. +       TRACE("Journal::_WriteTransactionToLog(): Syncing block cache\n");
  1587. +       cache_sync_transaction(fFilesystemBlockCache, fTransactionID);
  1588. +      
  1589. +       if (size > FreeLogBlocks()) {
  1590. +           panic("Transaction fits, but sync didn't result in enough"
  1591. +               "free space.\n\tGot %ld when at least %ld was expected.",
  1592. +               (long)FreeLogBlocks(), (long)size);
  1593. +       }
  1594. +   }
  1595. +  
  1596. +   TRACE("Journal::_WriteTransactionToLog(): finished managing space for "
  1597. +       "the transaction\n");
  1598. +
  1599. +   fHasSubTransaction = false;
  1600. +
  1601. +   // Prepare Descriptor block
  1602. +   TRACE("Journal::_WriteTransactionToLog(): attempting to allocate space for "
  1603. +       "the descriptor block, block size %lu\n", fBlockSize);
  1604. +   JournalHeader* descriptorBlock =
  1605. +       (JournalHeader*)new(std::nothrow) uint8[fBlockSize];
  1606. +   if (descriptorBlock == NULL) {
  1607. +       TRACE("Journal::_WriteTransactionToLog(): Failed to allocate a buffer "
  1608. +           "for the descriptor block\n");
  1609. +       return B_NO_MEMORY;
  1610. +   }
  1611. +   ArrayDeleter<uint8> descriptorBlockDeleter((uint8*)descriptorBlock);
  1612. +
  1613. +   descriptorBlock->MakeDescriptor(fCurrentCommitID);
  1614. +
  1615. +   // Prepare Commit block
  1616. +   TRACE("Journal::_WriteTransactionToLog(): attempting to allocate space for "
  1617. +       "the commit block, block size %lu\n", fBlockSize);
  1618. +   JournalHeader* commitBlock =
  1619. +       (JournalHeader*)new(std::nothrow) uint8[fBlockSize];
  1620. +   if (descriptorBlock == NULL) {
  1621. +       TRACE("Journal::_WriteTransactionToLog(): Failed to allocate a buffer "
  1622. +           "for the commit block\n");
  1623. +       return B_NO_MEMORY;
  1624. +   }
  1625. +   ArrayDeleter<uint8> commitBlockDeleter((uint8*)commitBlock);
  1626. +
  1627. +   commitBlock->MakeCommit(fCurrentCommitID + 1);
  1628. +   memset(commitBlock->data, 0, fBlockSize - sizeof(JournalHeader));
  1629. +       // TODO: This probably isn't necessary
  1630. +
  1631. +   uint8* escapedData = NULL;
  1632. +   ArrayDeleter<uint8> escapedDataDeleter;
  1633. +
  1634. +   off_t blockNumber;
  1635. +   long cookie = 0;
  1636. +
  1637. +   status_t status = cache_next_block_in_transaction(fFilesystemBlockCache,
  1638. +       fTransactionID, detached, &cookie, &blockNumber, NULL, NULL);
  1639. +   if (status != B_OK) {
  1640. +       TRACE("Journal::_WriteTransactionToLog(): Transaction has no blocks to
  1641. +           write\n");
  1642. +       return B_OK;
  1643. +   }
  1644. +
  1645. +   uint32 blockCount = 0;
  1646. +
  1647. +   uint32 logBlock = _WrapAroundLog(fLogEnd);
  1648. +  
  1649. +   bool finished = false;
  1650. +
  1651. +   status = _WritePartialTransactionToLog(descriptorBlock, detached,
  1652. +       &escapedData, logBlock, blockNumber, cookie, escapedDataDeleter,
  1653. +       blockCount, finished);
  1654. +   if (!finished && status != B_OK)
  1655. +       return status;
  1656. +
  1657. +   uint32 commitBlockPos = logBlock;
  1658. +
  1659. +   while (!finished) {
  1660. +       descriptorBlock->IncrementSequence();
  1661. +
  1662. +       status = _WritePartialTransactionToLog(descriptorBlock, detached,
  1663. +           &escapedData, logBlock, blockNumber, cookie, escapedDataDeleter,
  1664. +           blockCount, finished);
  1665. +       if (!finished && status != B_OK)
  1666. +           return status;
  1667. +      
  1668. +       // It is okay to write the commit blocks of the partial transactions
  1669. +       // as long as the commit block of the first partial transaction isn't
  1670. +       // written. When it recovery reaches where the first commit should be
  1671. +       // and doesn't find it, it considers it found the end of the log.
  1672. +
  1673. +       uint32 physicalBlock;
  1674. +       status = MapBlock(logBlock, physicalBlock);
  1675. +       if (status != B_OK)
  1676. +           return status;
  1677. +
  1678. +       off_t logOffset = physicalBlock * fBlockSize;
  1679. +      
  1680. +       TRACE("Journal::_WriteTransactionToLog(): Writting commit block to "
  1681. +           "%ld\n", (long)logOffset);
  1682. +       off_t written = write_pos(fJournalVolume->Device(), logOffset,
  1683. +           commitBlock, fBlockSize);
  1684. +       if (written != fBlockSize) {
  1685. +           TRACE("Failed to write journal commit block.\n");
  1686. +           return B_IO_ERROR;
  1687. +       }
  1688. +
  1689. +       commitBlock->IncrementSequence();
  1690. +       blockCount++;
  1691. +      
  1692. +       logBlock = _WrapAroundLog(logBlock + 1);
  1693. +   }
  1694. +
  1695. +   // Transaction will enter the Commit state
  1696. +   uint32 physicalBlock;
  1697. +   status = MapBlock(commitBlockPos, physicalBlock);
  1698. +   if (status != B_OK)
  1699. +       return status;
  1700. +
  1701. +   off_t logOffset = physicalBlock * fBlockSize;
  1702. +
  1703. +   TRACE("Journal::_WriteTansactionToLog(): Writing to: %ld\n",
  1704. +       (long)logOffset);
  1705. +   off_t written = write_pos(fJournalVolume->Device(), logOffset, commitBlock,
  1706. +       fBlockSize);
  1707. +   if (written != fBlockSize) {
  1708. +       TRACE("Failed to write journal commit block.\n");
  1709. +       return B_IO_ERROR;
  1710. +   }
  1711. +  
  1712. +   blockCount++;
  1713. +   fLogEnd = _WrapAroundLog(fLogEnd + blockCount);
  1714. +
  1715. +   status = _SaveSuperBlock();
  1716. +
  1717. +   // Transaction will enter Finished state
  1718. +   LogEntry *logEntry = new LogEntry(this, fLogEnd, fCurrentCommitID++);
  1719. +   TRACE("Journal::_WriteTransactionToLog(): Allocating log entry at %p\n", logEntry);
  1720. +   if (logEntry == NULL) {
  1721. +       panic("no memory to allocate log entries!");
  1722. +       return B_NO_MEMORY;
  1723. +   }
  1724. +
  1725. +   mutex_lock(&fLogEntriesLock);
  1726. +   fLogEntries.Add(logEntry);
  1727. +   mutex_unlock(&fLogEntriesLock);
  1728. +
  1729. +   if (detached) {
  1730. +       fTransactionID = cache_detach_sub_transaction(fFilesystemBlockCache,
  1731. +           fTransactionID, _TransactionWritten, logEntry);
  1732. +       fUnwrittenTransactions = 1;
  1733. +
  1734. +       if (status == B_OK && _FullTransactionSize() > fLogSize) {
  1735. +           // If the transaction is too large after writing, there is no way to
  1736. +           // recover, so let this transaction fail.
  1737. +           dprintf("transaction too large (%d blocks, log size %d)!\n",
  1738. +               (int)_FullTransactionSize(), (int)fLogSize);
  1739. +           return B_BUFFER_OVERFLOW;
  1740. +       }
  1741. +   } else {
  1742. +       cache_end_transaction(fFilesystemBlockCache, fTransactionID,
  1743. +           _TransactionWritten, logEntry);
  1744. +       fUnwrittenTransactions = 0;
  1745. +   }
  1746. +
  1747. +   return B_OK;
  1748. +}
  1749. +
  1750. +
  1751. +status_t
  1752. +Journal::_SaveSuperBlock()
  1753. +{
  1754. +   TRACE("Journal::_SaveSuperBlock()\n");
  1755. +   uint32 physicalBlock;
  1756. +   status_t status = MapBlock(0, physicalBlock);
  1757. +   if (status != B_OK)
  1758. +       return status;
  1759. +
  1760. +   off_t superblockPos = physicalBlock * fBlockSize;
  1761. +
  1762. +   JournalSuperBlock superblock;
  1763. +   size_t bytesRead = read_pos(fJournalVolume->Device(), superblockPos,
  1764. +       &superblock, sizeof(superblock));
  1765. +
  1766. +   if (bytesRead != sizeof(superblock))
  1767. +       return B_IO_ERROR;
  1768. +
  1769. +   superblock.SetFirstCommitID(fFirstCommitID);
  1770. +   superblock.SetLogStart(fLogStart);
  1771. +  
  1772. +   TRACE("Journal::SaveSuperBlock(): Write to %ld\n", (long)superblockPos);
  1773. +   size_t bytesWritten = write_pos(fJournalVolume->Device(), superblockPos,
  1774. +       &superblock, sizeof(superblock));
  1775. +
  1776. +   if (bytesWritten != sizeof(superblock))
  1777. +       return B_IO_ERROR;
  1778. +
  1779. +   TRACE("Journal::_SaveSuperBlock(): Done\n");
  1780. +
  1781. +   return B_OK;
  1782. +}
  1783. +
  1784. +
  1785. +status_t
  1786. +Journal::_LoadSuperBlock()
  1787. +{
  1788. +   TRACE("Journal::_LoadSuperBlock()\n");
  1789. +   uint32 superblockPos;
  1790. +
  1791. +   status_t status = MapBlock(0, superblockPos);
  1792. +   if (status != B_OK)
  1793. +       return status;
  1794. +  
  1795. +   TRACE("Journal::_LoadSuperBlock(): super block physical block: %lu\n",
  1796. +       superblockPos);
  1797. +  
  1798. +   JournalSuperBlock superblock;
  1799. +   size_t bytesRead = read_pos(fJournalVolume->Device(), superblockPos
  1800. +       * fJournalVolume->BlockSize(), &superblock, sizeof(superblock));
  1801. +
  1802. +   if (bytesRead != sizeof(superblock)) {
  1803. +       TRACE("Journal::_LoadSuperBlock(): failed to read superblock\n");
  1804. +       return B_IO_ERROR;
  1805. +   }
  1806. +
  1807. +   if (!superblock.header.CheckMagic()) {
  1808. +       TRACE("Journal::_LoadSuperBlock(): Invalid superblock magic %lX\n",
  1809. +           superblock.header.Magic());
  1810. +       return B_BAD_VALUE;
  1811. +   }
  1812. +
  1813. +   if (superblock.header.BlockType() == JOURNAL_SUPERBLOCK_V1) {
  1814. +       TRACE("Journal::_LoadSuperBlock(): Journal superblock version 1\n");
  1815. +       fVersion = 1;
  1816. +   } else if (superblock.header.BlockType() == JOURNAL_SUPERBLOCK_V2) {
  1817. +       TRACE("Journal::_LoadSuperBlock(): Journal superblock version 2\n");
  1818. +       fVersion = 2;
  1819. +   } else {
  1820. +       TRACE("Journal::_LoadSuperBlock(): Invalid superblock version\n");
  1821. +       return B_BAD_VALUE;
  1822. +   }
  1823. +
  1824. +   if (fVersion >= 2) {
  1825. +       status = _CheckFeatures(&superblock);
  1826. +
  1827. +       if (status != B_OK) {
  1828. +           TRACE("Journal::_LoadSuperBlock(): Unsupported features\n");
  1829. +           return status;
  1830. +       }
  1831. +   }
  1832. +
  1833. +   fBlockSize = superblock.BlockSize();
  1834. +   fFirstCommitID = superblock.FirstCommitID();
  1835. +   fFirstLogBlock = superblock.FirstLogBlock();
  1836. +   fLogStart = superblock.LogStart();
  1837. +   fLogSize = superblock.NumBlocks();
  1838. +
  1839. +   uint32 descriptorTags = (fBlockSize - sizeof(JournalHeader))
  1840. +       / sizeof(JournalBlockTag);
  1841. +       // Maximum tags per descriptor block
  1842. +   uint32 maxDescriptors = (fLogSize - 1) / (descriptorTags + 2);
  1843. +       // Maximum number of full journal transactions
  1844. +   fMaxTransactionSize = maxDescriptors * descriptorTags;
  1845. +   fMaxTransactionSize += (fLogSize - 1) - fMaxTransactionSize - 2;
  1846. +       // Maximum size of a "logical" transaction
  1847. +       // TODO: Why is "superblock.MaxTransactionBlocks();" zero?
  1848. +   //fFirstCacheCommitID = fFirstCommitID - fTransactionID /*+ 1*/;
  1849. +
  1850. +   TRACE("Journal::_LoadSuperBlock(): block size: %lu, first commit id: %lu, "
  1851. +       "first log block: %lu, log start: %lu, log size: %lu, max transaction "
  1852. +       "size: %lu\n", fBlockSize, fFirstCommitID, fFirstLogBlock, fLogStart,
  1853. +       fLogSize, fMaxTransactionSize);
  1854. +
  1855. +   return B_OK;
  1856. +}
  1857. +
  1858. +
  1859. +status_t
  1860. +Journal::_CheckFeatures(JournalSuperBlock* superblock)
  1861. +{
  1862. +   if ((superblock->ReadOnlyCompatibleFeatures()
  1863. +           & ~JOURNAL_KNOWN_READ_ONLY_COMPATIBLE_FEATURES) != 0
  1864. +       || (superblock->IncompatibleFeatures()
  1865. +           & ~JOURNAL_KNOWN_INCOMPATIBLE_FEATURES) != 0)
  1866. +       return B_NOT_SUPPORTED;
  1867. +
  1868. +   return B_OK;
  1869. +}
  1870. +
  1871. +
  1872. +uint32
  1873. +Journal::_CountTags(JournalHeader* descriptorBlock)
  1874. +{
  1875. +   uint32 count = 0;
  1876. +
  1877. +   JournalBlockTag* tags = (JournalBlockTag*)descriptorBlock->data;
  1878. +       // Skip the header
  1879. +   JournalBlockTag* lastTag = (JournalBlockTag*)
  1880. +       (descriptorBlock + fBlockSize - sizeof(JournalBlockTag));
  1881. +
  1882. +   while (tags < lastTag && (tags->Flags() & JOURNAL_FLAG_LAST_TAG) == 0) {
  1883. +       if ((tags->Flags() & JOURNAL_FLAG_SAME_UUID) == 0) {
  1884. +           // sizeof(UUID) = 16 = 2*sizeof(JournalBlockTag)
  1885. +           tags += 2;  // Skip new UUID
  1886. +       }
  1887. +
  1888. +       TRACE("Journal::_CountTags(): Tag block: %lu\n", tags->BlockNumber());
  1889. +
  1890. +       tags++; // Go to next tag
  1891. +       count++;
  1892. +   }
  1893. +  
  1894. +   TRACE("Journal::_CountTags(): counted tags: %lu\n", count);
  1895. +
  1896. +   return count;
  1897. +}
  1898. +
  1899. +
  1900. +/*virtual*/ status_t
  1901. +Journal::Recover()
  1902. +{
  1903. +   TRACE("Journal::Recover()\n");
  1904. +   if (fLogStart == 0) // Journal was cleanly unmounted
  1905. +       return B_OK;
  1906. +
  1907. +   TRACE("Journal::Recover(): Journal needs recovery\n");
  1908. +
  1909. +   uint32 lastCommitID;
  1910. +
  1911. +   status_t status = _RecoverPassScan(lastCommitID);
  1912. +   if (status != B_OK)
  1913. +       return status;
  1914. +  
  1915. +   status = _RecoverPassRevoke(lastCommitID);
  1916. +   if (status != B_OK)
  1917. +       return status;
  1918. +
  1919. +   return _RecoverPassReplay(lastCommitID);
  1920. +}
  1921. +
  1922. +
  1923. +// First pass: Find the end of the log
  1924. +status_t
  1925. +Journal::_RecoverPassScan(uint32& lastCommitID)
  1926. +{
  1927. +   TRACE("Journal Recover: 1st Pass: Scan\n");
  1928. +
  1929. +   CachedBlock cached(fJournalVolume);
  1930. +   JournalHeader* header;
  1931. +   uint32 nextCommitID = fFirstCommitID;
  1932. +   uint32 nextBlock = fLogStart;
  1933. +   uint32 nextBlockPos;
  1934. +
  1935. +   status_t status = MapBlock(nextBlock, nextBlockPos);
  1936. +   if (status != B_OK)
  1937. +       return status;
  1938. +
  1939. +   header = (JournalHeader*)cached.SetTo(nextBlockPos);
  1940. +
  1941. +   while (header->CheckMagic() && header->Sequence() == nextCommitID) {
  1942. +       uint32 blockType = header->BlockType();
  1943. +
  1944. +       if (blockType == JOURNAL_DESCRIPTOR_BLOCK)
  1945. +           nextBlock += nextBlock - 1;
  1946. +       else if (blockType == JOURNAL_COMMIT_BLOCK)
  1947. +           nextCommitID++;
  1948. +       else if (blockType != JOURNAL_REVOKE_BLOCK) {
  1949. +               // TODO: Warn that we found an unrecognized block
  1950. +           break;
  1951. +       } // If blockType == JOURNAL_REVOKE_BLOCK we just skip it
  1952. +
  1953. +       nextBlock = _WrapAroundLog(nextBlock + 1);
  1954. +
  1955. +       status = MapBlock(nextBlock, nextBlockPos);
  1956. +       if (status != B_OK)
  1957. +           return status;
  1958. +
  1959. +       header = (JournalHeader*)cached.SetTo(nextBlockPos);
  1960. +   }
  1961. +
  1962. +   TRACE("Journal Recovery pass scan: Last detected transaction ID: %lu\n",
  1963. +       nextCommitID);
  1964. +
  1965. +   lastCommitID = nextCommitID;
  1966. +   return B_OK;
  1967. +}
  1968. +
  1969. +
  1970. +// Second pass: Collect all revoked blocks
  1971. +status_t
  1972. +Journal::_RecoverPassRevoke(uint32 lastCommitID)
  1973. +{
  1974. +   TRACE("Journal Recover: 2nd Pass: Revoke\n");
  1975. +
  1976. +   CachedBlock cached(fJournalVolume);
  1977. +   JournalHeader* header;
  1978. +   uint32 nextCommitID = fFirstCommitID;
  1979. +   uint32 nextBlock = fLogStart;
  1980. +   uint32 nextBlockPos;
  1981. +
  1982. +   status_t status = MapBlock(nextBlock, nextBlockPos);
  1983. +   if (status != B_OK)
  1984. +       return status;
  1985. +
  1986. +   header = (JournalHeader*)cached.SetTo(nextBlockPos);
  1987. +
  1988. +   while (nextCommitID < lastCommitID) {
  1989. +       if (!header->CheckMagic() || header->Sequence() != nextCommitID) {
  1990. +           // Somehow the log is different than the expexted
  1991. +           return B_ERROR;
  1992. +       }
  1993. +
  1994. +       uint32 blockType = header->BlockType();
  1995. +
  1996. +       if (blockType == JOURNAL_DESCRIPTOR_BLOCK)
  1997. +           nextBlock += _CountTags(header) - 1;
  1998. +       else if (blockType == JOURNAL_COMMIT_BLOCK)
  1999. +           nextCommitID++;
  2000. +       else if (blockType == JOURNAL_REVOKE_BLOCK) {
  2001. +           TRACE("Journal::_RecoverPassRevoke(): Found a revoke block\n");
  2002. +           status = fRevokeManager->ScanRevokeBlock(
  2003. +               (JournalRevokeHeader*)header, nextCommitID);
  2004. +
  2005. +           if (status != B_OK)
  2006. +               return status;
  2007. +       } else {
  2008. +               // TODO: Warn that we found an unrecognized block
  2009. +           break;
  2010. +       }
  2011. +
  2012. +       nextBlock = _WrapAroundLog(nextBlock + 1);
  2013. +
  2014. +       status = MapBlock(nextBlock, nextBlockPos);
  2015. +       if (status != B_OK)
  2016. +           return status;
  2017. +
  2018. +       header = (JournalHeader*)cached.SetTo(nextBlockPos);
  2019. +   }
  2020. +
  2021. +   if (nextCommitID != lastCommitID) {
  2022. +       // Possibly because of some sort of IO error
  2023. +       TRACE("Journal::_RecoverPassRevoke(): Incompatible commit IDs\n");
  2024. +       return B_ERROR;
  2025. +   }
  2026. +
  2027. +   TRACE("Journal recovery pass revoke: Revoked blocks: %lu\n",
  2028. +       fRevokeManager->NumRevokes());
  2029. +
  2030. +   return B_OK;
  2031. +}
  2032. +
  2033. +
  2034. +// Third pass: Replay log
  2035. +status_t
  2036. +Journal::_RecoverPassReplay(uint32 lastCommitID)
  2037. +{
  2038. +   TRACE("Journal Recover: 3rd Pass: Replay\n");
  2039. +
  2040. +   uint32 nextCommitID = fFirstCommitID;
  2041. +   uint32 nextBlock = fLogStart;
  2042. +   uint32 nextBlockPos;
  2043. +
  2044. +   status_t status = MapBlock(nextBlock, nextBlockPos);
  2045. +   if (status != B_OK)
  2046. +       return status;
  2047. +
  2048. +   CachedBlock cached(fJournalVolume);
  2049. +   JournalHeader* header = (JournalHeader*)cached.SetTo(nextBlockPos);
  2050. +
  2051. +   int count = 0;
  2052. +
  2053. +   uint8* data = new(std::nothrow) uint8[fBlockSize];
  2054. +   if (data == NULL) {
  2055. +       TRACE("Journal::_RecoverPassReplay(): Failed to allocate memory for "
  2056. +           "data\n");
  2057. +       return B_NO_MEMORY;
  2058. +   }
  2059. +  
  2060. +   ArrayDeleter<uint8> dataDeleter(data);
  2061. +
  2062. +   while (nextCommitID < lastCommitID) {
  2063. +       if (!header->CheckMagic() || header->Sequence() != nextCommitID) {
  2064. +           // Somehow the log is different than the expexted
  2065. +           TRACE("Journal::_RecoverPassReplay(): Wierd problem with block\n");
  2066. +           return B_ERROR;
  2067. +       }
  2068. +
  2069. +       uint32 blockType = header->BlockType();
  2070. +
  2071. +       if (blockType == JOURNAL_DESCRIPTOR_BLOCK) {
  2072. +           JournalBlockTag* last_tag = (JournalBlockTag*)((uint8*)header
  2073. +               + fBlockSize - sizeof(JournalBlockTag));
  2074. +
  2075. +           for (JournalBlockTag* tag = (JournalBlockTag*)header->data;
  2076. +               tag <= last_tag; ++tag) {
  2077. +               nextBlock = _WrapAroundLog(nextBlock + 1);
  2078. +
  2079. +               status = MapBlock(nextBlock, nextBlockPos);
  2080. +               if (status != B_OK)
  2081. +                   return status;
  2082. +
  2083. +               if (!fRevokeManager->Lookup(tag->BlockNumber(),
  2084. +                       nextCommitID)) {
  2085. +                   // Block isn't revoked
  2086. +                   size_t read = read_pos(fJournalVolume->Device(),
  2087. +                       nextBlockPos * fBlockSize, data, fBlockSize);
  2088. +                   if (read != fBlockSize)
  2089. +                       return B_IO_ERROR;
  2090. +
  2091. +                   if ((tag->Flags() & JOURNAL_FLAG_ESCAPED) != 0) {
  2092. +                       // Block is escaped
  2093. +                       ((int32*)data)[0]
  2094. +                           = B_HOST_TO_BENDIAN_INT32(JOURNAL_MAGIC);
  2095. +                   }
  2096. +
  2097. +                   TRACE("Journal::_RevoverPassReplay(): Write to %lu\n",
  2098. +                       tag->BlockNumber() * fBlockSize);
  2099. +                   size_t written = write_pos(fFilesystemVolume->Device(),
  2100. +                       tag->BlockNumber() * fBlockSize, data, fBlockSize);
  2101. +
  2102. +                   if (written != fBlockSize)
  2103. +                       return B_IO_ERROR;
  2104. +
  2105. +                   ++count;
  2106. +               }
  2107. +
  2108. +               if ((tag->Flags() & JOURNAL_FLAG_LAST_TAG) != 0)
  2109. +                   break;
  2110. +               if ((tag->Flags() & JOURNAL_FLAG_SAME_UUID) == 0) {
  2111. +                   // TODO: Check new UUID with file system UUID
  2112. +                   tag += 2;
  2113. +                       // sizeof(JournalBlockTag) = 8
  2114. +                       // sizeof(UUID) = 16
  2115. +               }
  2116. +           }
  2117. +       }
  2118. +       else if (blockType == JOURNAL_COMMIT_BLOCK)
  2119. +           nextCommitID++;
  2120. +       else if (blockType != JOURNAL_REVOKE_BLOCK) {
  2121. +               // TODO: Warn that we found an unrecognized block
  2122. +           break;
  2123. +       } // If blockType == JOURNAL_REVOKE_BLOCK we just skip it
  2124. +
  2125. +       nextBlock = _WrapAroundLog(nextBlock + 1);
  2126. +
  2127. +       status = MapBlock(nextBlock, nextBlockPos);
  2128. +       if (status != B_OK)
  2129. +           return status;
  2130. +
  2131. +       header = (JournalHeader*)cached.SetTo(nextBlockPos);
  2132. +   }
  2133. +
  2134. +   if (nextCommitID != lastCommitID) {
  2135. +       // Possibly because of some sort of IO error
  2136. +       return B_ERROR;
  2137. +   }
  2138. +
  2139. +   TRACE("Journal recovery pass replay: Replayed blocks: %u\n", count);
  2140. +
  2141. +   return B_OK;
  2142. +}
  2143. +
  2144. +
  2145. +status_t
  2146. +Journal::_FlushLog(bool canWait, bool flushBlocks)
  2147. +{
  2148. +   TRACE("Journal::_FlushLog()\n");
  2149. +   status_t status = canWait ? recursive_lock_lock(&fLock)
  2150. +       : recursive_lock_trylock(&fLock);
  2151. +   if (status != B_OK)
  2152. +       return status;
  2153. +
  2154. +   TRACE("Journal::_FlushLog(): Acquired fLock, recursion: %ld\n",
  2155. +       recursive_lock_get_recursion(&fLock));
  2156. +
  2157. +   if (recursive_lock_get_recursion(&fLock) > 1) {
  2158. +       // Called from inside a transaction
  2159. +       recursive_lock_unlock(&fLock);
  2160. +       TRACE("Journal::_FlushLog(): Called from a transaction. Leaving...\n");
  2161. +       return B_OK;
  2162. +   }
  2163. +
  2164. +   if (fUnwrittenTransactions != 0 && _FullTransactionSize() != 0) {
  2165. +       status = _WriteTransactionToLog();
  2166. +       if (status < B_OK)
  2167. +           panic("Failed flushing transaction: %s\n", strerror(status));
  2168. +   }
  2169. +
  2170. +   TRACE("Journal::_FlushLog(): Attempting to flush journal volume at %p\n",
  2171. +       fJournalVolume);
  2172. +
  2173. +   // TODO: Not sure this is correct. Need to review...
  2174. +   // NOTE: Not correct. Causes double lock of a block cache mutex
  2175. +   // TODO: Need some other way to synchronize the journal...
  2176. +   /*status = fJournalVolume->FlushDevice();
  2177. +   if (status != B_OK)
  2178. +       return status;*/
  2179. +
  2180. +   TRACE("Journal::_FlushLog(): Flushed journal volume\n");
  2181. +
  2182. +   if (flushBlocks) {
  2183. +       TRACE("Journal::_FlushLog(): Attempting to flush file system volume "
  2184. +           "at %p\n", fFilesystemVolume);
  2185. +       status = fFilesystemVolume->FlushDevice();
  2186. +       if (status == B_OK)
  2187. +           TRACE("Journal::_FlushLog(): Flushed file system volume\n");
  2188. +   }
  2189. +
  2190. +   TRACE("Journal::_FlushLog(): Finished. Releasing lock\n");
  2191. +
  2192. +   recursive_lock_unlock(&fLock);
  2193. +  
  2194. +   TRACE("Journal::_FlushLog(): Done, final status: %s\n", strerror(status));
  2195. +   return status;
  2196. +}
  2197. +
  2198. +
  2199. +inline uint32
  2200. +Journal::_WrapAroundLog(uint32 block)
  2201. +{
  2202. +   TRACE("Journal::_WrapAroundLog()\n");
  2203. +   if (block >= fLogSize)
  2204. +       return block - fLogSize + fFirstLogBlock;
  2205. +   else
  2206. +       return block;
  2207. +}
  2208. +
  2209. +
  2210. +size_t
  2211. +Journal::_CurrentTransactionSize() const
  2212. +{
  2213. +   TRACE("Journal::_CurrentTransactionSize(): transaction %ld\n",
  2214. +       fTransactionID);
  2215. +
  2216. +   size_t count;
  2217. +
  2218. +   if (fHasSubTransaction) {
  2219. +       count = cache_blocks_in_sub_transaction(fFilesystemBlockCache,
  2220. +           fTransactionID);
  2221. +
  2222. +       TRACE("\tSub transaction size: %ld\n", count);
  2223. +   } else {
  2224. +       count =  cache_blocks_in_transaction(fFilesystemBlockCache,
  2225. +           fTransactionID);
  2226. +
  2227. +       TRACE("\tTransaction size: %ld\n", count);
  2228. +   }
  2229. +
  2230. +   return count;
  2231. +}
  2232. +
  2233. +
  2234. +size_t
  2235. +Journal::_FullTransactionSize() const
  2236. +{
  2237. +   TRACE("Journal::_FullTransactionSize(): transaction %ld\n", fTransactionID);
  2238. +   TRACE("\tFile sytem block cache: %p\n", fFilesystemBlockCache);
  2239. +
  2240. +   size_t count = cache_blocks_in_transaction(fFilesystemBlockCache,
  2241. +        fTransactionID);
  2242. +  
  2243. +   TRACE("\tFull transaction size: %ld\n", count);
  2244. +  
  2245. +   return count;
  2246. +}
  2247. +
  2248. +
  2249. +size_t
  2250. +Journal::_MainTransactionSize() const
  2251. +{
  2252. +   TRACE("Journal::_MainTransactionSize(): transaction %ld\n", fTransactionID);
  2253. +
  2254. +   size_t count =  cache_blocks_in_main_transaction(fFilesystemBlockCache,
  2255. +       fTransactionID);
  2256. +  
  2257. +   TRACE("\tMain transaction size: %ld\n", count);
  2258. +  
  2259. +   return count;
  2260. +}
  2261. +
  2262. +
  2263. +status_t
  2264. +Journal::_TransactionDone(bool success)
  2265. +{
  2266. +   if (!success) {
  2267. +       if (fHasSubTransaction) {
  2268. +           TRACE("Journal::_TransactionDone(): transaction %ld failed, "
  2269. +               "aborting subtransaction\n", fTransactionID);
  2270. +           cache_abort_sub_transaction(fFilesystemBlockCache, fTransactionID);
  2271. +           // parent is unaffected
  2272. +       } else {
  2273. +           TRACE("Journal::_TransactionDone(): transaction %ld failed,"
  2274. +               " aborting\n", fTransactionID);
  2275. +           cache_abort_transaction(fFilesystemBlockCache, fTransactionID);
  2276. +           fUnwrittenTransactions = 0;
  2277. +       }
  2278. +
  2279. +       return B_OK;
  2280. +   }
  2281. +  
  2282. +   // If possible, delay flushing the transaction
  2283. +   uint32 size = _FullTransactionSize();
  2284. +   TRACE("Journal::_TransactionDone(): full transaction size: %lu, max "
  2285. +       "transaction size: %lu, free log blocks: %lu\n", size,
  2286. +       fMaxTransactionSize, FreeLogBlocks());
  2287. +   if (fMaxTransactionSize > 0 && size < fMaxTransactionSize) {
  2288. +       TRACE("Journal::_TransactionDone(): delaying flush of transaction "
  2289. +           "%ld\n", fTransactionID);
  2290. +      
  2291. +       // Make sure the transaction fits in the log
  2292. +       if (size < FreeLogBlocks())
  2293. +           cache_sync_transaction(fFilesystemBlockCache, fTransactionID);
  2294. +      
  2295. +       fUnwrittenTransactions++;
  2296. +       return B_OK;
  2297. +   }
  2298. +
  2299. +   return _WriteTransactionToLog();
  2300. +}
  2301. +
  2302. +
  2303. +/*static*/ void
  2304. +Journal::_TransactionWritten(int32 transactionID, int32 event, void* _logEntry)
  2305. +{
  2306. +   LogEntry* logEntry = (LogEntry*)_logEntry;
  2307. +
  2308. +   TRACE("Journal::_TransactionWritten(): Transaction %ld checkpointed\n",
  2309. +       transactionID);
  2310. +
  2311. +   Journal* journal = logEntry->GetJournal();
  2312. +
  2313. +   TRACE("Journal::_TransactionWritten(): log entry: %p, journal: %p\n",
  2314. +       logEntry, journal);
  2315. +   TRACE("Journal::_TransactionWritten(): log entries: %p\n",
  2316. +       &journal->fLogEntries);
  2317. +
  2318. +   mutex_lock(&journal->fLogEntriesLock);
  2319. +
  2320. +   TRACE("Journal::_TransactionWritten(): first log entry: %p\n",
  2321. +       journal->fLogEntries.First());
  2322. +   if (logEntry == journal->fLogEntries.First()) {
  2323. +       TRACE("Journal::_TransactionWritten(): Moving start of log to %lu\n",
  2324. +           logEntry->Start());
  2325. +       journal->fLogStart = logEntry->Start();
  2326. +       journal->fFirstCommitID = logEntry->CommitID();
  2327. +       TRACE("Journal::_TransactionWritten(): Setting commit ID to %lu\n",
  2328. +           logEntry->CommitID());
  2329. +
  2330. +       if (journal->_SaveSuperBlock() != B_OK)
  2331. +           panic("ext2: Failed to write journal superblock\n");
  2332. +   }
  2333. +  
  2334. +   TRACE("Journal::_TransactionWritten(): Removing log entry\n");
  2335. +   journal->fLogEntries.Remove(logEntry);
  2336. +
  2337. +   TRACE("Journal::_TransactionWritten(): Unlocking entries list\n");
  2338. +   mutex_unlock(&journal->fLogEntriesLock);
  2339. +
  2340. +   TRACE("Journal::_TransactionWritten(): Deleting log entry at %p\n", logEntry);
  2341. +   delete logEntry;
  2342. +}
  2343. +
  2344. +
  2345. +/*static*/ void
  2346. +Journal::_TransactionIdle(int32 transactionID, int32 event, void* _journal)
  2347. +{
  2348. +   Journal* journal = (Journal*)_journal;
  2349. +   journal->_FlushLog(false, false);
  2350. +}
  2351.  
  2352. Property changes on: src/add-ons/kernel/file_systems/ext2/Journal.cpp
  2353. ___________________________________________________________________
  2354. Added: svn:executable
  2355.    + *
  2356.  
  2357. Index: src/add-ons/kernel/file_systems/ext2/NoJournal.h
  2358. ===================================================================
  2359. --- src/add-ons/kernel/file_systems/ext2/NoJournal.h    (revision 0)
  2360. +++ src/add-ons/kernel/file_systems/ext2/NoJournal.h    (revision 0)
  2361. @@ -0,0 +1,34 @@
  2362. +/*
  2363. + * Copyright 2001-2010, Haiku Inc. All rights reserved.
  2364. + * This file may be used under the terms of the MIT License.
  2365. + *
  2366. + * Authors:
  2367. + *     Janito V. Ferreira Filho
  2368. + */
  2369. +#ifndef NOJOURNAL_H
  2370. +#define NOJOURNAL_H
  2371. +
  2372. +
  2373. +#include "Journal.h"
  2374. +
  2375. +
  2376. +class NoJournal : public Journal {
  2377. +public:
  2378. +                       NoJournal(Volume* volume);
  2379. +                       ~NoJournal();
  2380. +
  2381. +           status_t    InitCheck();
  2382. +           status_t    Recover();
  2383. +           status_t    StartLog();
  2384. +          
  2385. +           status_t    Lock(Transaction* owner, bool separateSubTransactions);
  2386. +           status_t    Unlock(Transaction* owner, bool success);
  2387. +
  2388. +private:
  2389. +           status_t    _WriteTransactionToLog();
  2390. +
  2391. +   static  void        _TransactionWritten(int32 transactionID,
  2392. +                           int32 event, void* param);
  2393. +};
  2394. +
  2395. +#endif // NOJOURNAL_H
  2396. Index: src/add-ons/kernel/file_systems/ext2/HTree.h
  2397. ===================================================================
  2398. --- src/add-ons/kernel/file_systems/ext2/HTree.h    (revision 37957)
  2399. +++ src/add-ons/kernel/file_systems/ext2/HTree.h    (working copy)
  2400. @@ -9,8 +9,6 @@
  2401.  #define HTREE_H
  2402.  
  2403.  
  2404. -#include <AutoDeleter.h>
  2405. -
  2406.  #include "ext2.h"
  2407.  #include "DirectoryIterator.h"
  2408.  #include "HTreeEntryIterator.h"
  2409. @@ -26,14 +24,14 @@
  2410.  
  2411.  
  2412.  struct HTreeFakeDirEntry {
  2413. -   uint32              inode_num;
  2414. +   uint32              inode_id;
  2415.     uint16              entry_length;
  2416.     uint8               name_length;
  2417.     uint8               file_type;
  2418.     char                file_name[0];
  2419.    
  2420.     uint32              Inode()
  2421. -       { return B_LENDIAN_TO_HOST_INT32(inode_num); }
  2422. +       { return B_LENDIAN_TO_HOST_INT32(inode_id); }
  2423.  } _PACKED;
  2424.  
  2425.  struct HTreeCountLimit {
  2426. @@ -41,9 +39,15 @@
  2427.     uint16              count;
  2428.    
  2429.     uint16              Limit() const
  2430. -       { return B_LENDIAN_TO_HOST_INT32(limit); }
  2431. +       { return B_LENDIAN_TO_HOST_INT16(limit); }
  2432.     uint16              Count() const
  2433. -       { return B_LENDIAN_TO_HOST_INT32(count); }
  2434. +       { return B_LENDIAN_TO_HOST_INT16(count); }
  2435. +
  2436. +   void                SetLimit(uint16 value)
  2437. +       { limit = B_HOST_TO_LENDIAN_INT16(value); }
  2438. +
  2439. +   void                SetCount(uint16 value)
  2440. +       { count = B_HOST_TO_LENDIAN_INT16(value); }
  2441.  } _PACKED;
  2442.  
  2443.  struct HTreeEntry {
  2444. @@ -54,6 +58,12 @@
  2445.         { return B_LENDIAN_TO_HOST_INT32(hash); }
  2446.     uint32              Block() const
  2447.         { return B_LENDIAN_TO_HOST_INT32(block); }
  2448. +
  2449. +   void                SetHash(uint32 newHash)
  2450. +       { hash = B_HOST_TO_LENDIAN_INT32(newHash); }
  2451. +
  2452. +   void                SetBlock(uint32 newBlock)
  2453. +       { block = B_HOST_TO_LENDIAN_INT32(newBlock); }
  2454.  } _PACKED;
  2455.  
  2456.  struct HTreeRoot {
  2457. @@ -67,6 +77,8 @@
  2458.     uint8               root_info_length;
  2459.     uint8               indirection_levels;
  2460.     uint8               flags;
  2461. +
  2462. +   HTreeCountLimit     count_limit[0];
  2463.    
  2464.     bool            IsValid() const;
  2465.         // Implemented in HTree.cpp
  2466. @@ -94,17 +106,21 @@
  2467.                                 HTree(Volume* volume, Inode* directory);
  2468.                                 ~HTree();
  2469.  
  2470. +           status_t            PrepareForHash();
  2471. +           uint32              Hash(const char* name, uint8 length);
  2472. +
  2473.             status_t            Lookup(const char* name,
  2474.                                     DirectoryIterator** directory);
  2475.  
  2476. +   static  status_t            InitDir(Transaction& transaction, Inode* inode,
  2477. +                                   Inode* parent);
  2478. +
  2479.  private:
  2480.             status_t            _LookupInNode(uint32 hash, off_t& firstEntry,
  2481.                                     off_t& lastEntry,
  2482.                                     uint32 remainingIndirects);
  2483.            
  2484. -           uint32              _Hash(const char* name, uint8 version);
  2485. -          
  2486. -           uint32              _HashLegacy(const char* name);
  2487. +           uint32              _HashLegacy(const char* name, uint8 length);
  2488.  
  2489.     inline  uint32              _MD4F(uint32 x, uint32 y, uint32 z);
  2490.     inline  uint32              _MD4G(uint32 x, uint32 y, uint32 z);
  2491. @@ -113,21 +129,24 @@
  2492.                                     uint32& c, uint32& d);
  2493.             void                _HalfMD4Transform(uint32 buffer[4],
  2494.                                     uint32 blocks[8]);
  2495. -           uint32              _HashHalfMD4(const char* name);
  2496. +           uint32              _HashHalfMD4(const char* name, uint8 length);
  2497.            
  2498.             void                _TEATransform(uint32 buffer[4],
  2499.                                     uint32 blocks[4]);
  2500. -           uint32              _HashTEA(const char* name);
  2501. +           uint32              _HashTEA(const char* name, uint8 length);
  2502.            
  2503.             void                _PrepareBlocksForHash(const char* string,
  2504. -                                   int length, uint32* blocks, int numBlocks);
  2505. +                                   uint32 length, uint32* blocks, uint32 numBlocks);
  2506.  
  2507. +   inline  status_t            _FallbackToLinearIteration(
  2508. +                                   DirectoryIterator** iterator);
  2509. +
  2510.             bool                fIndexed;
  2511.             uint32              fBlockSize;
  2512.             Inode*              fDirectory;
  2513.             uint32              fHashSeed[4];
  2514.             HTreeEntryIterator* fRootEntry;
  2515. -           ObjectDeleter<HTreeEntryIterator> fRootDeleter;
  2516. +           uint8               fHashVersion;
  2517.  };
  2518.  
  2519.  #endif // HTREE_H
  2520.  
  2521. Property changes on: src/add-ons/kernel/file_systems/ext2/HTree.h
  2522. ___________________________________________________________________
  2523. Added: svn:executable
  2524.    + *
  2525.  
  2526. Index: src/add-ons/kernel/file_systems/ext2/IndexedDirectoryIterator.cpp
  2527. ===================================================================
  2528. --- src/add-ons/kernel/file_systems/ext2/IndexedDirectoryIterator.cpp   (revision 37957)
  2529. +++ src/add-ons/kernel/file_systems/ext2/IndexedDirectoryIterator.cpp   (working copy)
  2530. @@ -1,75 +0,0 @@
  2531. -/*
  2532. - * Copyright 2010, Haiku Inc. All rights reserved.
  2533. - * This file may be used under the terms of the MIT License.
  2534. - *
  2535. - * Authors:
  2536. - *     Janito V. Ferreira Filho
  2537. - */
  2538. -
  2539. -
  2540. -#include "IndexedDirectoryIterator.h"
  2541. -
  2542. -#include "ext2.h"
  2543. -#include "HTree.h"
  2544. -#include "HTreeEntryIterator.h"
  2545. -#include "Inode.h"
  2546. -
  2547. -
  2548. -//#define TRACE_EXT2
  2549. -#ifdef TRACE_EXT2
  2550. -#  define TRACE(x...) dprintf("\33[34mext2:\33[0m " x)
  2551. -#else
  2552. -#  define TRACE(x...) ;
  2553. -#endif
  2554. -
  2555. -
  2556. -IndexedDirectoryIterator::IndexedDirectoryIterator(off_t start,
  2557. -   uint32 blockSize, Inode* directory, HTreeEntryIterator* parent)
  2558. -   :
  2559. -   DirectoryIterator(directory),
  2560. -   fIndexing(true),
  2561. -  
  2562. -   fParent(parent),
  2563. -   fMaxOffset(start + blockSize),
  2564. -   fBlockSize(blockSize),
  2565. -   fMaxAttempts(0)
  2566. -{
  2567. -   fOffset = start;
  2568. -}
  2569. -
  2570. -
  2571. -IndexedDirectoryIterator::~IndexedDirectoryIterator()
  2572. -{
  2573. -}
  2574. -
  2575. -
  2576. -status_t
  2577. -IndexedDirectoryIterator::GetNext(char* name, size_t* nameLength, ino_t* id)
  2578. -{
  2579. -   if (fIndexing && fOffset + sizeof(HTreeFakeDirEntry) >= fMaxOffset) {
  2580. -       TRACE("IndexedDirectoryIterator::GetNext() calling next block\n");
  2581. -       status_t status = fParent->GetNext(fOffset);
  2582. -       if (status != B_OK)
  2583. -           return status;
  2584. -
  2585. -       if (fMaxAttempts++ > 4)
  2586. -           return B_ERROR;
  2587. -      
  2588. -       fMaxOffset = fOffset + fBlockSize;
  2589. -   }
  2590. -  
  2591. -   return DirectoryIterator::GetNext(name, nameLength, id);
  2592. -}
  2593. -
  2594. -
  2595. -status_t
  2596. -IndexedDirectoryIterator::Rewind()
  2597. -{
  2598. -   // The only way to rewind it is too loose indexing
  2599. -  
  2600. -   fOffset = 0;
  2601. -   fMaxOffset = fInode->Size();
  2602. -   fIndexing = false;
  2603. -
  2604. -   return B_OK;
  2605. -}
  2606. Index: src/add-ons/kernel/file_systems/ext2/DirectoryIterator.h
  2607. ===================================================================
  2608. --- src/add-ons/kernel/file_systems/ext2/DirectoryIterator.h    (revision 37957)
  2609. +++ src/add-ons/kernel/file_systems/ext2/DirectoryIterator.h    (working copy)
  2610. @@ -6,28 +6,68 @@
  2611.  #define DIRECTORY_ITERATOR_H
  2612.  
  2613.  
  2614. +#include <AutoDeleter.h>
  2615.  #include <SupportDefs.h>
  2616.  
  2617. +#include "Transaction.h"
  2618.  
  2619. +
  2620. +class HTreeEntryIterator;
  2621.  class Inode;
  2622.  
  2623.  class DirectoryIterator {
  2624.  public:
  2625. -                       DirectoryIterator(Inode* inode);
  2626. -   virtual             ~DirectoryIterator();
  2627. +                       DirectoryIterator(Inode* inode, off_t start = 0,
  2628. +                           HTreeEntryIterator* parent = NULL);
  2629. +                       ~DirectoryIterator();
  2630.  
  2631. -   virtual status_t    GetNext(char* name, size_t* _nameLength, ino_t* id);
  2632. +           status_t    InitCheck();
  2633.  
  2634. -   virtual status_t    Rewind();
  2635.  
  2636. +           status_t    Next();
  2637. +           status_t    Get(char* name, size_t* _nameLength, ino_t* id);
  2638. +
  2639. +           status_t    Rewind();
  2640. +
  2641. +           status_t    AddEntry(Transaction& transaction, const char* name,
  2642. +                           size_t nameLength, ino_t id);
  2643. +           status_t    FindEntry(const char* name, ino_t* id = NULL);
  2644. +           status_t    RemoveEntry(Transaction& transaction);
  2645. +
  2646.  private:
  2647.                         DirectoryIterator(const DirectoryIterator&);
  2648.                         DirectoryIterator &operator=(const DirectoryIterator&);
  2649.                             // no implementation
  2650.  
  2651. +
  2652.  protected:
  2653. -   Inode*              fInode;
  2654. -   off_t               fOffset;
  2655. +           status_t    _AllocateBestEntryInBlock(uint8 nameLength, uint16& pos,
  2656. +                           uint16& newLength);
  2657. +           status_t    _AddEntry(Transaction& transaction, const char* name,
  2658. +                           uint8 nameLength, ino_t id, uint16 newLength,
  2659. +                           uint16 pos, bool hasPrevious = true);
  2660. +           status_t    _SplitIndexedBlock(Transaction& transaction,
  2661. +                           const char* name, uint8 nameLength, ino_t id,
  2662. +                           bool firstSplit = false);
  2663. +
  2664. +           status_t    _NextBlock();
  2665. +
  2666. +
  2667. +   Inode*              fDirectory;
  2668. +   Volume*             fVolume;
  2669. +   uint32              fBlockSize;
  2670. +   HTreeEntryIterator* fParent;
  2671. +   bool                fIndexing;
  2672. +
  2673. +   uint32              fLogicalBlock;
  2674. +   uint32              fPhysicalBlock;
  2675. +   uint32              fDisplacement;
  2676. +   uint32              fPreviousDisplacement;
  2677. +
  2678. +   ObjectDeleter<HTreeEntryIterator> fParentDeleter;
  2679. +
  2680. +   status_t            fInitStatus;
  2681.  };
  2682.  
  2683.  #endif // DIRECTORY_ITERATOR_H
  2684. +
  2685. Index: src/add-ons/kernel/file_systems/ext2/RevokeManager.cpp
  2686. ===================================================================
  2687. --- src/add-ons/kernel/file_systems/ext2/RevokeManager.cpp  (revision 0)
  2688. +++ src/add-ons/kernel/file_systems/ext2/RevokeManager.cpp  (revision 0)
  2689. @@ -0,0 +1,51 @@
  2690. +/*
  2691. + * Copyright 2001-2010, Haiku Inc. All rights reserved.
  2692. + * This file may be used under the terms of the MIT License.
  2693. + *
  2694. + * Authors:
  2695. + *     Janito V. Ferreira Filho
  2696. + */
  2697. +
  2698. +#include "RevokeManager.h"
  2699. +
  2700. +
  2701. +//#define TRACE_EXT2
  2702. +#ifdef TRACE_EXT2
  2703. +#  define TRACE(x...) dprintf("\33[34mext2:\33[0m " x)
  2704. +#else
  2705. +#  define TRACE(x...) ;
  2706. +#endif
  2707. +
  2708. +
  2709. +RevokeManager::RevokeManager()
  2710. +   :
  2711. +   fRevokeCount(0)
  2712. +{
  2713. +}
  2714. +
  2715. +
  2716. +RevokeManager::~RevokeManager()
  2717. +{
  2718. +}
  2719. +
  2720. +
  2721. +status_t
  2722. +RevokeManager::ScanRevokeBlock(JournalRevokeHeader* revokeBlock, uint32 commitID)
  2723. +{
  2724. +   TRACE("RevokeManager::ScanRevokeBlock(): Commit ID: %lu\n", commitID);
  2725. +   int count = revokeBlock->NumBytes() >> 3;
  2726. +  
  2727. +   for (int i = 0; i < count; ++i) {
  2728. +       TRACE("RevokeManager::ScanRevokeBlock(): Found a revoke block: %lu\n",
  2729. +           revokeBlock->RevokeBlock(i));
  2730. +       status_t status = Insert(revokeBlock->RevokeBlock(i), commitID);
  2731. +      
  2732. +       if (status != B_OK) {
  2733. +           TRACE("RevokeManager::ScanRevokeBlock(): Error inserting\n");
  2734. +           return status;
  2735. +       }
  2736. +   }
  2737. +
  2738. +   return B_OK;
  2739. +}
  2740. +
  2741.  
  2742. Property changes on: src/add-ons/kernel/file_systems/ext2/RevokeManager.cpp
  2743. ___________________________________________________________________
  2744. Added: svn:executable
  2745.    + *
  2746.  
  2747. Index: src/add-ons/kernel/file_systems/ext2/Jamfile
  2748. ===================================================================
  2749. --- src/add-ons/kernel/file_systems/ext2/Jamfile    (revision 37957)
  2750. +++ src/add-ons/kernel/file_systems/ext2/Jamfile    (working copy)
  2751. @@ -7,6 +7,7 @@
  2752.  }
  2753.  
  2754.  #UsePrivateHeaders [ FDirName kernel disk_device_manager ] ;
  2755. +UsePrivateHeaders [ FDirName kernel util ] ;
  2756.  UsePrivateHeaders shared storage ;
  2757.  UsePrivateKernelHeaders ;
  2758.  
  2759. @@ -15,9 +16,17 @@
  2760.     Inode.cpp
  2761.     AttributeIterator.cpp
  2762.     DirectoryIterator.cpp
  2763. -   IndexedDirectoryIterator.cpp
  2764.     HTree.cpp
  2765.     HTreeEntryIterator.cpp
  2766. +   RevokeManager.cpp
  2767. +   HashRevokeManager.cpp
  2768. +   Journal.cpp
  2769. +   NoJournal.cpp
  2770. +   InodeJournal.cpp
  2771. +   Transaction.cpp
  2772. +   BitmapBlock.cpp
  2773. +   BlockAllocator.cpp
  2774. +   InodeAllocator.cpp
  2775.  
  2776.     kernel_interface.cpp
  2777.  ;
  2778. Index: src/add-ons/kernel/file_systems/ext2/BitmapBlock.cpp
  2779. ===================================================================
  2780. --- src/add-ons/kernel/file_systems/ext2/BitmapBlock.cpp    (revision 0)
  2781. +++ src/add-ons/kernel/file_systems/ext2/BitmapBlock.cpp    (revision 0)
  2782. @@ -0,0 +1,639 @@
  2783. +/*
  2784. + * Copyright 2001-2010, Haiku Inc. All rights reserved.
  2785. + * This file may be used under the terms of the MIT License.
  2786. + *
  2787. + * Authors:
  2788. + *     Janito V. Ferreira Filho
  2789. + */
  2790. +
  2791. +#include "BitmapBlock.h"
  2792. +
  2793. +
  2794. +//#define TRACE_EXT2
  2795. +#ifdef TRACE_EXT2
  2796. +#  define TRACE(x...) dprintf("\33[34mext2:\33[0m " x)
  2797. +#else
  2798. +#  define TRACE(x...) ;
  2799. +#endif
  2800. +
  2801. +
  2802. +BitmapBlock::BitmapBlock(Volume* volume, uint32 numBits)
  2803. +   :
  2804. +   CachedBlock(volume),
  2805. +   fData(NULL),
  2806. +   fReadOnlyData(NULL),
  2807. +   fNumBits(numBits)
  2808. +{
  2809. +   TRACE("BitmapBlock::BitmapBlock(): num bits: %lu\n", fNumBits);
  2810. +}
  2811. +
  2812. +
  2813. +BitmapBlock::~BitmapBlock()
  2814. +{
  2815. +}
  2816. +
  2817. +
  2818. +/*virtual*/ bool
  2819. +BitmapBlock::SetTo(uint32 block)
  2820. +{
  2821. +   fData = NULL;
  2822. +   fReadOnlyData = (uint32*)CachedBlock::SetTo(block);
  2823. +
  2824. +   return fReadOnlyData != NULL;
  2825. +}
  2826. +
  2827. +
  2828. +/*virtual*/ bool
  2829. +BitmapBlock::SetToWritable(Transaction& transaction, uint32 block, bool empty)
  2830. +{
  2831. +   fReadOnlyData = NULL;
  2832. +   fData = (uint32*)CachedBlock::SetToWritable(transaction, block, empty);
  2833. +
  2834. +   return fData != NULL;
  2835. +}
  2836. +
  2837. +
  2838. +/*virtual*/ bool
  2839. +BitmapBlock::CheckUnmarked(uint32 start, uint32 length)
  2840. +{
  2841. +   const uint32* data = fData == NULL ? fReadOnlyData : fData;
  2842. +   if (data == NULL)
  2843. +       return false;
  2844. +
  2845. +   if (start + length > fNumBits)
  2846. +       return false;
  2847. +
  2848. +   uint32 startIndex = start >> 5;
  2849. +   uint32 startBit = start & 0x1F;
  2850. +   uint32 remainingBits = (length - startBit) & 0x1F;
  2851. +
  2852. +   uint32 iterations;
  2853. +  
  2854. +   if (length < 32) {
  2855. +       if (startBit + length < 32) {
  2856. +           uint32 bits = B_LENDIAN_TO_HOST_INT32(fData[startIndex]);
  2857. +
  2858. +           uint32 mask = (1 << startBit + length) - 1;
  2859. +           mask &= ~((1 << startBit) - 1);
  2860. +          
  2861. +           return (bits & mask) == 0;
  2862. +       } else
  2863. +           iterations = 0;
  2864. +   } else
  2865. +       iterations = (length - 32 + startBit) >> 5;
  2866. +
  2867. +   uint32 index = startIndex;
  2868. +   uint32 mask = 0;
  2869. +
  2870. +   if (startBit != 0) {
  2871. +       mask = ~((1 << startBit) - 1);
  2872. +       uint32 bits = B_LENDIAN_TO_HOST_INT32(data[index]);
  2873. +
  2874. +       if ((bits & mask) != 0)
  2875. +           return false;
  2876. +
  2877. +       index += 1;
  2878. +   }
  2879. +
  2880. +   for (; iterations > 0; --iterations) {
  2881. +       if (data[index++] != 0)
  2882. +           return false;
  2883. +   }
  2884. +
  2885. +   if (remainingBits != 0) {
  2886. +       mask = (1 << remainingBits + 1) - 1;
  2887. +
  2888. +       uint32 bits = B_LENDIAN_TO_HOST_INT32(data[index]);
  2889. +       if ((bits & mask) != 0)
  2890. +           return false;
  2891. +   }
  2892. +
  2893. +   return true;
  2894. +}
  2895. +
  2896. +
  2897. +/*virtual*/ bool
  2898. +BitmapBlock::CheckMarked(uint32 start, uint32 length)
  2899. +{
  2900. +   const uint32* data = fData == NULL ? fReadOnlyData : fData;
  2901. +   if (data == NULL)
  2902. +       return false;
  2903. +
  2904. +   if (start + length > fNumBits)
  2905. +       return false;
  2906. +
  2907. +   uint32 startIndex = start >> 5;
  2908. +   uint32 startBit = start & 0x1F;
  2909. +   uint32 remainingBits = (length - startBit) & 0x1F;
  2910. +
  2911. +   uint32 iterations;
  2912. +  
  2913. +   if (length < 32) {
  2914. +       if (startBit + length < 32) {
  2915. +           uint32 bits = B_LENDIAN_TO_HOST_INT32(fData[startIndex]);
  2916. +
  2917. +           uint32 mask = (1 << startBit + length) - 1;
  2918. +           mask &= ~((1 << startBit) - 1);
  2919. +          
  2920. +           return (bits & mask) != 0;
  2921. +       } else
  2922. +           iterations = 0;
  2923. +   } else
  2924. +       iterations = (length - 32 + startBit) >> 5;
  2925. +
  2926. +   uint32 index = startIndex;
  2927. +   uint32 mask = 0;
  2928. +
  2929. +   if (startBit != 0) {
  2930. +       mask = ~((1 << startBit) - 1);
  2931. +       uint32 bits = B_LENDIAN_TO_HOST_INT32(data[index]);
  2932. +
  2933. +       if ((bits & mask) != mask)
  2934. +           return false;
  2935. +
  2936. +       index += 1;
  2937. +   }
  2938. +
  2939. +   mask = 0xFFFFFFFF;
  2940. +   for (; iterations > 0; --iterations) {
  2941. +       if (data[index++] != mask)
  2942. +           return false;
  2943. +   }
  2944. +
  2945. +   if (remainingBits != 0) {
  2946. +       mask = (1 << remainingBits + 1) - 1;
  2947. +       uint32 bits = B_HOST_TO_LENDIAN_INT32(data[index]);
  2948. +
  2949. +       if ((bits & mask) != mask)
  2950. +           return false;
  2951. +   }
  2952. +
  2953. +   return true;
  2954. +}
  2955. +
  2956. +
  2957. +/*virtual*/ bool
  2958. +BitmapBlock::Mark(uint32 start, uint32 length, bool force)
  2959. +{
  2960. +   if (fData == NULL || start + length > fNumBits)
  2961. +       return false;
  2962. +
  2963. +   uint32 startIndex = start >> 5;
  2964. +   uint32 startBit = start & 0x1F;
  2965. +   uint32 remainingBits = (length - 32 + startBit) & 0x1F;
  2966. +
  2967. +   uint32 iterations;
  2968. +  
  2969. +   if (length < 32) {
  2970. +       if (startBit + length < 32) {
  2971. +           uint32 bits = B_LENDIAN_TO_HOST_INT32(fData[startIndex]);
  2972. +
  2973. +           uint32 mask = (1 << startBit + length) - 1;
  2974. +           mask &= ~((1 << startBit) - 1);
  2975. +          
  2976. +           if ((bits & mask) != 0)
  2977. +               return false;
  2978. +          
  2979. +           bits |= mask;
  2980. +          
  2981. +           fData[startIndex] = B_HOST_TO_LENDIAN_INT32(bits);
  2982. +          
  2983. +           return true;
  2984. +       } else
  2985. +           iterations = 0;
  2986. +   } else
  2987. +       iterations = (length - 32 + startBit) >> 5;
  2988. +
  2989. +   uint32 index = startIndex;
  2990. +   uint32 mask = 0;
  2991. +  
  2992. +   TRACE("BitmapBlock::Mark(): start: %lu, length: %lu, startIndex: %lu, "
  2993. +       "startBit: %lu, iterations: %lu, remainingBits: %lu\n", start, length,
  2994. +       startIndex, startBit, iterations, remainingBits);
  2995. +
  2996. +   if (startBit != 0) {
  2997. +       mask = ~((1 << startBit) - 1);
  2998. +       uint32 bits = B_LENDIAN_TO_HOST_INT32(fData[index]);
  2999. +      
  3000. +       TRACE("BitmapBlock::Mark(): mask: %lX, bits: %lX\n", mask, bits);
  3001. +
  3002. +       if (!force && (bits & mask) != 0)
  3003. +           return false;
  3004. +
  3005. +       bits |= mask;
  3006. +       fData[index] = B_HOST_TO_LENDIAN_INT32(bits);
  3007. +
  3008. +       index += 1;
  3009. +   }
  3010. +
  3011. +   mask = 0xFFFFFFFF;
  3012. +   for (; iterations > 0; --iterations) {
  3013. +       if (!force && fData[index] != 0)
  3014. +           return false;
  3015. +       fData[index++] |= mask;
  3016. +   }
  3017. +
  3018. +   if (remainingBits != 0) {
  3019. +       mask = (1 << remainingBits) - 1;
  3020. +       uint32 bits = B_LENDIAN_TO_HOST_INT32(fData[index]);
  3021. +       TRACE("BitmapBlock::(): marking remaining %lu bits: %lX, mask: %lX\n",
  3022. +           remainingBits, bits, mask);
  3023. +
  3024. +       if (!force && (bits & mask) != 0)
  3025. +           return false;
  3026. +
  3027. +       bits |= mask;
  3028. +       fData[index] = B_HOST_TO_LENDIAN_INT32(bits);
  3029. +   }
  3030. +
  3031. +   return true;
  3032. +}
  3033. +
  3034. +
  3035. +/*virtual*/ bool
  3036. +BitmapBlock::Unmark(uint32 start, uint32 length, bool force)
  3037. +{
  3038. +   if (fData == NULL || start + length > fNumBits)
  3039. +       return false;
  3040. +
  3041. +   uint32 startIndex = start >> 5;
  3042. +   uint32 startBit = start & 0x1F;
  3043. +   uint32 remainingBits = (length - 32 + startBit) & 0x1F;
  3044. +
  3045. +   uint32 iterations;
  3046. +  
  3047. +   if (length < 32) {
  3048. +       if (startBit + length < 32) {
  3049. +           uint32 bits = B_LENDIAN_TO_HOST_INT32(fData[startIndex]);
  3050. +
  3051. +           uint32 mask = (1 << startBit + length) - 1;
  3052. +           mask &= ~((1 << startBit) - 1);
  3053. +          
  3054. +           if ((bits & mask) != mask)
  3055. +               return false;
  3056. +          
  3057. +           bits &= ~mask;
  3058. +          
  3059. +           fData[startIndex] = B_HOST_TO_LENDIAN_INT32(bits);
  3060. +          
  3061. +           return true;
  3062. +       } else
  3063. +           iterations = 0;
  3064. +   } else
  3065. +       iterations = (length - 32 + startBit) >> 5;
  3066. +
  3067. +   uint32 index = startIndex;
  3068. +   uint32 mask = 0;
  3069. +
  3070. +   if (startBit != 0) {
  3071. +       mask = ~((1 << startBit) - 1);
  3072. +       uint32 bits = B_LENDIAN_TO_HOST_INT32(fData[index]);
  3073. +
  3074. +       if (!force && (bits & mask) != mask)
  3075. +           return false;
  3076. +
  3077. +       bits &= ~mask;
  3078. +       fData[index] = B_HOST_TO_LENDIAN_INT32(bits);
  3079. +
  3080. +       index += 1;
  3081. +   }
  3082. +
  3083. +   mask = 0xFFFFFFFF;
  3084. +   for (; iterations > 0; --iterations) {
  3085. +       if (!force && fData[index] != mask)
  3086. +           return false;
  3087. +       fData[index++] = 0;
  3088. +   }
  3089. +
  3090. +   if (remainingBits != 0) {
  3091. +       mask = (1 << remainingBits) - 1;
  3092. +       uint32 bits = B_LENDIAN_TO_HOST_INT32(fData[index]);
  3093. +
  3094. +       if (!force && (bits & mask) != mask)
  3095. +           return false;
  3096. +
  3097. +       bits &= ~mask;
  3098. +       fData[index] = B_HOST_TO_LENDIAN_INT32(bits);
  3099. +   }
  3100. +
  3101. +   return true;
  3102. +}
  3103. +
  3104. +
  3105. +void
  3106. +BitmapBlock::FindNextMarked(uint32& pos)
  3107. +{
  3108. +   TRACE("BitmapBlock::FindNextMarked(): pos: %lu\n", pos);
  3109. +
  3110. +   const uint32* data = fData == NULL ? fReadOnlyData : fData;
  3111. +   if (data == NULL)
  3112. +       return;
  3113. +
  3114. +   if (pos >= fNumBits) {
  3115. +       pos = fNumBits;
  3116. +       return;
  3117. +   }
  3118. +
  3119. +   uint32 index = pos >> 5;
  3120. +   uint32 bit = pos & 0x1F;
  3121. +
  3122. +   uint32 mask = (1 << bit) - 1;
  3123. +   uint32 bits = B_LENDIAN_TO_HOST_INT32(data[index]);
  3124. +
  3125. +   TRACE("BitmapBlock::FindNextMarked(): index: %lu, bit: %lu, mask: %lX, "
  3126. +       "bits: %lX\n", index, bit, mask, bits);
  3127. +
  3128. +   bits = bits & ~mask;
  3129. +
  3130. +   if (bits == 0) {
  3131. +       // Find an block of 32 bits that has a marked bit
  3132. +       uint32 maxIndex = fNumBits >> 5;
  3133. +       TRACE("BitmapBlock::FindNextMarked(): max index: %lu\n", maxIndex);
  3134. +
  3135. +       do {
  3136. +           index++;
  3137. +       } while (index < maxIndex && data[index] == 0);
  3138. +
  3139. +       if (index >= maxIndex) {
  3140. +           // Not found
  3141. +           TRACE("BitmapBlock::FindNextMarked(): reached end of block, num "
  3142. +               "bits: %lu\n", fNumBits);
  3143. +           pos = fNumBits;
  3144. +           return;
  3145. +       }
  3146. +
  3147. +       bits = B_LENDIAN_TO_HOST_INT32(data[index]);
  3148. +       bit = 0;
  3149. +   }
  3150. +
  3151. +   for (; bit < 32; ++bit) {
  3152. +       // Find the marked bit
  3153. +       if ((bits >> bit & 1) != 0) {
  3154. +           pos = index << 5 | bit;
  3155. +           TRACE("BitmapBlock::FindNextMarked(): found bit: %lu\n", pos);
  3156. +           return;
  3157. +       }
  3158. +   }
  3159. +
  3160. +   panic("Couldn't find marked bit inside an int32 which is different than "
  3161. +       "zero!?\n");
  3162. +}
  3163. +
  3164. +
  3165. +void
  3166. +BitmapBlock::FindNextUnmarked(uint32& pos)
  3167. +{
  3168. +   TRACE("BitmapBlock::FindNextUnmarked(): pos: %lu\n", pos);
  3169. +
  3170. +   const uint32* data = fData == NULL ? fReadOnlyData : fData;
  3171. +   if (data == NULL)
  3172. +       return;
  3173. +
  3174. +   if (pos >= fNumBits) {
  3175. +       pos = fNumBits;
  3176. +       return;
  3177. +   }
  3178. +
  3179. +   uint32 index = pos >> 5;
  3180. +   uint32 bit = pos & 0x1F;
  3181. +
  3182. +   uint32 mask = (1 << bit) - 1;
  3183. +   uint32 bits = B_LENDIAN_TO_HOST_INT32(data[index]);
  3184. +
  3185. +   TRACE("BitmapBlock::FindNextUnmarked(): index: %lu, bit: %lu, mask: %lX, "
  3186. +       "bits: %lX\n", index, bit, mask, bits);
  3187. +
  3188. +   bits &= ~mask;
  3189. +
  3190. +   if (bits == ~mask) {
  3191. +       // Find an block of 32 bits that has a unmarked bit
  3192. +       uint32 maxIndex = fNumBits >> 5;
  3193. +       TRACE("BitmapBlock::FindNextUnmarked(): max index: %lu\n", maxIndex);
  3194. +
  3195. +       do {
  3196. +           index++;
  3197. +       } while (index < maxIndex && data[index] == 0xFFFFFFFF);
  3198. +
  3199. +       if (index >= maxIndex) {
  3200. +           // Not found
  3201. +           TRACE("BitmapBlock::FindNextUnmarked(): reached end of block, num "
  3202. +               "bits: %lu\n", fNumBits);
  3203. +           pos = fNumBits;
  3204. +           return;
  3205. +       }
  3206. +
  3207. +       bits = B_LENDIAN_TO_HOST_INT32(data[index]);
  3208. +       bit = 0;
  3209. +   }
  3210. +
  3211. +   for (; bit < 32; ++bit) {
  3212. +       // Find the unmarked bit
  3213. +       if ((bits >> bit & 1) == 0) {
  3214. +           pos = index << 5 | bit;
  3215. +           TRACE("BitmapBlock::FindNextUnmarked(): found bit: %lu\n", pos);
  3216. +           return;
  3217. +       }
  3218. +   }
  3219. +
  3220. +   panic("Couldn't find unmarked bit inside an int32 whith value zero!?\n");
  3221. +}
  3222. +
  3223. +
  3224. +void
  3225. +BitmapBlock::FindPreviousMarked(uint32& pos)
  3226. +{
  3227. +   const uint32* data = fData == NULL ? fReadOnlyData : fData;
  3228. +   if (data == NULL)
  3229. +       return;
  3230. +
  3231. +   if (pos >= fNumBits)
  3232. +       pos = fNumBits;
  3233. +
  3234. +   if (pos == 0)
  3235. +       return;
  3236. +
  3237. +   uint32 index = pos >> 5;
  3238. +   uint32 bit = pos & 0x1F;
  3239. +
  3240. +   uint32 mask = (1 << bit + 1) - 1;
  3241. +   uint32 bits = B_LENDIAN_TO_HOST_INT32(data[index]);
  3242. +   bits = bits & mask;
  3243. +
  3244. +   if (bits == 0) {
  3245. +       // Find an block of 32 bits that has a marked bit
  3246. +       do { index--; }
  3247. +           while (data[index] == 0 && index >= 0);
  3248. +
  3249. +       bits = B_LENDIAN_TO_HOST_INT32(data[index]);
  3250. +       if (bits == 0) {
  3251. +           // Not found
  3252. +           pos = 0;
  3253. +           return;
  3254. +       }
  3255. +
  3256. +       bit = 31;
  3257. +   }
  3258. +
  3259. +   for (; bit >= 0; --bit) {
  3260. +       // Find the unmarked bit
  3261. +       if ((bits >> bit & 1) == 0) {
  3262. +           pos = index << 5 | bit;
  3263. +           return;
  3264. +       }
  3265. +   }
  3266. +
  3267. +   panic("Couldn't find marked bit inside an int32 whith value different than "
  3268. +       "zero!?\n");
  3269. +}
  3270. +
  3271. +
  3272. +void
  3273. +BitmapBlock::FindLargestUnmarkedRange(uint32& start, uint32& length)
  3274. +{
  3275. +   const uint32* data = fData == NULL ? fReadOnlyData : fData;
  3276. +   if (data == NULL)
  3277. +       return;
  3278. +
  3279. +   uint32 wordSpan = length >> 5;
  3280. +   uint32 lastIndex = fNumBits >> 5;
  3281. +   uint32 startIndex = 0;
  3282. +   uint32 index = 0;
  3283. +   uint32 bits = B_LENDIAN_TO_HOST_INT32(data[0]);
  3284. +
  3285. +   TRACE("BitmapBlock::FindLargestUnmarkedRange(): word span: %lu, last "
  3286. +       "index: %lu, start index: %lu, index: %lu, bits: %lX, start: %lu, "
  3287. +       "length: %lu\n", wordSpan, lastIndex, startIndex, index, bits, start,
  3288. +       length);
  3289. +
  3290. +   if (wordSpan == 0) {
  3291. +       uint32 startPos = 0;
  3292. +       uint32 endPos = 0;
  3293. +
  3294. +       while (endPos < fNumBits) {
  3295. +           FindNextUnmarked(startPos);
  3296. +           endPos = startPos;
  3297. +
  3298. +           if (startPos != fNumBits) {
  3299. +               FindNextMarked(endPos);
  3300. +
  3301. +               uint32 newLength = endPos - startPos;
  3302. +
  3303. +               if (newLength > length) {
  3304. +                   start = startPos;
  3305. +                   length = newLength;
  3306. +                   TRACE("BitmapBlock::FindLargestUnmarkedRange(): Found "
  3307. +                       "larger length %lu starting at %lu\n", length, start);
  3308. +               }
  3309. +
  3310. +               startPos = endPos;
  3311. +
  3312. +               if (newLength >= 32)
  3313. +                   break;
  3314. +           }
  3315. +       }
  3316. +      
  3317. +       if (endPos >= fNumBits)
  3318. +           return;
  3319. +
  3320. +       wordSpan = length >> 5;
  3321. +       startIndex = startPos >> 5;
  3322. +       index = (endPos >> 5) + 1;
  3323. +       bits = B_LENDIAN_TO_HOST_INT32(data[index]);
  3324. +   }
  3325. +
  3326. +   for (; index < lastIndex; ++index) {
  3327. +       bits = B_LENDIAN_TO_HOST_INT32(data[index]);
  3328. +
  3329. +       if (bits != 0) {
  3330. +           // Contains marked bits
  3331. +           if (index - startIndex >= wordSpan) {
  3332. +               uint32 newLength = index - startIndex - 1 << 5;
  3333. +               uint32 newStart = startIndex + 1 << 5;
  3334. +
  3335. +               uint32 startBits =
  3336. +                   B_LENDIAN_TO_HOST_INT32(data[startIndex]);
  3337. +
  3338. +               for (int32 bit = 31; bit >= 0; --bit) {
  3339. +                   if ((startBits >> bit & 1) != 0)
  3340. +                       break;
  3341. +
  3342. +                   ++newLength;
  3343. +                   --newStart;
  3344. +               }
  3345. +
  3346. +               for (int32 bit = 0; bit < 32; ++bit) {
  3347. +                   if ((bits >> bit & 1) != 0)
  3348. +                       break;
  3349. +
  3350. +                   ++newLength;
  3351. +               }
  3352. +
  3353. +               if (newLength > length) {
  3354. +                   start = newStart;
  3355. +                   length = newLength;
  3356. +                   wordSpan = length >> 5;
  3357. +                  
  3358. +                   TRACE("BitmapBlock::FindLargestUnmarkedRange(): Found "
  3359. +                       "larger length %lu starting at %lu; word span: "
  3360. +                       "%lu\n", length, start, wordSpan);
  3361. +               }
  3362. +           }
  3363. +
  3364. +           startIndex = index;
  3365. +       }
  3366. +   }
  3367. +  
  3368. +   --index;
  3369. +
  3370. +   if (index - startIndex >= wordSpan) {
  3371. +       uint32 newLength = index - startIndex << 5;
  3372. +       uint32 newStart = startIndex + 1 << 5;
  3373. +      
  3374. +       TRACE("BitmapBlock::FindLargestUnmarkedRange(): Possibly found a "
  3375. +           "larger range. index: %lu, start index: %lu, word span: %lu, "
  3376. +           "new length: %lu, new start: %lu\n", index, startIndex, wordSpan,
  3377. +           newLength, newStart);
  3378. +
  3379. +       if (newStart != 0) {
  3380. +           uint32 startBits = B_LENDIAN_TO_HOST_INT32(data[startIndex]);
  3381. +          
  3382. +           TRACE("BitmapBlock::FindLargestUnmarkedRange(): start bits: %lu\n",
  3383. +               startBits);
  3384. +
  3385. +           for (int32 bit = 31; bit >= 0; --bit) {
  3386. +               if ((startBits >> bit & 1) != 0)
  3387. +                   break;
  3388. +
  3389. +               ++newLength;
  3390. +               --newStart;
  3391. +           }
  3392. +          
  3393. +           TRACE("BitmapBlock::FindLargestUnmarkedRange(): updated new start "
  3394. +               "to %lu and new length to %lu\n", newStart, newLength);
  3395. +       }
  3396. +
  3397. +       for (int32 bit = 0; bit < 32; ++bit) {
  3398. +           if ((bits >> bit & 1) == 0)
  3399. +               break;
  3400. +
  3401. +           ++newLength;
  3402. +       }
  3403. +      
  3404. +       TRACE("BitmapBlock::FindLargestUnmarkedRange(): updated new length to "
  3405. +           "%lu\n", newLength);
  3406. +
  3407. +       if (newLength > length) {
  3408. +           start = newStart;
  3409. +           length = newLength;
  3410. +           TRACE("BitmapBlock::FindLargestUnmarkedRange(): Found "
  3411. +               "largest length %lu starting at %lu\n", length, start);
  3412. +       }
  3413. +   }
  3414. +}
  3415. +
  3416. +
  3417. +uint32
  3418. +BitmapBlock::NumBits() const
  3419. +{
  3420. +   return fNumBits;
  3421. +}
  3422.  
  3423. Property changes on: src/add-ons/kernel/file_systems/ext2/BitmapBlock.cpp
  3424. ___________________________________________________________________
  3425. Added: svn:executable
  3426.    + *
  3427.  
  3428. Index: src/add-ons/kernel/file_systems/ext2/InodeJournal.cpp
  3429. ===================================================================
  3430. --- src/add-ons/kernel/file_systems/ext2/InodeJournal.cpp   (revision 0)
  3431. +++ src/add-ons/kernel/file_systems/ext2/InodeJournal.cpp   (revision 0)
  3432. @@ -0,0 +1,90 @@
  3433. +/*
  3434. + * Copyright 2001-2010, Haiku Inc. All rights reserved.
  3435. + * This file may be used under the terms of the MIT License.
  3436. + *
  3437. + * Authors:
  3438. + *     Janito V. Ferreira Filho
  3439. + */
  3440. +
  3441. +#include "InodeJournal.h"
  3442. +
  3443. +#include <new>
  3444. +
  3445. +#include <fs_cache.h>
  3446. +
  3447. +#include "HashRevokeManager.h"
  3448. +
  3449. +
  3450. +//#define TRACE_EXT2
  3451. +#ifdef TRACE_EXT2
  3452. +#  define TRACE(x...) dprintf("\33[34mext2:\33[0m " x)
  3453. +#else
  3454. +#  define TRACE(x...) ;
  3455. +#endif
  3456. +
  3457. +
  3458. +InodeJournal::InodeJournal(Inode* inode)
  3459. +   :
  3460. +   Journal(),
  3461. +   fInode(inode)
  3462. +{
  3463. +   if (inode == NULL)
  3464. +       fInitStatus = B_BAD_DATA;
  3465. +   else {
  3466. +       Volume* volume = inode->GetVolume();
  3467. +
  3468. +       fFilesystemVolume = volume;
  3469. +       fFilesystemBlockCache = volume->BlockCache();
  3470. +       fJournalVolume = volume;
  3471. +       fJournalBlockCache = volume->BlockCache();
  3472. +
  3473. +       if (!inode->IsFileCacheDisabled())
  3474. +           fInitStatus = inode->DisableFileCache();
  3475. +       else
  3476. +           fInitStatus = B_OK;
  3477. +      
  3478. +       if (fInitStatus == B_OK) {
  3479. +           TRACE("InodeJournal::InodeJournal(): Inode's file cache disabled "
  3480. +               "successfully\n");
  3481. +           HashRevokeManager* revokeManager = new(std::nothrow)
  3482. +               HashRevokeManager;
  3483. +           TRACE("InodeJournal::InodeJournal(): Allocated a hash revoke "
  3484. +               "manager at %p\n", revokeManager);
  3485. +
  3486. +           if (revokeManager == NULL) {
  3487. +               TRACE("InodeJournal::InodeJournal(): Insufficient memory to "
  3488. +                   "create the hash revoke manager\n");
  3489. +               fInitStatus = B_NO_MEMORY;
  3490. +           } else {
  3491. +               fInitStatus = revokeManager->Init();
  3492. +              
  3493. +               if (fInitStatus == B_OK) {
  3494. +                   fRevokeManager = revokeManager;
  3495. +                   fInitStatus = _LoadSuperBlock();
  3496. +               }
  3497. +           }
  3498. +       }
  3499. +   }
  3500. +}
  3501. +
  3502. +
  3503. +InodeJournal::~InodeJournal()
  3504. +{
  3505. +}
  3506. +
  3507. +
  3508. +status_t
  3509. +InodeJournal::InitCheck()
  3510. +{
  3511. +   if (fInitStatus != B_OK)
  3512. +       TRACE("InodeJournal: Initialization error\n");
  3513. +   return fInitStatus;
  3514. +}
  3515. +
  3516. +
  3517. +status_t
  3518. +InodeJournal::MapBlock(uint32 logical, uint32& physical)
  3519. +{
  3520. +   TRACE("InodeJournal::MapBlock()\n");
  3521. +   return fInode->FindBlock(logical * fBlockSize, physical);
  3522. +}
  3523. Index: src/add-ons/kernel/file_systems/ext2/Transaction.h
  3524. ===================================================================
  3525. --- src/add-ons/kernel/file_systems/ext2/Transaction.h  (revision 0)
  3526. +++ src/add-ons/kernel/file_systems/ext2/Transaction.h  (revision 0)
  3527. @@ -0,0 +1,72 @@
  3528. +/*
  3529. + * Copyright 2001-2010, Haiku Inc. All rights reserved.
  3530. + * This file may be used under the terms of the MIT License.
  3531. + *
  3532. + * Authors:
  3533. + *     Janito V. Ferreira Filho
  3534. + */
  3535. +#ifndef TRANSACTION_H
  3536. +#define TRANSACTION_H
  3537. +
  3538. +
  3539. +#include <util/DoublyLinkedList.h>
  3540. +
  3541. +
  3542. +class Journal;
  3543. +class Volume;
  3544. +
  3545. +
  3546. +class TransactionListener
  3547. +   : public DoublyLinkedListLinkImpl<TransactionListener> {
  3548. +public:
  3549. +                               TransactionListener();
  3550. +   virtual                     ~TransactionListener();
  3551. +
  3552. +   virtual void                TransactionDone(bool success) = 0;
  3553. +   virtual void                RemovedFromTransaction() = 0;
  3554. +};
  3555. +
  3556. +typedef DoublyLinkedList<TransactionListener> TransactionListeners;
  3557. +
  3558. +
  3559. +class Transaction {
  3560. +public:
  3561. +                                   Transaction();
  3562. +                                   Transaction(Journal* journal);
  3563. +                                   ~Transaction();
  3564. +
  3565. +           status_t                Start(Journal* journal);
  3566. +           status_t                Done(bool success = true);
  3567. +
  3568. +           bool                    IsStarted() const;
  3569. +           bool                    HasParent() const;
  3570. +
  3571. +           status_t                WriteBlocks(off_t blockNumber,
  3572. +                                       const uint8* buffer,
  3573. +                                       size_t numBlocks = 1);
  3574. +
  3575. +           void                    Split();
  3576. +
  3577. +           Volume*                 GetVolume() const;
  3578. +           int32                   ID() const;
  3579. +
  3580. +           void                    AddListener(TransactionListener* listener);
  3581. +           void                    RemoveListener(
  3582. +                                       TransactionListener* listener);
  3583. +
  3584. +           void                    NotifyListeners(bool success);
  3585. +           void                    MoveListenersTo(Transaction* transaction);
  3586. +          
  3587. +           void                    SetParent(Transaction* transaction);
  3588. +           Transaction*            Parent() const;
  3589. +private:
  3590. +                                   Transaction(const Transaction& other);
  3591. +           Transaction&            operator=(const Transaction& other);
  3592. +               // no implementation
  3593. +
  3594. +           Journal*                fJournal;
  3595. +           TransactionListeners    fListeners;
  3596. +           Transaction*            fParent;
  3597. +};
  3598. +
  3599. +#endif // TRANSACTION_H
  3600. Index: src/add-ons/kernel/file_systems/ext2/BlockAllocator.cpp
  3601. ===================================================================
  3602. --- src/add-ons/kernel/file_systems/ext2/BlockAllocator.cpp (revision 0)
  3603. +++ src/add-ons/kernel/file_systems/ext2/BlockAllocator.cpp (revision 0)
  3604. @@ -0,0 +1,661 @@
  3605. +/*
  3606. + * Copyright 2001-2010, Haiku Inc. All rights reserved.
  3607. + * This file may be used under the terms of the MIT License.
  3608. + *
  3609. + * Authors:
  3610. + *     Janito V. Ferreira Filho
  3611. + */
  3612. +
  3613. +#include "BlockAllocator.h"
  3614. +
  3615. +#include <util/AutoLock.h>
  3616. +
  3617. +#include "BitmapBlock.h"
  3618. +#include "Inode.h"
  3619. +
  3620. +
  3621. +//#define TRACE_EXT2
  3622. +#ifdef TRACE_EXT2
  3623. +#  define TRACE(x...) dprintf("\33[34mext2:\33[0m " x)
  3624. +#else
  3625. +#  define TRACE(x...) ;
  3626. +#endif
  3627. +
  3628. +
  3629. +class AllocationBlockGroup : public TransactionListener {
  3630. +public:
  3631. +                       AllocationBlockGroup();
  3632. +                       ~AllocationBlockGroup();
  3633. +
  3634. +           status_t    Initialize(Volume* v, uint32 blockGroup,
  3635. +                           uint32 numBits);
  3636. +
  3637. +           status_t    ScanFreeRanges();
  3638. +           bool        IsFull() const;
  3639. +
  3640. +           status_t    Allocate(Transaction& transaction, uint32 start,
  3641. +                           uint32 length);
  3642. +           status_t    Free(Transaction& transaction, uint32 start,
  3643. +                           uint32 length);
  3644. +           status_t    FreeAll(Transaction& transaction);
  3645. +           status_t    Check(uint32 start, uint32 length);
  3646. +
  3647. +           uint32      NumBits() const;
  3648. +           uint32      FreeBits() const;
  3649. +           uint32      Start() const;
  3650. +
  3651. +           uint32      LargestStart() const;
  3652. +           uint32      LargestLength() const;
  3653. +
  3654. +           // TransactionListener implementation
  3655. +           void        TransactionDone(bool success);
  3656. +           void        RemovedFromTransaction();
  3657. +
  3658. +private:
  3659. +           void        _AddFreeRange(uint32 start, uint32 length);
  3660. +
  3661. +
  3662. +           Volume*     fVolume;
  3663. +
  3664. +           uint32      fStart;
  3665. +           uint32      fNumBits;
  3666. +           uint32      fBitmapBlock;
  3667. +
  3668. +           uint32      fFreeBits;
  3669. +           uint32      fFirstFree;
  3670. +           uint32      fLargestStart;
  3671. +           uint32      fLargestLength;
  3672. +          
  3673. +           uint32      fPreviousFreeBits;
  3674. +           uint32      fPreviousFirstFree;
  3675. +           uint32      fPreviousLargestStart;
  3676. +           uint32      fPreviousLargestLength;
  3677. +};
  3678. +
  3679. +
  3680. +class BlockAllocatorTransactionListener : public TransactionListener {
  3681. +public:
  3682. +                       BlockAllocatorTransactionListener(
  3683. +                           BlockAllocator* allocator, uint32 blocks);
  3684. +                       ~BlockAllocatorTransactionListener();
  3685. +
  3686. +           void        TransactionDone(bool success);
  3687. +           void        RemovedFromTransaction();
  3688. +private:
  3689. +           BlockAllocator* fAllocator;
  3690. +           uint32      fBlockAffected;
  3691. +};
  3692. +
  3693. +
  3694. +AllocationBlockGroup::AllocationBlockGroup()
  3695. +   :
  3696. +   fStart(0),
  3697. +   fNumBits(0),
  3698. +   fBitmapBlock(0),
  3699. +   fFreeBits(0),
  3700. +   fFirstFree(0),
  3701. +   fLargestStart(0),
  3702. +   fLargestLength(0),
  3703. +   fPreviousFreeBits(0),
  3704. +   fPreviousFirstFree(0),
  3705. +   fPreviousLargestStart(0),
  3706. +   fPreviousLargestLength(0)
  3707. +{
  3708. +}
  3709. +
  3710. +
  3711. +AllocationBlockGroup::~AllocationBlockGroup()
  3712. +{
  3713. +}
  3714. +
  3715. +
  3716. +status_t
  3717. +AllocationBlockGroup::Initialize(Volume* volume, uint32 blockGroup,
  3718. +   uint32 numBits)
  3719. +{
  3720. +   fVolume = volume;
  3721. +   fNumBits = numBits;
  3722. +
  3723. +   ext2_block_group* group;
  3724. +   status_t status = fVolume->GetBlockGroup(blockGroup, &group);
  3725. +   if (status != B_OK)
  3726. +       return status;
  3727. +
  3728. +   fBitmapBlock = group->BlockBitmap();
  3729. +
  3730. +   status = ScanFreeRanges();
  3731. +
  3732. +   fPreviousFreeBits = fFreeBits;
  3733. +   fPreviousFirstFree = fFirstFree;
  3734. +   fPreviousLargestStart = fLargestStart;
  3735. +   fPreviousLargestLength = fLargestLength;
  3736. +  
  3737. +   return status;
  3738. +}
  3739. +
  3740. +
  3741. +status_t
  3742. +AllocationBlockGroup::ScanFreeRanges()
  3743. +{
  3744. +   TRACE("AllocationBlockGroup::ScanFreeRanges()\n");
  3745. +   BitmapBlock block(fVolume, fNumBits);
  3746. +
  3747. +   if (!block.SetTo(fBitmapBlock))
  3748. +       return B_ERROR;
  3749. +
  3750. +   uint32 start = 0;
  3751. +   uint32 end = 0;
  3752. +
  3753. +   while (end < fNumBits) {
  3754. +       block.FindNextUnmarked(start);
  3755. +       end = start;
  3756. +
  3757. +       if (start != block.NumBits()) {
  3758. +           block.FindNextMarked(end);
  3759. +           _AddFreeRange(start, end - start);
  3760. +           start = end;
  3761. +       }
  3762. +   }
  3763. +
  3764. +   return B_OK;
  3765. +}
  3766. +
  3767. +
  3768. +bool
  3769. +AllocationBlockGroup::IsFull() const
  3770. +{
  3771. +   return fFreeBits == 0;
  3772. +}
  3773. +
  3774. +
  3775. +status_t
  3776. +AllocationBlockGroup::Allocate(Transaction& transaction, uint32 start,
  3777. +   uint32 length)
  3778. +{
  3779. +   TRACE("AllocationBlockGroup::Allocate()\n");
  3780. +   uint32 end = start + length;
  3781. +   if (end > fLargestLength + fLargestStart)
  3782. +       return B_BAD_DATA;
  3783. +
  3784. +   BitmapBlock block(fVolume, fNumBits);
  3785. +
  3786. +   if (!block.SetToWritable(transaction, fBitmapBlock))
  3787. +       return B_ERROR;
  3788. +  
  3789. +   if (!block.Mark(start, length)) {
  3790. +       TRACE("Failed to allocate blocks from %lu to %lu. Some were "
  3791. +           "already allocated.\n", start, start + length);
  3792. +       return B_ERROR;
  3793. +   }
  3794. +
  3795. +   transaction.AddListener(this);
  3796. +
  3797. +   fFreeBits -= length;
  3798. +
  3799. +   if (start == fLargestStart) {
  3800. +       if (fFirstFree == fLargestStart)
  3801. +           fFirstFree += length;
  3802. +
  3803. +       fLargestStart += length;
  3804. +       fLargestLength -= length;
  3805. +   } else if (start + length == fLargestStart + fLargestLength) {
  3806. +       fLargestLength -= length;
  3807. +   } else if (start < fLargestStart + fLargestLength
  3808. +           && start > fLargestStart) {
  3809. +       uint32 firstLength = start - fLargestStart;
  3810. +       uint32 secondLength = fLargestStart + fLargestLength
  3811. +           - (start + length);
  3812. +
  3813. +       if (firstLength >= secondLength) {
  3814. +           fLargestLength = firstLength;
  3815. +       } else {
  3816. +           fLargestLength = secondLength;
  3817. +           fLargestStart = start + length;
  3818. +       }
  3819. +   } else {
  3820. +       // No need to revalidate the largest free range
  3821. +       return B_OK;
  3822. +   }
  3823. +
  3824. +   if (fLargestLength < fNumBits / 2)
  3825. +       block.FindLargestUnmarkedRange(fLargestStart, fLargestLength);
  3826. +
  3827. +   return B_OK;
  3828. +}
  3829. +
  3830. +
  3831. +status_t
  3832. +AllocationBlockGroup::Free(Transaction& transaction, uint32 start,
  3833. +   uint32 length)
  3834. +{
  3835. +   uint32 end = start + length;
  3836. +
  3837. +   if (end > fLargestLength)
  3838. +       return B_BAD_DATA;
  3839. +
  3840. +   BitmapBlock block(fVolume, fNumBits);
  3841. +
  3842. +   if (!block.SetToWritable(transaction, fBitmapBlock))
  3843. +       return B_ERROR;
  3844. +
  3845. +   if (!block.Unmark(start, length)) {
  3846. +       TRACE("Failed to free blocks from %lu to %lu. Some were "
  3847. +           "already freed.\n", start, start + length);
  3848. +       return B_ERROR;
  3849. +   }
  3850. +
  3851. +   transaction.AddListener(this);
  3852. +
  3853. +   if (fFirstFree > start)
  3854. +       fFirstFree = start;
  3855. +
  3856. +   if (start + length == fLargestStart) {
  3857. +       fLargestStart = start;
  3858. +       fLargestLength += length;
  3859. +   } else if (start == fLargestStart + fLargestLength) {
  3860. +       fLargestLength += length;
  3861. +   } else if (fLargestLength >= fNumBits / 2) {
  3862. +       // May have merged with some free blocks, becoming the largest
  3863. +       uint32 newEnd = start + length;
  3864. +       block.FindNextMarked(newEnd);
  3865. +
  3866. +       uint32 newStart = start;
  3867. +       block.FindPreviousMarked(newStart);
  3868. +
  3869. +       if (newEnd - newStart > fLargestLength) {
  3870. +           fLargestLength = newEnd - newStart;
  3871. +           fLargestStart = newStart;
  3872. +       }
  3873. +   }
  3874. +
  3875. +   fFreeBits += length;
  3876. +
  3877. +   return B_OK;
  3878. +}
  3879. +
  3880. +
  3881. +status_t
  3882. +AllocationBlockGroup::FreeAll(Transaction& transaction)
  3883. +{
  3884. +   return Free(transaction, 0, fNumBits);
  3885. +}
  3886. +
  3887. +
  3888. +uint32
  3889. +AllocationBlockGroup::NumBits() const
  3890. +{
  3891. +   return fNumBits;
  3892. +}
  3893. +
  3894. +
  3895. +uint32
  3896. +AllocationBlockGroup::FreeBits() const
  3897. +{
  3898. +   return fFreeBits;
  3899. +}
  3900. +
  3901. +
  3902. +uint32
  3903. +AllocationBlockGroup::Start() const
  3904. +{
  3905. +   return fStart;
  3906. +}
  3907. +
  3908. +
  3909. +uint32
  3910. +AllocationBlockGroup::LargestStart() const
  3911. +{
  3912. +   return fLargestStart;
  3913. +}
  3914. +
  3915. +
  3916. +uint32
  3917. +AllocationBlockGroup::LargestLength() const
  3918. +{
  3919. +   return fLargestLength;
  3920. +}
  3921. +
  3922. +
  3923. +void
  3924. +AllocationBlockGroup::_AddFreeRange(uint32 start, uint32 length)
  3925. +{
  3926. +   if (IsFull()) {
  3927. +       fFirstFree = start;
  3928. +       fLargestStart = start;
  3929. +       fLargestLength = length;
  3930. +   } else if (length > fLargestLength) {
  3931. +       fLargestStart = start;
  3932. +       fLargestLength = length;
  3933. +   }
  3934. +
  3935. +   fFreeBits += length;
  3936. +}
  3937. +
  3938. +
  3939. +void
  3940. +AllocationBlockGroup::TransactionDone(bool success)
  3941. +{
  3942. +   if (success) {
  3943. +       TRACE("AllocationBlockGroup::TransactionDone(): The transaction "
  3944. +           "succeeded, discarding previous state\n");
  3945. +       fPreviousFreeBits = fFreeBits;
  3946. +       fPreviousFirstFree = fFirstFree;
  3947. +       fPreviousLargestStart = fLargestStart;
  3948. +       fPreviousLargestLength = fLargestLength;
  3949. +   } else {
  3950. +       TRACE("AllocationBlockGroup::TransactionDone(): The transaction "
  3951. +           "failed, restoring to previous state\n");
  3952. +       fFreeBits = fPreviousFreeBits;
  3953. +       fFirstFree = fPreviousFirstFree;
  3954. +       fLargestStart = fPreviousLargestStart;
  3955. +       fLargestLength = fPreviousLargestLength;
  3956. +   }
  3957. +}
  3958. +
  3959. +
  3960. +void
  3961. +AllocationBlockGroup::RemovedFromTransaction()
  3962. +{
  3963. +   // TODO: What to do here?
  3964. +}
  3965. +
  3966. +
  3967. +BlockAllocator::BlockAllocator(Volume* volume)
  3968. +   :
  3969. +   fVolume(volume),
  3970. +   fGroups(NULL),
  3971. +   fBlocksPerGroup(0),
  3972. +   fNumBlocks(0),
  3973. +   fNumGroups(0)
  3974. +{
  3975. +   mutex_init(&fLock, "ext2 block allocator");
  3976. +}
  3977. +
  3978. +
  3979. +BlockAllocator::~BlockAllocator()
  3980. +{
  3981. +   mutex_destroy(&fLock);
  3982. +
  3983. +   if (fGroups != NULL)
  3984. +       delete [] fGroups;
  3985. +}
  3986. +
  3987. +
  3988. +status_t
  3989. +BlockAllocator::Initialize()
  3990. +{
  3991. +   fBlocksPerGroup = fVolume->BlocksPerGroup();
  3992. +   fNumGroups = fVolume->NumGroups();
  3993. +   fFirstBlock = fVolume->FirstDataBlock();
  3994. +   fNumBlocks = fVolume->NumBlocks();
  3995. +  
  3996. +   TRACE("BlockAllocator::Initialize(): blocks per group: %lu, block groups: "
  3997. +       "%lu, first block: %lu, num blocks: %lu\n", fBlocksPerGroup,
  3998. +       fNumGroups, fFirstBlock, fNumBlocks);
  3999. +
  4000. +   fGroups = new(std::nothrow) AllocationBlockGroup[fNumGroups];
  4001. +   if (fGroups == NULL)
  4002. +       return B_NO_MEMORY;
  4003. +
  4004. +   TRACE("BlockAllocator::Initialize(): allocated allocation block groups\n");
  4005. +
  4006. +   mutex_lock(&fLock);
  4007. +       // Released by _Initialize
  4008. +
  4009. +   thread_id id = -1; // spawn_kernel_thread(
  4010. +       // (thread_func)BlockAllocator::_Initialize, "ext2 block allocator",
  4011. +       // B_LOW_PRIORITY, this);
  4012. +   if (id < B_OK)
  4013. +       return _Initialize(this);
  4014. +
  4015. +   // mutex_transfer_lock(&fLock, id);
  4016. +
  4017. +   // return resume_thread(id);
  4018. +   panic("Failed to fall back to synchronous block allocator"
  4019. +       "initialization.\n");
  4020. +   return B_ERROR;
  4021. +}
  4022. +
  4023. +
  4024. +status_t
  4025. +BlockAllocator::AllocateBlocks(Transaction& transaction, uint32 minimum,
  4026. +   uint32 maximum, uint32& blockGroup, uint32& start, uint32& length)
  4027. +{
  4028. +   TRACE("BlockAllocator::AllocateBlocks()\n");
  4029. +   MutexLocker lock(fLock);
  4030. +   TRACE("BlockAllocator::AllocateBlocks(): Aquired lock\n");
  4031. +
  4032. +   TRACE("BlockAllocator::AllocateBlocks(): transaction: %ld, min: %lu, "
  4033. +       "max: %lu, block group: %lu, start: %lu, num groups: %lu\n",
  4034. +       transaction.ID(), minimum, maximum, blockGroup, start, fNumGroups);
  4035. +
  4036. +   uint32 bestStart = 0;
  4037. +   uint32 bestLength = 0;
  4038. +   uint32 bestGroup = 0;
  4039. +
  4040. +   uint32 groupNum = blockGroup;
  4041. +
  4042. +   AllocationBlockGroup* last = &fGroups[fNumGroups];
  4043. +   AllocationBlockGroup* group = &fGroups[blockGroup];
  4044. +
  4045. +   for (int32 iterations = 0; iterations < 2; iterations++) {
  4046. +       for (; group < last; ++group, ++groupNum) {
  4047. +           TRACE("BlockAllocator::AllocateBlocks(): Group %lu has largest "
  4048. +           "length of %lu\n", groupNum, group->LargestLength());
  4049. +
  4050. +           if (group->LargestLength() > bestLength) {
  4051. +               if (start <= group->LargestStart()) {
  4052. +                   bestStart = group->LargestStart();
  4053. +                   bestLength = group->LargestLength();
  4054. +                   bestGroup = groupNum;
  4055. +
  4056. +                   TRACE("BlockAllocator::AllocateBlocks(): Found a better "
  4057. +                       "range: block group: %lu, %lu-%lu\n", groupNum,
  4058. +                       bestStart, bestStart + bestLength);
  4059. +
  4060. +                   if (bestLength >= maximum)
  4061. +                       break;
  4062. +               }
  4063. +           }
  4064. +
  4065. +           start = 0;
  4066. +       }
  4067. +
  4068. +       if (bestLength >= maximum)
  4069. +           break;
  4070. +
  4071. +       groupNum = 0;
  4072. +
  4073. +       group = &fGroups[0];
  4074. +       last = &fGroups[blockGroup + 1];
  4075. +   }
  4076. +
  4077. +   if (bestLength < minimum) {
  4078. +       TRACE("BlockAllocator::AllocateBlocks(): best range (length %lu) "
  4079. +           "doesn't have minimum length of %lu\n", bestLength, minimum);
  4080. +       return B_DEVICE_FULL;
  4081. +   }
  4082. +
  4083. +   if (bestLength > maximum)
  4084. +       bestLength = maximum;
  4085. +
  4086. +   TRACE("BlockAllocator::AllocateBlocks(): Selected range: block group %lu, "
  4087. +       "%lu-%lu\n", bestGroup, bestStart, bestStart + bestLength);
  4088. +
  4089. +   status_t status = fGroups[bestGroup].Allocate(transaction, bestStart,
  4090. +       bestLength);
  4091. +   if (status != B_OK) {
  4092. +       TRACE("BlockAllocator::AllocateBlocks(): Failed to allocate %lu blocks "
  4093. +           "inside block group %lu.\n", bestLength, bestGroup);
  4094. +       return status;
  4095. +   }
  4096. +
  4097. +   start = bestStart;
  4098. +   length = bestLength;
  4099. +   blockGroup = bestGroup;
  4100. +
  4101. +   return B_OK;
  4102. +}
  4103. +
  4104. +
  4105. +status_t
  4106. +BlockAllocator::Allocate(Transaction& transaction, Inode* inode,
  4107. +   off_t numBlocks, uint32 minimum, uint32& start, uint32& allocated)
  4108. +{
  4109. +   if (numBlocks <= 0)
  4110. +       return B_ERROR;
  4111. +
  4112. +   uint32 group = inode->ID() / fVolume->InodesPerGroup();
  4113. +   uint32 preferred = 0;
  4114. +
  4115. +   if (inode->Size() > 0) {
  4116. +       // Try to allocate near it's last blocks
  4117. +       ext2_data_stream* dataStream = &inode->Node().stream;
  4118. +       uint32 numBlocks = inode->Size() / fVolume->BlockSize() + 1;
  4119. +       uint32 lastBlock = 0;
  4120. +
  4121. +       // DANGER! What happens with sparse files?
  4122. +       if (numBlocks < EXT2_DIRECT_BLOCKS) {
  4123. +           // Only direct blocks
  4124. +           lastBlock = dataStream->direct[numBlocks];
  4125. +       } else {
  4126. +           numBlocks -= EXT2_DIRECT_BLOCKS - 1;
  4127. +           uint32 numIndexes = fVolume->BlockSize() / 4;
  4128. +               // block size / sizeof(int32)
  4129. +           uint32 numIndexes2 = numIndexes * numIndexes;
  4130. +           uint32 numIndexes3 = numIndexes2 * numIndexes;
  4131. +           uint32 indexesInIndirect = numIndexes;
  4132. +           uint32 indexesInDoubleIndirect = indexesInIndirect
  4133. +               + numIndexes2;
  4134. +           // uint32 indexesInTripleIndirect = indexesInDoubleIndirect
  4135. +               // + numIndexes3;
  4136. +
  4137. +           uint32 doubleIndirectBlock = EXT2_DIRECT_BLOCKS + 1;
  4138. +           uint32 indirectBlock = EXT2_DIRECT_BLOCKS;
  4139. +
  4140. +           CachedBlock cached(fVolume);
  4141. +           uint32* indirectData;
  4142. +
  4143. +           if (numBlocks > indexesInDoubleIndirect) {
  4144. +               // Triple indirect blocks
  4145. +               indirectData = (uint32*)cached.SetTo(EXT2_DIRECT_BLOCKS + 2);
  4146. +               if (indirectData == NULL)
  4147. +                   return B_IO_ERROR;
  4148. +
  4149. +               uint32 index = (numBlocks - indexesInDoubleIndirect)
  4150. +                   / numIndexes3;
  4151. +               doubleIndirectBlock = indirectData[index];
  4152. +           }
  4153. +
  4154. +           if (numBlocks > indexesInIndirect) {
  4155. +               // Double indirect blocks
  4156. +               indirectData = (uint32*)cached.SetTo(doubleIndirectBlock);
  4157. +               if (indirectData == NULL)
  4158. +                   return B_IO_ERROR;
  4159. +
  4160. +               uint32 index = (numBlocks - indexesInIndirect) / numIndexes2;
  4161. +               indirectBlock = indirectData[index];
  4162. +           }
  4163. +
  4164. +           indirectData = (uint32*)cached.SetTo(indirectBlock);
  4165. +               if (indirectData == NULL)
  4166. +                   return B_IO_ERROR;
  4167. +
  4168. +           uint32 index = numBlocks / numIndexes;
  4169. +           lastBlock = indirectData[index];
  4170. +       }
  4171. +
  4172. +       group = (lastBlock - fFirstBlock) / fBlocksPerGroup;
  4173. +       preferred = (lastBlock - fFirstBlock) % fBlocksPerGroup + 1;
  4174. +   }
  4175. +
  4176. +   // TODO: Apply some more policies
  4177. +
  4178. +   return AllocateBlocks(transaction, minimum, minimum + 8, group, start,
  4179. +       allocated);
  4180. +}
  4181. +
  4182. +
  4183. +status_t
  4184. +BlockAllocator::Free(Transaction& transaction, uint32 start, uint32 length)
  4185. +{
  4186. +   MutexLocker lock(fLock);
  4187. +
  4188. +   if (start == 0) {
  4189. +       panic("Trying to free superblock!\n");
  4190. +       return B_BAD_DATA;
  4191. +   }
  4192. +
  4193. +   if (length == 0)
  4194. +       return B_OK;
  4195. +
  4196. +   uint32 group = (start - fFirstBlock) / fBlocksPerGroup;
  4197. +   start = (start - fFirstBlock) % fBlocksPerGroup;
  4198. +   uint32 lastGroup = (start + length - fFirstBlock) / fBlocksPerGroup;
  4199. +
  4200. +   if (group == lastGroup)
  4201. +       return fGroups[group].Free(transaction, start, length);
  4202. +
  4203. +   status_t status = fGroups[group].Free(transaction, start,
  4204. +       fGroups[group].NumBits());
  4205. +   if (status != B_OK)
  4206. +       return status;
  4207. +
  4208. +   for (++group; group < lastGroup; ++group) {
  4209. +       status = fGroups[group].FreeAll(transaction);
  4210. +       if (status != B_OK)
  4211. +           return status;
  4212. +   }
  4213. +
  4214. +   return fGroups[group].Free(transaction, 0, (start + length - fFirstBlock)
  4215. +       % fBlocksPerGroup);
  4216. +}
  4217. +
  4218. +
  4219. +/*static*/ status_t
  4220. +BlockAllocator::_Initialize(BlockAllocator* allocator)
  4221. +{
  4222. +   TRACE("BlockAllocator::_Initialize()\n");
  4223. +   // fLock is already heald
  4224. +   Volume* volume = allocator->fVolume;
  4225. +
  4226. +   AllocationBlockGroup* groups = allocator->fGroups;
  4227. +   uint32 numGroups = allocator->fNumGroups - 1;
  4228. +
  4229. +   uint32 freeBlocks = 0;
  4230. +   TRACE("BlockAllocator::_Initialize(): free blocks: %lu\n", freeBlocks);
  4231. +
  4232. +   for (uint32 i = 0; i < numGroups; ++i) {
  4233. +       status_t status = groups[i].Initialize(volume, i,
  4234. +           allocator->fBlocksPerGroup);
  4235. +       if (status != B_OK) {
  4236. +           mutex_unlock(&allocator->fLock);
  4237. +           return status;
  4238. +       }
  4239. +
  4240. +       freeBlocks += groups[i].FreeBits();
  4241. +       TRACE("BlockAllocator::_Initialize(): free blocks: %lu\n", freeBlocks);
  4242. +   }
  4243. +  
  4244. +   // Last block group may have less blocks
  4245. +   status_t status = groups[numGroups].Initialize(volume, numGroups,
  4246. +       allocator->fNumBlocks - allocator->fBlocksPerGroup * numGroups
  4247. +       - allocator->fFirstBlock);
  4248. +   if (status != B_OK) {
  4249. +       mutex_unlock(&allocator->fLock);
  4250. +       return status;
  4251. +   }
  4252. +  
  4253. +   freeBlocks += groups[numGroups].FreeBits();
  4254. +
  4255. +   TRACE("BlockAllocator::_Initialize(): free blocks: %lu\n", freeBlocks);
  4256. +
  4257. +   mutex_unlock(&allocator->fLock);
  4258. +
  4259. +   if (freeBlocks != volume->NumFreeBlocks()) {
  4260. +       TRACE("Counted free blocks doesn't match value in the superblock.\n");
  4261. +       return B_BAD_DATA;
  4262. +   }
  4263. +
  4264. +   return B_OK;
  4265. +}
  4266.  
  4267. Property changes on: src/add-ons/kernel/file_systems/ext2/BlockAllocator.cpp
  4268. ___________________________________________________________________
  4269. Added: svn:executable
  4270.    + *
  4271.  
  4272. Index: src/add-ons/kernel/file_systems/ext2/Inode.cpp
  4273. ===================================================================
  4274. --- src/add-ons/kernel/file_systems/ext2/Inode.cpp  (revision 37957)
  4275. +++ src/add-ons/kernel/file_systems/ext2/Inode.cpp  (working copy)
  4276. @@ -8,8 +8,12 @@
  4277.  
  4278.  #include <fs_cache.h>
  4279.  #include <string.h>
  4280. +#include <util/AutoLock.h>
  4281.  
  4282.  #include "CachedBlock.h"
  4283. +#include "DirectoryIterator.h"
  4284. +#include "HTree.h"
  4285. +#include "Utility.h"
  4286.  
  4287.  
  4288.  //#define TRACE_EXT2
  4289. @@ -26,56 +30,131 @@
  4290.     fID(id),
  4291.     fCache(NULL),
  4292.     fMap(NULL),
  4293. -   fNode(NULL),
  4294.     fAttributesBlock(NULL)
  4295.  {
  4296.     rw_lock_init(&fLock, "ext2 inode");
  4297.  
  4298. -   uint32 block;
  4299. -   if (volume->GetInodeBlock(id, block) == B_OK) {
  4300. -       TRACE("inode %Ld at block %lu\n", ID(), block);
  4301. -       uint8* inodeBlock = (uint8*)block_cache_get(volume->BlockCache(),
  4302. -           block);
  4303. -       if (inodeBlock != NULL) {
  4304. -           fNode = (ext2_inode*)(inodeBlock + volume->InodeBlockIndex(id)
  4305. -               * volume->InodeSize());
  4306. +   fInitStatus = UpdateNodeFromDisk();
  4307. +   if (fInitStatus == B_OK) {
  4308. +       if (Size() == 0 || IsDirectory() || (IsSymLink() && Size() < 60)) {
  4309. +           fCached = false;
  4310. +       } else {
  4311. +           fCache = file_cache_create(fVolume->ID(), ID(), Size());
  4312. +           fMap = file_map_create(fVolume->ID(), ID(), Size());
  4313. +
  4314. +           if (fCache != NULL)
  4315. +               fCached = true;
  4316. +           else {
  4317. +               fCached = false;
  4318. +               fInitStatus = B_ERROR;
  4319. +           }
  4320.         }
  4321. +   } else {
  4322. +       TRACE("Inode: Failed initialization\n");
  4323. +       fCached = false;
  4324.     }
  4325. -
  4326. -   if (fNode != NULL) {
  4327. -       // TODO: we don't need a cache for short symlinks
  4328. -       fCache = file_cache_create(fVolume->ID(), ID(), Size());
  4329. -       fMap = file_map_create(fVolume->ID(), ID(), Size());
  4330. -   }
  4331.  }
  4332.  
  4333.  
  4334.  Inode::~Inode()
  4335.  {
  4336. -   file_cache_delete(FileCache());
  4337. -   file_map_delete(Map());
  4338. +   TRACE("Inode destructor\n");
  4339.  
  4340. +   if (fCached) {
  4341. +       TRACE("Deleting the file cache and file map\n");
  4342. +       file_cache_delete(FileCache());
  4343. +       file_map_delete(Map());
  4344. +   }
  4345. +
  4346.     if (fAttributesBlock) {
  4347. +       TRACE("Returning the attributes block\n");
  4348.         uint32 block = B_LENDIAN_TO_HOST_INT32(Node().file_access_control);
  4349.         block_cache_put(fVolume->BlockCache(), block);
  4350.     }
  4351.  
  4352. -   if (fNode != NULL) {
  4353. -       uint32 block;
  4354. -       if (fVolume->GetInodeBlock(ID(), block) == B_OK)
  4355. -           block_cache_put(fVolume->BlockCache(), block);
  4356. -   }
  4357. +   TRACE("Inode destructor: Done\n");
  4358.  }
  4359.  
  4360.  
  4361.  status_t
  4362.  Inode::InitCheck()
  4363.  {
  4364. -   return fNode != NULL ? B_OK : B_ERROR;
  4365. +   return fInitStatus;
  4366.  }
  4367.  
  4368.  
  4369. +void
  4370. +Inode::WriteLockInTransaction(Transaction& transaction)
  4371. +{
  4372. +   acquire_vnode(fVolume->FSVolume(), ID());
  4373. +
  4374. +   rw_lock_write_lock(&fLock);
  4375. +
  4376. +   transaction.AddListener(this);
  4377. +}
  4378. +
  4379. +
  4380.  status_t
  4381. +Inode::WriteBack(Transaction& transaction)
  4382. +{
  4383. +   WriteLockInTransaction(transaction);
  4384. +
  4385. +   uint32 inodeBlock;
  4386. +
  4387. +   status_t status = fVolume->GetInodeBlock(fID, inodeBlock);
  4388. +   if (status != B_OK)
  4389. +       return status;
  4390. +
  4391. +   CachedBlock cached(fVolume);
  4392. +   uint8* inodeBlockData = cached.SetToWritable(transaction, inodeBlock);
  4393. +   if (inodeBlockData == NULL)
  4394. +       return B_IO_ERROR;
  4395. +
  4396. +   memcpy(inodeBlockData +
  4397. +           fVolume->InodeBlockIndex(fID) * fVolume->InodeSize(),
  4398. +       (uint8*)&fNode, fNodeSize);
  4399. +
  4400. +   TRACE("Inode::WriteBack() finished\n");
  4401. +
  4402. +   return B_OK;
  4403. +}
  4404. +
  4405. +
  4406. +status_t
  4407. +Inode::UpdateNodeFromDisk()
  4408. +{
  4409. +   uint32 block;
  4410. +
  4411. +   status_t status = fVolume->GetInodeBlock(fID, block);
  4412. +   if (status != B_OK)
  4413. +       return status;
  4414. +
  4415. +   TRACE("inode %Ld at block %lu\n", fID, block);
  4416. +
  4417. +   CachedBlock cached(fVolume);
  4418. +   const uint8* inodeBlock = cached.SetTo(block);
  4419. +
  4420. +   if (inodeBlock == NULL)
  4421. +       return B_IO_ERROR;
  4422. +
  4423. +   TRACE("Inode size: %lu, inode index: %lu\n", fVolume->InodeSize(),
  4424. +       fVolume->InodeBlockIndex(fID));
  4425. +   ext2_inode* inode = (ext2_inode*)(inodeBlock
  4426. +       + fVolume->InodeBlockIndex(fID) * fVolume->InodeSize());
  4427. +
  4428. +   fNodeSize = sizeof(ext2_inode) > fVolume->InodeSize()
  4429. +       ? fVolume->InodeSize() : sizeof(ext2_inode);
  4430. +
  4431. +   TRACE("Attempting to copy inode data from %p to %p, ext2_inode "
  4432. +       "size: %lu\n", inode, &fNode, fNodeSize);
  4433. +
  4434. +   memcpy(&fNode, inode, fNodeSize);
  4435. +
  4436. +   return B_OK;
  4437. +}
  4438. +
  4439. +
  4440. +status_t
  4441.  Inode::CheckPermissions(int accessMode) const
  4442.  {
  4443.     uid_t user = geteuid();
  4444. @@ -95,9 +174,9 @@
  4445.  
  4446.     // shift mode bits, to check directly against accessMode
  4447.     mode_t mode = Mode();
  4448. -   if (user == (uid_t)fNode->UserID())
  4449. +   if (user == (uid_t)fNode.UserID())
  4450.         mode >>= 6;
  4451. -   else if (group == (gid_t)fNode->GroupID())
  4452. +   else if (group == (gid_t)fNode.GroupID())
  4453.         mode >>= 3;
  4454.  
  4455.     if (accessMode & ~(mode & S_IRWXO))
  4456. @@ -114,8 +193,10 @@
  4457.     uint32 perIndirectBlock = perBlock * perBlock;
  4458.     uint32 index = offset >> fVolume->BlockShift();
  4459.  
  4460. -   if (offset >= Size())
  4461. +   if (offset >= Size()) {
  4462. +       TRACE("FindBlock: offset larger than inode size\n");
  4463.         return B_ENTRY_NOT_FOUND;
  4464. +   }
  4465.  
  4466.     // TODO: we could return the size of the sparse range, as this might be more
  4467.     // than just a block
  4468. @@ -186,7 +267,7 @@
  4469.             }
  4470.         }
  4471.     } else {
  4472. -       // outside of the possible data stream
  4473. +       // Outside of the possible data stream
  4474.         dprintf("ext2: block outside datastream!\n");
  4475.         return B_ERROR;
  4476.     }
  4477. @@ -203,7 +284,8 @@
  4478.  
  4479.     // set/check boundaries for pos/length
  4480.     if (pos < 0) {
  4481. -       TRACE("inode %Ld: ReadAt failed(pos %Ld, length %lu)\n", ID(), pos, length);
  4482. +       TRACE("inode %Ld: ReadAt failed(pos %Ld, length %lu)\n", ID(), pos,
  4483. +           length);
  4484.         return B_BAD_VALUE;
  4485.     }
  4486.  
  4487. @@ -218,6 +300,120 @@
  4488.  
  4489.  
  4490.  status_t
  4491. +Inode::WriteAt(Transaction& transaction, off_t pos, uint8* buffer,
  4492. +   size_t* _length)
  4493. +{
  4494. +   ReadLocker readLocker(fLock);
  4495. +
  4496. +   if (pos < 0)
  4497. +       return B_BAD_DATA;
  4498. +
  4499. +   readLocker.Unlock();
  4500. +
  4501. +   transaction.Start(fVolume->GetJournal());
  4502. +       // We will update the modified time anyway
  4503. +
  4504. +   WriteLocker writeLocker(fLock);
  4505. +
  4506. +   size_t length = *_length;
  4507. +   off_t end = pos + length;
  4508. +   off_t oldSize = Size();
  4509. +
  4510. +   if (end > oldSize) {
  4511. +       status_t status = Resize(transaction, end);
  4512. +       if (status != B_OK) {
  4513. +           *_length = 0;
  4514. +           WriteLockInTransaction(transaction);
  4515. +           return status;
  4516. +       }
  4517. +
  4518. +       status = WriteBack(transaction);
  4519. +       if (status != B_OK) {
  4520. +           *_length = 0;
  4521. +           WriteLockInTransaction(transaction);
  4522. +           return status;
  4523. +       }
  4524. +   }
  4525. +
  4526. +   writeLocker.Unlock();
  4527. +
  4528. +   if (oldSize < pos)
  4529. +       FillGapWithZeros(oldSize, pos);
  4530. +
  4531. +   if (length == 0) {
  4532. +       // Probably just changed the file size with the pos parameter
  4533. +       return B_OK;
  4534. +   }
  4535. +
  4536. +   status_t status = file_cache_write(FileCache(), NULL, pos, buffer, _length);
  4537. +
  4538. +   WriteLockInTransaction(transaction);
  4539. +
  4540. +   return status;
  4541. +}
  4542. +
  4543. +
  4544. +status_t
  4545. +Inode::FillGapWithZeros(off_t start, off_t end)
  4546. +{
  4547. +   while (start < end) {
  4548. +       size_t size;
  4549. +
  4550. +       if (end > start + 1024 * 1024 * 1024)
  4551. +           size = 1024 * 1024 * 1024;
  4552. +       else
  4553. +           size = end - start;
  4554. +
  4555. +       status_t status = file_cache_write(FileCache(), NULL, start, NULL,
  4556. +           &size);
  4557. +       if (status != B_OK)
  4558. +           return status;
  4559. +
  4560. +       start += size;
  4561. +   }
  4562. +
  4563. +   return B_OK;
  4564. +}
  4565. +
  4566. +
  4567. +status_t
  4568. +Inode::Resize(Transaction& transaction, off_t size)
  4569. +{
  4570. +   TRACE("Inode::Resize() size: %ld\n", (long)size);
  4571. +   if (size < 0)
  4572. +       return B_BAD_VALUE;
  4573. +
  4574. +   off_t oldSize = Size();
  4575. +
  4576. +   if (size == oldSize)
  4577. +       return B_OK;
  4578. +
  4579. +   status_t status;
  4580. +   if (size > oldSize) {
  4581. +       status = _EnlargeDataStream(transaction, size);
  4582. +       if (status != B_OK) {
  4583. +           // Restore original size
  4584. +           _ShrinkDataStream(transaction, oldSize);
  4585. +       }
  4586. +   } else
  4587. +       status = _ShrinkDataStream(transaction, size);
  4588. +
  4589. +   TRACE("Inode::Resize(): Updating file map and cache\n");
  4590. +
  4591. +   if (status != B_OK)
  4592. +       return status;
  4593. +
  4594. +   file_cache_set_size(FileCache(), size);
  4595. +   file_map_set_size(Map(), size);
  4596. +
  4597. +   TRACE("Inode::Resize(): Writing back inode changes. Size: %ld\n",
  4598. +       (long)Size());
  4599. +
  4600. +   return WriteBack(transaction);
  4601. +}
  4602. +
  4603. +
  4604. +status_t
  4605.  Inode::AttributeBlockReadAt(off_t pos, uint8* buffer, size_t* _length)
  4606.  {
  4607.     TRACE("Inode::%s(%Ld, , %lu)\n", __FUNCTION__, pos, *_length);
  4608. @@ -245,3 +441,816 @@
  4609.     *_length = length;
  4610.     return B_NO_ERROR;
  4611.  }
  4612. +
  4613. +
  4614. +status_t
  4615. +Inode::InitDirectory(Transaction& transaction, Inode* parent)
  4616. +{
  4617. +   uint32 blockSize = fVolume->BlockSize();
  4618. +
  4619. +   status_t status = Resize(transaction, blockSize);
  4620. +   if (status != B_OK)
  4621. +       return status;
  4622. +
  4623. +   uint32 blockNum;
  4624. +   status = FindBlock(0, blockNum);
  4625. +   if (status != B_OK)
  4626. +       return status;
  4627. +
  4628. +   CachedBlock cached(fVolume);
  4629. +   uint8* block = cached.SetToWritable(transaction, blockNum, true);
  4630. +
  4631. +   HTreeRoot* root = (HTreeRoot*)block;
  4632. +   root->dot.inode_id = fID;
  4633. +   root->dot.entry_length = 12;
  4634. +   root->dot.name_length = 1;
  4635. +   root->dot.file_type = EXT2_TYPE_DIRECTORY;
  4636. +   root->dot_entry_name[0] = '.';
  4637. +
  4638. +   root->dotdot.inode_id = parent == NULL ? fID : parent->ID();
  4639. +   root->dotdot.entry_length = blockSize - 12;
  4640. +   root->dotdot.name_length = 2;
  4641. +   root->dotdot.file_type = EXT2_TYPE_DIRECTORY;
  4642. +   root->dotdot_entry_name[0] = '.';
  4643. +   root->dotdot_entry_name[1] = '.';
  4644. +
  4645. +   return B_OK;
  4646. +}
  4647. +
  4648. +
  4649. +/*static*/ status_t
  4650. +Inode::Create(Transaction& transaction, Inode* parent, const char* name,
  4651. +   int32 mode, int openMode, uint32 type, bool* _created, ino_t* _id,
  4652. +   Inode** _inode, fs_vnode_ops* vnodeOps, uint32 publishFlags)
  4653. +{
  4654. +   Volume* volume = transaction.GetVolume();
  4655. +
  4656. +   DirectoryIterator* entries = NULL;
  4657. +   ObjectDeleter<DirectoryIterator> entriesDeleter;
  4658. +
  4659. +   if (parent != NULL) {
  4660. +       parent->WriteLockInTransaction(transaction);
  4661. +
  4662. +       HTree htree(volume, parent);
  4663. +
  4664. +       status_t status = htree.Lookup(name, &entries);
  4665. +       if (status == B_ENTRY_NOT_FOUND) {
  4666. +           panic("We need to add the first node.\n");
  4667. +           return B_ERROR;
  4668. +       }
  4669. +       if (status != B_OK)
  4670. +           return status;
  4671. +       entriesDeleter.SetTo(entries);
  4672. +
  4673. +       ino_t entryID;
  4674. +
  4675. +       status = entries->FindEntry(name, &entryID);
  4676. +       if (status == B_OK) {
  4677. +           // File already exists
  4678. +           if (S_ISDIR(mode) || S_ISLNK(mode) || (openMode & O_EXCL) != 0)
  4679. +               return B_FILE_EXISTS;
  4680. +
  4681. +           Vnode vnode(volume, entryID);
  4682. +           Inode* inode;
  4683. +  
  4684. +           status = vnode.Get(&inode);
  4685. +           if (status != B_OK) {
  4686. +               TRACE("Inode::Create() Failed to get the inode from the "
  4687. +                   "vnode\n");
  4688. +               return B_ENTRY_NOT_FOUND;
  4689. +           }
  4690. +
  4691. +           if (inode->IsDirectory() && (openMode & O_RWMASK) != O_RDONLY)
  4692. +               return B_IS_A_DIRECTORY;
  4693. +           if ((openMode & O_DIRECTORY) != 0 && !inode->IsDirectory())
  4694. +               return B_NOT_A_DIRECTORY;
  4695. +
  4696. +           if (inode->CheckPermissions(open_mode_to_access(openMode)
  4697. +                   | ((openMode & O_TRUNC) != 0 ? W_OK : 0)) != B_OK)
  4698. +               return B_NOT_ALLOWED;
  4699. +
  4700. +           if ((openMode & O_TRUNC) != 0) {
  4701. +               // Truncate requested
  4702. +               inode->WriteLockInTransaction(transaction);
  4703. +
  4704. +               status = inode->Resize(transaction, 0);
  4705. +               if (status != B_OK)
  4706. +                   return status;
  4707. +           }
  4708. +
  4709. +           if (_created != NULL)
  4710. +               *_created = false;
  4711. +           if (_id != NULL)
  4712. +               *_id = inode->ID();
  4713. +           if (_inode != NULL)
  4714. +               *_inode = inode;
  4715. +
  4716. +           if (_id != NULL || _inode != NULL)
  4717. +               vnode.Keep();
  4718. +
  4719. +           return B_OK;
  4720. +       } else if ((mode & S_ATTR_DIR) == 0) {
  4721. +           return B_BAD_VALUE;
  4722. +       } else if ((openMode & O_DIRECTORY) != 0) {
  4723. +           return B_ENTRY_NOT_FOUND;
  4724. +       } else {
  4725. +           // Return to initial position
  4726. +           status_t status = htree.Lookup(name, &entries);
  4727. +               // TODO: We need a LookupForInsertion method, that allocates
  4728. +               // any blocks that are necessary
  4729. +           if (status != B_OK)
  4730. +               return status;
  4731. +           entriesDeleter.SetTo(entries);
  4732. +       }
  4733. +   }
  4734. +
  4735. +   status_t status;
  4736. +   if (parent != NULL) {
  4737. +       status = parent->CheckPermissions(W_OK);
  4738. +       if (status != B_OK)
  4739. +           return status;
  4740. +   }
  4741. +
  4742. +   ino_t id;
  4743. +   status = volume->AllocateInode(transaction, parent, mode, id);
  4744. +   if (status != B_OK)
  4745. +       return status;
  4746. +
  4747. +   if (entries != NULL) {
  4748. +       size_t nameLength = strlen(name);
  4749. +       status = entries->AddEntry(transaction, name, nameLength, id);
  4750. +       if (status != B_OK)
  4751. +           return status;
  4752. +   }
  4753. +
  4754. +   Inode* inode = new(std::nothrow) Inode(volume, id);
  4755. +   if (inode == NULL)
  4756. +       return B_NO_MEMORY;
  4757. +
  4758. +   ext2_inode& node = inode->Node();
  4759. +   node.SetMode(mode);
  4760. +   node.SetUserID(geteuid());
  4761. +   node.SetGroupID(parent != NULL ? parent->Node().GroupID() : getegid());
  4762. +   node.SetSize(0);
  4763. +   node.SetNumLinks(1);
  4764. +   node.SetNumBlocks(volume->BlockSize() / 512);
  4765. +
  4766. +   time_t creationTime = real_time_clock();
  4767. +   node.SetCreationTime(creationTime);
  4768. +   node.SetModificationTime(creationTime);
  4769. +   node.SetFlags(0);
  4770. +
  4771. +   if (inode->IsDirectory()) {
  4772. +       status = inode->InitDirectory(transaction, parent);
  4773. +       if (status != B_OK)
  4774. +           return status;
  4775. +   }
  4776. +
  4777. +   inode->WriteBack(transaction);
  4778. +
  4779. +   return B_OK;
  4780. +}
  4781. +
  4782. +
  4783. +status_t
  4784. +Inode::DisableFileCache()
  4785. +{
  4786. +   TRACE("Inode::DisableFileCache()\n");
  4787. +
  4788. +   if (!fCached)
  4789. +       return B_OK;
  4790. +
  4791. +   file_cache_delete(FileCache());
  4792. +   file_map_delete(Map());
  4793. +
  4794. +   fCached = false;
  4795. +
  4796. +   return B_OK;
  4797. +}
  4798. +
  4799. +
  4800. +void
  4801. +Inode::TransactionDone(bool success)
  4802. +{
  4803. +   if (!success) {
  4804. +       // Revert any changes to the inode
  4805. +       if (UpdateNodeFromDisk() != B_OK)
  4806. +           panic("Failed to reload inode from disk!\n");
  4807. +   }
  4808. +}
  4809. +
  4810. +
  4811. +void
  4812. +Inode::RemovedFromTransaction()
  4813. +{
  4814. +   rw_lock_write_unlock(&fLock);
  4815. +
  4816. +   put_vnode(fVolume->FSVolume(), ID());
  4817. +}
  4818. +
  4819. +
  4820. +status_t
  4821. +Inode::_EnlargeDataStream(Transaction& transaction, off_t size)
  4822. +{
  4823. +   // TODO: Update fNode.num_blocks
  4824. +   if (size < 0)
  4825. +       return B_BAD_DATA;
  4826. +
  4827. +   TRACE("Inode::_EnlargeDataStream()\n");
  4828. +
  4829. +   uint32 blockSize = fVolume->BlockSize();
  4830. +   off_t oldSize = Size();
  4831. +   off_t maxSize = oldSize;
  4832. +   if (maxSize % blockSize != 0)
  4833. +       maxSize += blockSize - maxSize % blockSize;
  4834. +
  4835. +   if (size <= maxSize) {
  4836. +       // No need to allocate more blocks
  4837. +       TRACE("Inode::_EnlargeDataStream(): No need to allocate more blocks\n");
  4838. +       TRACE("Inode::_EnlargeDataStream(): Setting size to %ld\n", (long)size);
  4839. +       fNode.SetSize(size);
  4840. +       TRACE("Inode::_EnlargeDataStream(): Size: %ld\n", (long)Size());
  4841. +       return B_OK;
  4842. +   }
  4843. +
  4844. +   off_t bytesNeeded = size - maxSize;
  4845. +   uint32 blocksNeeded = (bytesNeeded - 1) / blockSize + 1;
  4846. +
  4847. +   if (blocksNeeded > fVolume->NumFreeBlocks()) {
  4848. +       TRACE("Inode::_EnlargeDataStream(): Insufficient free blocks. Needed: "
  4849. +           "%lu, available: %lu\n", blocksNeeded,
  4850. +           (uint32)fVolume->NumFreeBlocks());
  4851. +       return B_DEVICE_FULL;
  4852. +   }
  4853. +
  4854. +   // Discover the last mapped block
  4855. +   uint32 pos = 0;
  4856. +   off_t lastByte = oldSize == 0 ? 0 : oldSize - 1;
  4857. +   if (oldSize != 0) {
  4858. +       status_t status = FindBlock(lastByte, pos);
  4859. +       if (status != B_OK)
  4860. +           return status;
  4861. +   }
  4862. +  
  4863. +   uint32 blockGroup = pos / fVolume->BlocksPerGroup();
  4864. +   pos %= fVolume->BlocksPerGroup();
  4865. +
  4866. +   // Allocate the required blocks (currently no preallocation)
  4867. +   //  if we fail, it is assumed the transaction fails, and everything is
  4868. +   //  reverted
  4869. +   while (blocksNeeded > 0) {
  4870. +       uint32 length;
  4871. +       status_t status = fVolume->AllocateBlocks(transaction, 1, blocksNeeded,
  4872. +           blockGroup, pos, length);
  4873. +       if (status != B_OK)
  4874. +           return status;
  4875. +
  4876. +       blocksNeeded -= length;
  4877. +
  4878. +       uint32 numBlocks = lastByte / fVolume->BlockSize() + 1;
  4879. +       status = _MapBlocksInDataStream(transaction, numBlocks, pos,
  4880. +           length, blockGroup);
  4881. +       if (status != B_OK)
  4882. +           return status;
  4883. +   }
  4884. +
  4885. +   TRACE("Inode::_EnlargeDataStream(): Setting size to %ld\n", (long)size);
  4886. +   fNode.SetSize(size);
  4887. +
  4888. +   return B_OK;
  4889. +}
  4890. +
  4891. +
  4892. +status_t
  4893. +Inode::_ShrinkDataStream(Transaction& transaction, off_t size)
  4894. +{
  4895. +   TRACE("Inode::_ShrinkDataStream()\n");
  4896. +
  4897. +   if (size < 0)
  4898. +       return B_BAD_DATA;
  4899. +
  4900. +   uint32 blockSize = fVolume->BlockSize();
  4901. +   off_t oldSize = Size();
  4902. +   off_t lastByte = oldSize == 0 ? 0 : oldSize - 1;
  4903. +   off_t minSize = (lastByte / blockSize + 1) * blockSize;
  4904. +       // Minimum size that doesn't require freeing blocks
  4905. +
  4906. +   if (size > minSize) {
  4907. +       // No need to allocate more blocks
  4908. +       fNode.SetSize(size);
  4909. +       return B_OK;
  4910. +   }
  4911. +
  4912. +   // Discover the last mapped block
  4913. +   uint32 lastBlock;
  4914. +   if (oldSize != 0) {
  4915. +       status_t status = FindBlock(lastByte, lastBlock);
  4916. +       if (status != B_OK)
  4917. +           return status;
  4918. +   }
  4919. +
  4920. +   uint32 freeStart = minSize + 1;
  4921. +
  4922. +   uint32 indirectsPerBlock = fVolume->BlockSize() / 4; // 32 bits
  4923. +   uint32 indirectsPerBlock2 = indirectsPerBlock * indirectsPerBlock;
  4924. +
  4925. +   uint32 maxDirect = EXT2_DIRECT_BLOCKS;
  4926. +   uint32 maxIndirect = maxDirect + indirectsPerBlock;
  4927. +   uint32 maxDoubleIndirect = maxDirect + indirectsPerBlock + indirectsPerBlock2;
  4928. +
  4929. +   ext2_data_stream* dataStream = &fNode.stream;
  4930. +
  4931. +   status_t status;
  4932. +
  4933. +   if (freeStart < maxDirect) {
  4934. +       uint32 directEnd = lastBlock < maxDirect ? lastBlock + 1 : maxDirect;
  4935. +
  4936. +       status = _FreeDirectBlocks(transaction, (uint32*)&dataStream[freeStart],
  4937. +           (uint32*)&dataStream[directEnd]);
  4938. +       if (status != B_OK)
  4939. +           return status;
  4940. +
  4941. +       if (directEnd != maxDirect) {
  4942. +           fNode.SetSize(size);
  4943. +           return B_OK;
  4944. +       }
  4945. +   }
  4946. +
  4947. +   CachedBlock cached(fVolume);
  4948. +
  4949. +   if (freeStart < maxIndirect && dataStream->Indirect() != 0) {
  4950. +       uint32* indirectBlock = (uint32*)cached.SetToWritable(transaction,
  4951. +           dataStream->Indirect());
  4952. +
  4953. +       if (freeStart >= maxDirect)
  4954. +           indirectBlock += freeStart - maxDirect;
  4955. +      
  4956. +       uint32* indirectBlockEnd = lastBlock < maxIndirect
  4957. +           ? &indirectBlock[lastBlock + 1] : &indirectBlock[maxIndirect];
  4958. +
  4959. +       status = _FreeIndirectBlock(transaction, indirectBlock,
  4960. +           indirectBlockEnd);
  4961. +       if (status != B_OK)
  4962. +           return status;
  4963. +
  4964. +       if (freeStart < maxDirect) {
  4965. +           status = fVolume->FreeBlocks(transaction, dataStream->Indirect(), 1);
  4966. +           if (status != B_OK)
  4967. +               return status;
  4968. +
  4969. +           dataStream->SetIndirect(0);
  4970. +       }
  4971. +   }
  4972. +
  4973. +   if (lastBlock < maxIndirect) {
  4974. +       fNode.SetSize(size);
  4975. +       return B_OK;
  4976. +   }
  4977. +
  4978. +   if (freeStart < maxDoubleIndirect && dataStream->DoubleIndirect() != 0) {
  4979. +       uint32* doubleIndirectBlock = (uint32*)cached.SetToWritable(
  4980. +           transaction, dataStream->DoubleIndirect());
  4981. +
  4982. +       if (freeStart >= maxIndirect)
  4983. +           doubleIndirectBlock += freeStart - maxIndirect;
  4984. +
  4985. +       uint32* doubleIndirectBlockEnd = lastBlock < maxDoubleIndirect
  4986. +           ? &doubleIndirectBlock[lastBlock + 1]
  4987. +           : &doubleIndirectBlock[maxDoubleIndirect];
  4988. +
  4989. +       status = _FreeDoubleIndirectBlock(transaction, doubleIndirectBlock,
  4990. +           doubleIndirectBlockEnd);
  4991. +       if (status != B_OK)
  4992. +           return status;
  4993. +
  4994. +       if (freeStart < maxIndirect) {
  4995. +           status = fVolume->FreeBlocks(transaction,
  4996. +               dataStream->DoubleIndirect(), 1);
  4997. +           if (status != B_OK)
  4998. +               return status;
  4999. +
  5000. +           dataStream->SetDoubleIndirect(0);
  5001. +       }
  5002. +   }
  5003. +
  5004. +   if (lastBlock < maxDoubleIndirect) {
  5005. +       fNode.SetSize(size);
  5006. +       return B_OK;
  5007. +   }
  5008. +
  5009. +   if (dataStream->TripleIndirect() != 0) {
  5010. +       uint32* tripleIndirectBlock = (uint32*)cached.SetToWritable(
  5011. +           transaction, dataStream->TripleIndirect());
  5012. +
  5013. +       if (freeStart >= maxDoubleIndirect)
  5014. +           tripleIndirectBlock += freeStart - maxDoubleIndirect;
  5015. +
  5016. +       uint32* tripleIndirectBlockEnd = &tripleIndirectBlock[lastBlock + 1];
  5017. +
  5018. +       status = _FreeTripleIndirectBlock(transaction, tripleIndirectBlock,
  5019. +           tripleIndirectBlockEnd);
  5020. +       if (status != B_OK)
  5021. +           return status;
  5022. +
  5023. +       if (freeStart < maxDoubleIndirect) {
  5024. +           status = fVolume->FreeBlocks(transaction,
  5025. +               dataStream->TripleIndirect(), 1);
  5026. +           if (status != B_OK)
  5027. +               return status;
  5028. +
  5029. +           dataStream->SetTripleIndirect(0);
  5030. +       }
  5031. +   }
  5032. +
  5033. +   fNode.SetSize(size);
  5034. +   return B_OK;
  5035. +}
  5036. +
  5037. +
  5038. +status_t
  5039. +Inode::_FreeDirectBlocks(Transaction& transaction, uint32* block,
  5040. +   uint32* maxPos)
  5041. +{
  5042. +   uint32 start, value, expected;
  5043. +
  5044. +   value = B_LENDIAN_TO_HOST_INT32(*block);
  5045. +   ++block;
  5046. +
  5047. +   status_t status = B_OK;
  5048. +   while (status == B_OK && block < maxPos) {
  5049. +       start = value;
  5050. +       expected = value;
  5051. +
  5052. +       while (block < maxPos && expected == value) {
  5053. +           value = B_LENDIAN_TO_HOST_INT32(*block);
  5054. +           *block = 0;
  5055. +
  5056. +           expected++;
  5057. +           block++;
  5058. +       }
  5059. +
  5060. +       status = fVolume->FreeBlocks(transaction, start, expected - start);
  5061. +   }
  5062. +
  5063. +   return status;
  5064. +}
  5065. +
  5066. +
  5067. +status_t
  5068. +Inode::_FreeIndirectBlock(Transaction& transaction, uint32* indirectBlock,
  5069. +   uint32* maxIndirectPos)
  5070. +{
  5071. +   // TODO: Ideally, we should group all blocks to be freed to minimize the
  5072. +   // number of calls to the block allocator
  5073. +
  5074. +   CachedBlock cached(fVolume);
  5075. +   uint32 *indirectPos = indirectBlock;
  5076. +   uint32 *directBlock;
  5077. +   uint32 *directMaxPos;
  5078. +
  5079. +   status_t status = B_OK;
  5080. +   while (status == B_OK && indirectPos < maxIndirectPos) {
  5081. +       uint32 block = B_LENDIAN_TO_HOST_INT32(*indirectPos);
  5082. +       *indirectPos = 0;
  5083. +
  5084. +       directBlock = (uint32*)cached.SetToWritable(transaction, block);
  5085. +       if (directBlock == NULL)
  5086. +           return B_IO_ERROR;
  5087. +
  5088. +       directMaxPos = (uint32*)((uint8*)directBlock + fVolume->BlockSize());
  5089. +
  5090. +       status = _FreeDirectBlocks(transaction, directBlock, directMaxPos);
  5091. +   }
  5092. +
  5093. +   if (status == B_OK)
  5094. +       status = _FreeDirectBlocks(transaction, indirectBlock, maxIndirectPos);
  5095. +
  5096. +   return status;
  5097. +}
  5098. +
  5099. +
  5100. +status_t
  5101. +Inode::_FreeDoubleIndirectBlock(Transaction& transaction,
  5102. +   uint32* doubleIndirectBlock, uint32* maxDoubleIndirectPos)
  5103. +{
  5104. +   // TODO: Ideally, we should group all blocks to be freed to minimize the
  5105. +   // number of calls to the block allocator
  5106. +
  5107. +   CachedBlock cached(fVolume);
  5108. +   uint32 *doubleIndirectPos = doubleIndirectBlock;
  5109. +   uint32 *indirectBlock;
  5110. +   uint32 *maxIndirectPos;
  5111. +
  5112. +   status_t status = B_OK;
  5113. +   while (status == B_OK && doubleIndirectPos < maxDoubleIndirectPos) {
  5114. +       uint32 block = B_LENDIAN_TO_HOST_INT32(*doubleIndirectPos);
  5115. +       *doubleIndirectPos = 0;
  5116. +
  5117. +       indirectBlock = (uint32*)cached.SetToWritable(transaction, block);
  5118. +       if (indirectBlock == NULL)
  5119. +           return B_IO_ERROR;
  5120. +
  5121. +       maxIndirectPos = (uint32*)((uint8*)indirectBlock + fVolume->BlockSize());
  5122. +
  5123. +       status = _FreeIndirectBlock(transaction, indirectBlock, maxIndirectPos);
  5124. +   }
  5125. +
  5126. +   if (status == B_OK) {
  5127. +       status = _FreeDirectBlocks(transaction, doubleIndirectBlock,
  5128. +           maxDoubleIndirectPos);
  5129. +   }
  5130. +
  5131. +   return status;
  5132. +}
  5133. +
  5134. +
  5135. +status_t
  5136. +Inode::_FreeTripleIndirectBlock(Transaction& transaction,
  5137. +   uint32* tripleIndirectBlock, uint32* maxTripleIndirectPos)
  5138. +{
  5139. +   // TODO: Ideally, we should group all blocks to be freed to minimize the
  5140. +   // number of calls to the block allocator
  5141. +
  5142. +   CachedBlock cached(fVolume);
  5143. +   uint32 *tripleIndirectPos = tripleIndirectBlock;
  5144. +   uint32 *doubleIndirectBlock;
  5145. +   uint32 *maxDoubleIndirectPos;
  5146. +
  5147. +   status_t status = B_OK;
  5148. +   while (status == B_OK && tripleIndirectPos < maxTripleIndirectPos) {
  5149. +       uint32 block = B_LENDIAN_TO_HOST_INT32(*tripleIndirectPos);
  5150. +       *tripleIndirectPos = 0;
  5151. +
  5152. +       doubleIndirectBlock = (uint32*)cached.SetToWritable(transaction, block);
  5153. +       if (doubleIndirectBlock == NULL)
  5154. +           return B_IO_ERROR;
  5155. +
  5156. +       maxDoubleIndirectPos = (uint32*)((uint8*)doubleIndirectBlock
  5157. +           + fVolume->BlockSize());
  5158. +
  5159. +       status = _FreeDoubleIndirectBlock(transaction, doubleIndirectBlock,
  5160. +           maxDoubleIndirectPos);
  5161. +   }
  5162. +
  5163. +   if (status == B_OK) {
  5164. +       status = _FreeDirectBlocks(transaction, tripleIndirectBlock,
  5165. +           maxTripleIndirectPos);
  5166. +   }
  5167. +
  5168. +   return status;
  5169. +}
  5170. +
  5171. +
  5172. +status_t
  5173. +Inode::_GetBlockFromAllocation(Transaction& transaction, uint32& blocksNeeded,
  5174. +   uint32& allocated, uint32& allocatedPos, uint32& block)
  5175. +{
  5176. +   TRACE("Inode::_GetBlockFromAllocation()\n");
  5177. +
  5178. +   if (allocated > 0) {
  5179. +       if (blocksNeeded == 0)
  5180. +           TRACE("Failed to allocate enough blocks\n");
  5181. +
  5182. +       allocated--;
  5183. +       block = allocatedPos++;
  5184. +
  5185. +       return B_OK;
  5186. +   }
  5187. +
  5188. +   uint32 blockGroup = allocatedPos / fVolume->BlocksPerGroup();
  5189. +   allocatedPos %= fVolume->BlocksPerGroup();
  5190. +
  5191. +   status_t status = fVolume->AllocateBlocks(transaction, 1, blocksNeeded,
  5192. +       blockGroup, allocatedPos, allocated);
  5193. +
  5194. +   allocatedPos += fVolume->BlockSize() * blockGroup;
  5195. +
  5196. +   return status;
  5197. +}
  5198. +
  5199. +
  5200. +void
  5201. +Inode::_MapBlocksInIndirectBlock(uint32* block, uint32* maxPos,
  5202. +   uint32 increment, uint32& length, uint32& rangePos)
  5203. +{
  5204. +   uint32 rangeStart = rangePos;
  5205. +
  5206. +   while (length > 0 && block < maxPos) {
  5207. +       *block = B_HOST_TO_LENDIAN_INT32(rangePos);
  5208. +
  5209. +       rangePos += increment;
  5210. +       ++block;
  5211. +       --length;
  5212. +   }
  5213. +
  5214. +   TRACE("Inode::_MapBlocksInIndirectBlock(): Mapped %lu-%lu\n", rangeStart,
  5215. +       rangePos);
  5216. +}
  5217. +
  5218. +
  5219. +status_t
  5220. +Inode::_MapBlocksInDoubleIndirectBlock(Transaction& transaction,
  5221. +   uint32* doubleIndirectBlock, uint32* maxDoubleIndirectPos,
  5222. +   uint32* indirectBlock, uint32* maxIndirectPos, uint32 increment,
  5223. +   uint32& blocksNeeded, uint32& allocated, uint32& allocatedPos,
  5224. +   uint32& length, uint32& rangePos)
  5225. +{
  5226. +   _MapBlocksInIndirectBlock(indirectBlock, maxIndirectPos, increment, length,
  5227. +       rangePos);
  5228. +   ++doubleIndirectBlock;
  5229. +
  5230. +   CachedBlock cached(fVolume);
  5231. +
  5232. +   while (length > 0 && doubleIndirectBlock < maxDoubleIndirectPos) {
  5233. +       uint32 block = B_LENDIAN_TO_HOST_INT32(*doubleIndirectBlock);
  5234. +
  5235. +       if (block == 0) {
  5236. +           status_t status = _GetBlockFromAllocation(transaction, blocksNeeded,
  5237. +               allocated, allocatedPos, block);
  5238. +           if (status != B_OK)
  5239. +               return status;
  5240. +
  5241. +           *doubleIndirectBlock = B_HOST_TO_LENDIAN_INT32(block);
  5242. +       }
  5243. +
  5244. +       indirectBlock = (uint32*)cached.SetToWritable(transaction, block);
  5245. +       if (indirectBlock == NULL)
  5246. +           return B_IO_ERROR;
  5247. +
  5248. +       maxIndirectPos = (uint32*)((uint8*)indirectBlock
  5249. +           + fVolume->BlockSize());
  5250. +
  5251. +       _MapBlocksInIndirectBlock(indirectBlock, maxIndirectPos, increment,
  5252. +           length, rangePos);
  5253. +       ++doubleIndirectBlock;
  5254. +   }
  5255. +
  5256. +   return B_OK;
  5257. +}
  5258. +
  5259. +
  5260. +status_t
  5261. +Inode::_MapBlocksInDataStream(Transaction& transaction, uint32 mapPos,
  5262. +   uint32 rangePos, uint32 length, uint32 preferredBlockGroup)
  5263. +{
  5264. +   TRACE("Inode::_MapBlocksInDataStream(): map pos: %lu, range pos: %lu, "
  5265. +       "length: %lu, preferred block group: %lu\n", mapPos, rangePos, length,
  5266. +       preferredBlockGroup);
  5267. +   if (length == 0)
  5268. +       return B_OK;
  5269. +
  5270. +   uint32 increment = rangePos == 0 ? 0 : 1;
  5271. +   uint32 indirectsPerBlock = fVolume->BlockSize() / 4; // 32 bits
  5272. +   uint32 indirectsPerBlock2 = indirectsPerBlock * indirectsPerBlock;
  5273. +
  5274. +   uint32 maxDirect = EXT2_DIRECT_BLOCKS - 1;
  5275. +   uint32 maxIndirect = maxDirect + indirectsPerBlock;
  5276. +   uint32 maxDoubleIndirect = maxDirect + indirectsPerBlock + indirectsPerBlock2;
  5277. +
  5278. +   ext2_data_stream* dataStream = &fNode.stream;
  5279. +   _MapBlocksInIndirectBlock(&dataStream->direct[mapPos],
  5280. +       &dataStream->direct[maxDirect], increment, length, rangePos);
  5281. +
  5282. +   if (length == 0)
  5283. +       return B_OK;
  5284. +
  5285. +   // Count the number of blocks that need to be allocated
  5286. +   uint32 blocksNeeded = 0;
  5287. +   uint32 end = mapPos + length;
  5288. +
  5289. +   off_t size = Size();
  5290. +   uint32 numBlocks = size == 0 ? 0 : (size - 1) / fVolume->BlockSize() + 1;
  5291. +
  5292. +   if (end > numBlocks) {
  5293. +       if (dataStream->Indirect() == 0)
  5294. +           blocksNeeded++;
  5295. +       if (end > maxIndirect) {
  5296. +           if (dataStream->DoubleIndirect() == 0)
  5297. +               blocksNeeded += 1 + (end - maxIndirect) / indirectsPerBlock;
  5298. +           else
  5299. +               blocksNeeded += (end - numBlocks) / indirectsPerBlock;
  5300. +       }
  5301. +       if (end > maxDoubleIndirect) {
  5302. +           if (dataStream->TripleIndirect() == 0)
  5303. +               blocksNeeded += 1 + (end - maxDoubleIndirect) / indirectsPerBlock2;
  5304. +           else
  5305. +               blocksNeeded += (end - numBlocks) / indirectsPerBlock2;
  5306. +       }
  5307. +   }
  5308. +
  5309. +   // Prepare for block allocation
  5310. +   if (fVolume->NumFreeBlocks() < blocksNeeded) {
  5311. +       TRACE("Not enough blocks to enlarge data stream\n");
  5312. +       return B_DEVICE_FULL;
  5313. +   }
  5314. +
  5315. +   uint32 allocated = 0;
  5316. +   uint32 allocatedPos = preferredBlockGroup * fVolume->BlockSize();
  5317. +
  5318. +   // Prepare blocks
  5319. +   uint32* indirectBlock = NULL;
  5320. +   uint32* doubleIndirectBlock = NULL;
  5321. +   uint32* tripleIndirectBlock = NULL;
  5322. +
  5323. +   uint32* maxIndirectPos = NULL;
  5324. +   uint32* maxDoubleIndirectPos = NULL;
  5325. +   uint32* maxTripleIndirectPos = NULL;
  5326. +
  5327. +   CachedBlock cachedIndirect(fVolume);
  5328. +   CachedBlock cachedDoubleIndirect(fVolume);
  5329. +   CachedBlock cachedTripleIndirect(fVolume);
  5330. +
  5331. +   uint32 block = dataStream->Indirect();
  5332. +   if (block == 0) {
  5333. +       status_t status = _GetBlockFromAllocation(transaction, blocksNeeded,
  5334. +           allocated, allocatedPos, block);
  5335. +       if (status != B_OK)
  5336. +           return status;
  5337. +
  5338. +       dataStream->SetIndirect(block);
  5339. +   }
  5340. +   indirectBlock = (uint32*)cachedIndirect.SetToWritable(transaction, block);
  5341. +   maxIndirectPos = (uint32*)((uint8*)indirectBlock + fVolume->BlockSize());
  5342. +
  5343. +   if (end > maxIndirect) {
  5344. +       // Reaches double indirect blocks
  5345. +       block = dataStream->DoubleIndirect();
  5346. +       if (block == 0) {
  5347. +           status_t status = _GetBlockFromAllocation(transaction,
  5348. +               blocksNeeded, allocated, allocatedPos, block);
  5349. +           if (status != B_OK)
  5350. +               return status;
  5351. +
  5352. +           dataStream->SetDoubleIndirect(block);
  5353. +       }
  5354. +
  5355. +       doubleIndirectBlock = (uint32*)cachedDoubleIndirect.SetToWritable(
  5356. +           transaction, block);
  5357. +       maxDoubleIndirectPos = (uint32*)((uint8*)doubleIndirectBlock
  5358. +           + fVolume->BlockSize());
  5359. +
  5360. +       if (end > maxDoubleIndirect) {
  5361. +           // Reaches triple indirect blocks
  5362. +           block = dataStream->TripleIndirect();
  5363. +           if (block == 0) {
  5364. +               status_t status = _GetBlockFromAllocation(transaction,
  5365. +                   blocksNeeded, allocated, allocatedPos, block);
  5366. +               if (status != B_OK)
  5367. +                   return status;
  5368. +
  5369. +               dataStream->SetTripleIndirect(block);
  5370. +           }
  5371. +
  5372. +           tripleIndirectBlock = (uint32*)cachedTripleIndirect.SetToWritable(
  5373. +               transaction, block);
  5374. +           maxTripleIndirectPos = (uint32*)((uint8*)tripleIndirectBlock
  5375. +               + fVolume->BlockSize());
  5376. +       }
  5377. +   }
  5378. +
  5379. +   indirectBlock += mapPos - maxDirect;
  5380. +   doubleIndirectBlock += (mapPos - maxIndirect) / indirectsPerBlock;
  5381. +   tripleIndirectBlock += (mapPos - maxDoubleIndirect) / indirectsPerBlock2;
  5382. +
  5383. +   // Perform the mapping
  5384. +   status_t status = _MapBlocksInDoubleIndirectBlock(transaction,
  5385. +       doubleIndirectBlock, maxDoubleIndirectPos, indirectBlock,
  5386. +       maxIndirectPos, increment, blocksNeeded, allocated, allocatedPos,
  5387. +       length, rangePos);
  5388. +   if (status != B_OK)
  5389. +       return status;
  5390. +
  5391. +   ++tripleIndirectBlock;
  5392. +
  5393. +   while (length > 0 && tripleIndirectBlock < maxTripleIndirectPos) {
  5394. +       uint32 block = B_LENDIAN_TO_HOST_INT32(*tripleIndirectBlock);
  5395. +
  5396. +       if (block == 0) {
  5397. +           status = _GetBlockFromAllocation(transaction, blocksNeeded,
  5398. +               allocated, allocatedPos, block);
  5399. +           if (status != B_OK)
  5400. +               return status;
  5401. +
  5402. +           *tripleIndirectBlock = B_HOST_TO_LENDIAN_INT32(block);
  5403. +       }
  5404. +
  5405. +       doubleIndirectBlock = (uint32*)cachedDoubleIndirect.SetToWritable(
  5406. +           transaction, block);
  5407. +       if (doubleIndirectBlock == NULL)
  5408. +           return B_IO_ERROR;
  5409. +
  5410. +       maxDoubleIndirectPos = (uint32*)((uint8*)doubleIndirectBlock
  5411. +           + fVolume->BlockSize());
  5412. +
  5413. +       status_t status = _MapBlocksInDoubleIndirectBlock(transaction,
  5414. +           doubleIndirectBlock, maxDoubleIndirectPos, indirectBlock,
  5415. +           maxIndirectPos, increment, blocksNeeded, allocated, allocatedPos,
  5416. +           length, rangePos);
  5417. +       if (status != B_OK)
  5418. +           return status;
  5419. +
  5420. +       ++tripleIndirectBlock;
  5421. +   }
  5422. +
  5423. +   return B_OK;
  5424. +}
  5425. Index: src/add-ons/kernel/file_systems/ext2/HashRevokeManager.h
  5426. ===================================================================
  5427. --- src/add-ons/kernel/file_systems/ext2/HashRevokeManager.h    (revision 0)
  5428. +++ src/add-ons/kernel/file_systems/ext2/HashRevokeManager.h    (revision 0)
  5429. @@ -0,0 +1,47 @@
  5430. +/*
  5431. + * Copyright 2001-2010, Haiku Inc. All rights reserved.
  5432. + * This file may be used under the terms of the MIT License.
  5433. + *
  5434. + * Authors:
  5435. + *     Janito V. Ferreira Filho
  5436. + */
  5437. +#ifndef HASHREVOKEMANAGER_H
  5438. +#define HASHREVOKEMANAGER_H
  5439. +
  5440. +#include <util/khash.h>
  5441. +
  5442. +#include "RevokeManager.h"
  5443. +
  5444. +
  5445. +struct RevokeElement {
  5446. +   RevokeElement*  next;   // Next in hash
  5447. +   uint32          block;
  5448. +   uint32          commitID;
  5449. +};
  5450. +
  5451. +
  5452. +class HashRevokeManager : public RevokeManager {
  5453. +public:
  5454. +                       HashRevokeManager();
  5455. +   virtual             ~HashRevokeManager();
  5456. +
  5457. +           status_t    Init();
  5458. +
  5459. +   virtual status_t    Insert(uint32 block, uint32 commitID);
  5460. +   virtual status_t    Remove(uint32 block);
  5461. +   virtual bool        Lookup(uint32 block, uint32 commitID);
  5462. +          
  5463. +   static  int         Compare(void* element, const void* key);
  5464. +   static  uint32      Hash(void* element, const void* key, uint32 range);
  5465. +
  5466. +protected:
  5467. +           status_t    _ForceInsert(uint32 block, uint32 commitID);
  5468. +
  5469. +private:
  5470. +           hash_table* fHash;
  5471. +
  5472. +   const   int         kInitialHashSize;
  5473. +};
  5474. +
  5475. +#endif // HASHREVOKEMANAGER_H
  5476. +
  5477.  
  5478. Property changes on: src/add-ons/kernel/file_systems/ext2/HashRevokeManager.h
  5479. ___________________________________________________________________
  5480. Added: svn:executable
  5481.    + *
  5482.  
  5483. Index: src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp
  5484. ===================================================================
  5485. --- src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp   (revision 37957)
  5486. +++ src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp   (working copy)
  5487. @@ -11,12 +11,17 @@
  5488.  #include <AutoDeleter.h>
  5489.  #include <fs_cache.h>
  5490.  #include <fs_info.h>
  5491. +#include <io_requests.h>
  5492. +#include <NodeMonitor.h>
  5493.  
  5494.  #include "AttributeIterator.h"
  5495. +#include "CachedBlock.h"
  5496.  #include "DirectoryIterator.h"
  5497.  #include "ext2.h"
  5498.  #include "HTree.h"
  5499.  #include "Inode.h"
  5500. +#include "Journal.h"
  5501. +#include "Utility.h"
  5502.  
  5503.  
  5504.  //#define TRACE_EXT2
  5505. @@ -35,23 +40,29 @@
  5506.  };
  5507.  
  5508.  
  5509. -/*!    Converts the open mode, the open flags given to bfs_open(), into
  5510. -   access modes, e.g. since O_RDONLY requires read access to the
  5511. -   file, it will be converted to R_OK.
  5512. -*/
  5513. -int
  5514. -open_mode_to_access(int openMode)
  5515. +//!    ext2_io() callback hook
  5516. +static status_t
  5517. +iterative_io_get_vecs_hook(void* cookie, io_request* request, off_t offset,
  5518. +   size_t size, struct file_io_vec* vecs, size_t* _count)
  5519.  {
  5520. -   openMode &= O_RWMASK;
  5521. -   if (openMode == O_RDONLY)
  5522. -       return R_OK;
  5523. -   else if (openMode == O_WRONLY)
  5524. -       return W_OK;
  5525. +   Inode* inode = (Inode*)cookie;
  5526.  
  5527. -   return R_OK | W_OK;
  5528. +   return file_map_translate(inode->Map(), offset, size, vecs, _count,
  5529. +       inode->GetVolume()->BlockSize());
  5530.  }
  5531.  
  5532.  
  5533. +//!    ext2_io() callback hook
  5534. +static status_t
  5535. +iterative_io_finished_hook(void* cookie, io_request* request, status_t status,
  5536. +   bool partialTransfer, size_t bytesTransferred)
  5537. +{
  5538. +   Inode* inode = (Inode*)cookie;
  5539. +   rw_lock_read_unlock(inode->Lock());
  5540. +   return B_OK;
  5541. +}
  5542. +
  5543. +
  5544.  // #pragma mark - Scanning
  5545.  
  5546.  
  5547. @@ -116,6 +127,7 @@
  5548.  
  5549.     status_t status = volume->Mount(device, flags);
  5550.     if (status != B_OK) {
  5551. +       TRACE("Failed mounting the volume. Error: %s\n", strerror(status));
  5552.         delete volume;
  5553.         return status;
  5554.     }
  5555. @@ -148,7 +160,7 @@
  5556.     info->io_size = EXT2_IO_SIZE;
  5557.     info->block_size = volume->BlockSize();
  5558.     info->total_blocks = volume->NumBlocks();
  5559. -   info->free_blocks = volume->FreeBlocks();
  5560. +   info->free_blocks = volume->NumFreeBlocks();
  5561.  
  5562.     // Volume name
  5563.     strlcpy(info->volume_name, volume->Name(), sizeof(info->volume_name));
  5564. @@ -253,6 +265,81 @@
  5565.  
  5566.  
  5567.  static status_t
  5568. +ext2_write_pages(fs_volume* _volume, fs_vnode* _node, void* _cookie,
  5569. +   off_t pos, const iovec* vecs, size_t count, size_t* _numBytes)
  5570. +{
  5571. +   Volume* volume = (Volume*)_volume->private_volume;
  5572. +   Inode* inode = (Inode*)_node->private_node;
  5573. +
  5574. +   if (volume->IsReadOnly())
  5575. +       return B_READ_ONLY_DEVICE;
  5576. +
  5577. +   if (inode->FileCache() == NULL)
  5578. +       return B_BAD_VALUE;
  5579. +
  5580. +   rw_lock_read_lock(inode->Lock());
  5581. +
  5582. +   uint32 vecIndex = 0;
  5583. +   size_t vecOffset = 0;
  5584. +   size_t bytesLeft = *_numBytes;
  5585. +   status_t status;
  5586. +
  5587. +   while (true) {
  5588. +       file_io_vec fileVecs[8];
  5589. +       size_t fileVecCount = 8;
  5590. +
  5591. +       status = file_map_translate(inode->Map(), pos, bytesLeft, fileVecs,
  5592. +           &fileVecCount, 0);
  5593. +       if (status != B_OK && status != B_BUFFER_OVERFLOW)
  5594. +           break;
  5595. +
  5596. +       bool bufferOverflow = status == B_BUFFER_OVERFLOW;
  5597. +
  5598. +       size_t bytes = bytesLeft;
  5599. +       status = write_file_io_vec_pages(volume->Device(), fileVecs,
  5600. +           fileVecCount, vecs, count, &vecIndex, &vecOffset, &bytes);
  5601. +       if (status != B_OK || !bufferOverflow)
  5602. +           break;
  5603. +
  5604. +       pos += bytes;
  5605. +       bytesLeft -= bytes;
  5606. +   }
  5607. +
  5608. +   rw_lock_read_unlock(inode->Lock());
  5609. +
  5610. +   return status;
  5611. +}
  5612. +
  5613. +
  5614. +static status_t
  5615. +ext2_io(fs_volume* _volume, fs_vnode* _node, void* _cookie, io_request* request)
  5616. +{
  5617. +   Volume* volume = (Volume*)_volume->private_volume;
  5618. +   Inode* inode = (Inode*)_node->private_node;
  5619. +
  5620. +#ifndef EXT2_SHELL
  5621. +   if (io_request_is_write(request) && volume->IsReadOnly()) {
  5622. +       notify_io_request(request, B_READ_ONLY_DEVICE);
  5623. +       return B_READ_ONLY_DEVICE;
  5624. +   }
  5625. +#endif
  5626. +
  5627. +   if (inode->FileCache() == NULL) {
  5628. +#ifndef EXT2_SHELL
  5629. +       notify_io_request(request, B_BAD_VALUE);
  5630. +#endif
  5631. +       return B_BAD_VALUE;
  5632. +   }
  5633. +
  5634. +   // We lock the node here and will unlock it in the "finished" hook.
  5635. +   rw_lock_read_lock(inode->Lock());
  5636. +
  5637. +   return do_iterative_fd_io(volume->Device(), request,
  5638. +       iterative_io_get_vecs_hook, iterative_io_finished_hook, inode);
  5639. +}
  5640. +
  5641. +
  5642. +static status_t
  5643.  ext2_get_file_map(fs_volume* _volume, fs_vnode* _node, off_t offset,
  5644.     size_t size, struct file_io_vec* vecs, size_t* _count)
  5645.  {
  5646. @@ -294,7 +381,7 @@
  5647.         if (size <= vecs[index - 1].length || offset >= inode->Size()) {
  5648.             // We're done!
  5649.             *_count = index;
  5650. -           TRACE("ext2_get_file_map for inode %ld\n", inode->ID());
  5651. +           TRACE("ext2_get_file_map for inode %ld\n", (long)inode->ID());
  5652.             return B_OK;
  5653.         }
  5654.     }
  5655. @@ -311,6 +398,8 @@
  5656.  ext2_lookup(fs_volume* _volume, fs_vnode* _directory, const char* name,
  5657.     ino_t* _vnodeID)
  5658.  {
  5659. +   TRACE("ext2_lookup: name address: %p\n", name);
  5660. +   TRACE("ext2_lookup: name: %s\n", name);
  5661.     Volume* volume = (Volume*)_volume->private_volume;
  5662.     Inode* directory = (Inode*)_directory->private_node;
  5663.  
  5664. @@ -328,19 +417,71 @@
  5665.    
  5666.     ObjectDeleter<DirectoryIterator> iteratorDeleter(iterator);
  5667.  
  5668. -   while (true) {
  5669. -       char buffer[B_FILE_NAME_LENGTH];
  5670. -       size_t length = sizeof(buffer);
  5671. -       status = iterator->GetNext(buffer, &length, _vnodeID);
  5672. -       if (status != B_OK)
  5673. -           return status;
  5674. -       TRACE("ext2_lookup() %s\n", buffer);
  5675. +   status = iterator->FindEntry(name, _vnodeID);
  5676. +   if (status != B_OK)
  5677. +       return status;
  5678. +  
  5679. +   return get_vnode(volume->FSVolume(), *_vnodeID, NULL);
  5680. +}
  5681.  
  5682. -       if (!strcmp(buffer, name))
  5683. -           break;
  5684. +void
  5685. +transaction_written(int32 id, int32, void*)
  5686. +{
  5687. +   TRACE("transaction_written: %ld\n", id);
  5688. +}
  5689. +
  5690. +static status_t
  5691. +ext2_ioctl(fs_volume* _volume, fs_vnode* _node, void* _cookie, uint32 cmd,
  5692. +   void* buffer, size_t bufferLength)
  5693. +{
  5694. +   TRACE("ioctl: %lu\n", cmd);
  5695. +
  5696. +   Volume* volume = (Volume*)_volume->private_volume;
  5697. +   switch (cmd) {
  5698. +       case 56742:
  5699. +       {
  5700. +           TRACE("ioctl: Test the block allocator\n");
  5701. +           // Test the block allocator
  5702. +           TRACE("ioctl: Creating transaction\n");
  5703. +           Transaction transaction(volume->GetJournal());
  5704. +           TRACE("ioctl: Creating cached block\n");
  5705. +           CachedBlock cached(volume);
  5706. +           uint32 blocksPerGroup = volume->BlocksPerGroup();
  5707. +           uint32 blockSize  = volume->BlockSize();
  5708. +           uint32 firstBlock = volume->FirstDataBlock();
  5709. +           uint32 start = 0;
  5710. +           uint32 group = 0;
  5711. +           uint32 length;
  5712. +
  5713. +           TRACE("ioctl: blocks per group: %lu, block size: %lu, "
  5714. +               "first block: %lu, start: %lu, group: %lu\n", blocksPerGroup,
  5715. +               blockSize, firstBlock, start, group);
  5716. +
  5717. +           while (volume->AllocateBlocks(transaction, 1, 2048, group, start,
  5718. +                   length) == B_OK) {
  5719. +               TRACE("ioctl: Allocated blocks in group %lu: %lu-%lu\n", group,
  5720. +                   start, start + length);
  5721. +               uint32 blockNum = start + group * blocksPerGroup - firstBlock;
  5722. +
  5723. +               for (uint32 i = 0; i < length; ++i) {
  5724. +                   uint8* block = cached.SetToWritable(transaction, blockNum);
  5725. +                   memset(block, 0, blockSize);
  5726. +                   blockNum++;
  5727. +               }
  5728. +
  5729. +               TRACE("ioctl: Blocks cleared\n");
  5730. +              
  5731. +               transaction.Done();
  5732. +               transaction.Start(volume->GetJournal());
  5733. +           }
  5734. +
  5735. +           TRACE("ioctl: Done\n");
  5736. +
  5737. +           return B_OK;
  5738. +       }
  5739.     }
  5740.  
  5741. -   return get_vnode(volume->FSVolume(), *_vnodeID, NULL);
  5742. +   return B_OK;
  5743.  }
  5744.  
  5745.  
  5746. @@ -371,7 +512,146 @@
  5747.  }
  5748.  
  5749.  
  5750. +status_t
  5751. +ext2_write_stat(fs_volume* _volume, fs_vnode* _node, const struct stat* stat,
  5752. +   uint32 mask)
  5753. +{
  5754. +   TRACE("ext2_write_stat\n");
  5755. +   Volume* volume = (Volume*)_volume->private_volume;
  5756. +
  5757. +   if (volume->IsReadOnly())
  5758. +       return B_READ_ONLY_DEVICE;
  5759. +
  5760. +   Inode* inode = (Inode*)_node->private_node;
  5761. +
  5762. +   status_t status = inode->CheckPermissions(W_OK);
  5763. +   if (status < B_OK)
  5764. +       return status;
  5765. +
  5766. +   TRACE("ext2_write_stat: Starting transaction\n");
  5767. +   Transaction transaction(volume->GetJournal());
  5768. +   TRACE("ext2_write_stat: Finishing transaction\n");
  5769. +   transaction.Done(true);
  5770. +   TRACE("ext2_write_stat: Syncing\n");
  5771. +   volume->GetJournal()->FlushLogAndBlocks();
  5772. +   TRACE("ext2_write_stat: Done\n");
  5773. +   //inode->WriteLockInTransaction(transaction);
  5774. +
  5775. +   if ((mask & B_STAT_SIZE) != 0) {
  5776. +       if (inode->IsDirectory())
  5777. +           return B_IS_A_DIRECTORY;
  5778. +       if (!inode->IsFile())
  5779. +           return B_BAD_VALUE;
  5780. +
  5781. +       TRACE("ext2_write_stat: Old size: %ld, new size: %ld\n", (long)inode->Size(),
  5782. +           (long)stat->st_size);
  5783. +       if (inode->Size() != stat->st_size) {
  5784. +           off_t oldSize = inode->Size();
  5785. +
  5786. +           //status = inode->Resize(transaction, stat->st_size);
  5787. +           // if(status != B_OK)
  5788. +               return status;
  5789. +       }
  5790. +   }
  5791. +
  5792. +   return B_NOT_ALLOWED;
  5793. +}
  5794. +
  5795. +
  5796.  static status_t
  5797. +ext2_create(fs_volume* _volume, fs_vnode* _directory, const char* name,
  5798. +   int openMode, int mode, void** _cookie, ino_t* _vnodeID)
  5799. +{
  5800. +   Volume* volume = (Volume*)_volume->private_volume;
  5801. +   Inode* directory = (Inode*)_directory->private_node;
  5802. +
  5803. +   if (volume->IsReadOnly())
  5804. +       return B_READ_ONLY_DEVICE;
  5805. +
  5806. +   if (!directory->IsDirectory())
  5807. +       return B_BAD_TYPE;
  5808. +
  5809. +   // Allocate cookie
  5810. +   /*file_cookie* cookie = new(std::nothrow) file_cookie;
  5811. +   if (cookie == NULL)
  5812. +       return B_NO_MEMORY;
  5813. +
  5814. +   cookie->open_mode = openMode;
  5815. +   cookie->last_size = 0;
  5816. +   cookie->last_notification = system_time();*/
  5817. +
  5818. +   Transaction transaction(volume->GetJournal());
  5819. +
  5820. +   Inode* inode;
  5821. +   bool created;
  5822. +   status_t status = Inode::Create(transaction, directory, name,
  5823. +       S_FILE | (mode & S_IUMSK), openMode, 0, &created, _vnodeID, &inode);
  5824. +
  5825. +   if (status == B_OK && (openMode & O_NOCACHE) != 0
  5826. +       && inode->IsFileCacheDisabled()) {
  5827. +       status = inode->DisableFileCache();
  5828. +   }
  5829. +
  5830. +   entry_cache_add(volume->ID(), directory->ID(), name, *_vnodeID);
  5831. +
  5832. +   if (status != B_OK) {
  5833. +       entry_cache_remove(volume->ID(), directory->ID(), name);
  5834. +       //delete cookie;
  5835. +
  5836. +       return status;
  5837. +   }
  5838. +
  5839. +   //*_cookie = cookie;
  5840. +
  5841. +   if (created)
  5842. +       notify_entry_created(volume->ID(), directory->ID(), name, *_vnodeID);
  5843. +
  5844. +   return B_OK;
  5845. +}
  5846. +
  5847. +
  5848. +static status_t
  5849. +ext2_unlink(fs_volume* _volume, fs_vnode* _directory, const char* name)
  5850. +{
  5851. +   if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
  5852. +       return B_NOT_ALLOWED;
  5853. +
  5854. +   Volume* volume = (Volume*)_volume->private_volume;
  5855. +   Inode* directory = (Inode*)_directory->private_node;
  5856. +
  5857. +   status_t status = directory->CheckPermissions(W_OK);
  5858. +   if (status != B_OK)
  5859. +       return status;
  5860. +
  5861. +   HTree htree(volume, directory);
  5862. +   DirectoryIterator* directoryIterator;
  5863. +
  5864. +   status = htree.Lookup(name, &directoryIterator);
  5865. +   if (status != B_OK)
  5866. +       return status;
  5867. +
  5868. +   ino_t id;
  5869. +
  5870. +   status = directoryIterator->FindEntry(name, &id);
  5871. +   if (status != B_OK)
  5872. +       return status;
  5873. +
  5874. +   Transaction transaction(volume->GetJournal());
  5875. +
  5876. +   Inode inode(volume, id);
  5877. +   //status = inode.Unlink(transaction);
  5878. +   if (status != B_OK)
  5879. +       return status;
  5880. +
  5881. +   status = directoryIterator->RemoveEntry(transaction);
  5882. +   if (status != B_OK)
  5883. +       return status;
  5884. +
  5885. +   return B_OK;
  5886. +}
  5887. +
  5888. +
  5889. +static status_t
  5890.  ext2_open(fs_volume* _volume, fs_vnode* _node, int openMode, void** _cookie)
  5891.  {
  5892.     Inode* inode = (Inode*)_node->private_node;
  5893. @@ -477,13 +757,17 @@
  5894.  
  5895.     size_t length = bufferSize;
  5896.     ino_t id;
  5897. -   status_t status = iterator->GetNext(dirent->d_name, &length, &id);
  5898. +   status_t status = iterator->Get(dirent->d_name, &length, &id);
  5899.     if (status == B_ENTRY_NOT_FOUND) {
  5900.         *_num = 0;
  5901.         return B_OK;
  5902.     } else if (status != B_OK)
  5903.         return status;
  5904.  
  5905. +   status = iterator->Next();
  5906. +   if (status != B_OK && status != B_ENTRY_NOT_FOUND)
  5907. +       return status;
  5908. +
  5909.     Volume* volume = (Volume*)_volume->private_volume;
  5910.  
  5911.     dirent->d_dev = volume->ID();
  5912. @@ -748,8 +1032,8 @@
  5913.  
  5914.     &ext2_get_file_map,
  5915.  
  5916. +   &ext2_ioctl,
  5917.     NULL,
  5918. -   NULL,
  5919.     NULL,   // fs_select
  5920.     NULL,   // fs_deselect
  5921.     NULL,
  5922. @@ -763,7 +1047,7 @@
  5923.  
  5924.     &ext2_access,
  5925.     &ext2_read_stat,
  5926. -   NULL,
  5927. +   &ext2_write_stat,
  5928.  
  5929.     /* file operations */
  5930.     NULL,
  5931. Index: src/add-ons/kernel/file_systems/ext2/InodeAllocator.h
  5932. ===================================================================
  5933. --- src/add-ons/kernel/file_systems/ext2/InodeAllocator.h   (revision 0)
  5934. +++ src/add-ons/kernel/file_systems/ext2/InodeAllocator.h   (revision 0)
  5935. @@ -0,0 +1,40 @@
  5936. +/*
  5937. + * Copyright 2001-2010, Haiku Inc. All rights reserved.
  5938. + * This file may be used under the terms of the MIT License.
  5939. + *
  5940. + * Authors:
  5941. + *     Janito V. Ferreira Filho
  5942. + */
  5943. +#ifndef INODEALLOCATOR_H
  5944. +#define INODEALLOCATOR_H
  5945. +
  5946. +#include <lock.h>
  5947. +
  5948. +#include "Transaction.h"
  5949. +
  5950. +
  5951. +class Inode;
  5952. +class Volume;
  5953. +
  5954. +
  5955. +class InodeAllocator {
  5956. +public:
  5957. +                       InodeAllocator(Volume* volume);
  5958. +   virtual             ~InodeAllocator();
  5959. +
  5960. +   virtual status_t    New(Transaction& transaction, Inode* parent,
  5961. +                           int32 mode, ino_t& id);
  5962. +
  5963. +private:
  5964. +           status_t    _Allocate(Transaction& transaction,
  5965. +                           uint32 prefferedBlockGroup, ino_t& id);
  5966. +           status_t    _MarkInBitmap(Transaction& transaction,
  5967. +                           uint32 bitmapBlock, uint32 blockGroup,
  5968. +                           uint32 numInodes, ino_t& id);
  5969. +
  5970. +
  5971. +           Volume*     fVolume;
  5972. +           mutex       fLock;
  5973. +};
  5974. +
  5975. +#endif // INODEALLOCATOR_H
  5976.  
  5977. Property changes on: src/add-ons/kernel/file_systems/ext2/InodeAllocator.h
  5978. ___________________________________________________________________
  5979. Added: svn:executable
  5980.    + *
  5981.  
  5982. Index: src/add-ons/kernel/file_systems/ext2/NoJournal.cpp
  5983. ===================================================================
  5984. --- src/add-ons/kernel/file_systems/ext2/NoJournal.cpp  (revision 0)
  5985. +++ src/add-ons/kernel/file_systems/ext2/NoJournal.cpp  (revision 0)
  5986. @@ -0,0 +1,100 @@
  5987. +/*
  5988. + * Copyright 2001-2010, Haiku Inc. All rights reserved.
  5989. + * This file may be used under the terms of the MIT License.
  5990. + *
  5991. + * Authors:
  5992. + *     Janito V. Ferreira Filho
  5993. + */
  5994. +
  5995. +#include "NoJournal.h"
  5996. +
  5997. +#include <string.h>
  5998. +
  5999. +#include <fs_cache.h>
  6000. +
  6001. +
  6002. +//#define TRACE_EXT2
  6003. +#ifdef TRACE_EXT2
  6004. +#  define TRACE(x...) dprintf("\33[34mext2:\33[0m " x)
  6005. +#else
  6006. +#  define TRACE(x...) ;
  6007. +#endif
  6008. +
  6009. +
  6010. +NoJournal::NoJournal(Volume* volume)
  6011. +   :
  6012. +   Journal()
  6013. +{
  6014. +   fFilesystemVolume = volume;
  6015. +   fFilesystemBlockCache = volume->BlockCache();
  6016. +   fJournalVolume = volume;
  6017. +   fHasSubTransaction = false;
  6018. +   fSeparateSubTransactions = false;
  6019. +}
  6020. +
  6021. +
  6022. +NoJournal::~NoJournal()
  6023. +{
  6024. +}
  6025. +
  6026. +
  6027. +status_t
  6028. +NoJournal::InitCheck()
  6029. +{
  6030. +   return B_OK;
  6031. +}
  6032. +
  6033. +
  6034. +status_t
  6035. +NoJournal::Recover()
  6036. +{
  6037. +   return B_OK;
  6038. +}
  6039. +
  6040. +
  6041. +status_t
  6042. +NoJournal::StartLog()
  6043. +{
  6044. +   return B_OK;
  6045. +}
  6046. +
  6047. +
  6048. +status_t
  6049. +NoJournal::Lock(Transaction* owner, bool separateSubTransactions)
  6050. +{
  6051. +   status_t status = block_cache_sync(fFilesystemBlockCache);
  6052. +   TRACE("NoJournal::Lock(): block_cache_sync: %s\n", strerror(status));
  6053. +  
  6054. +   if (status == B_OK)
  6055. +       status = Journal::Lock(owner, separateSubTransactions);
  6056. +  
  6057. +   return status;
  6058. +}
  6059. +
  6060. +
  6061. +status_t
  6062. +NoJournal::Unlock(Transaction* owner, bool success)
  6063. +{
  6064. +   TRACE("NoJournal::Unlock\n");
  6065. +   return Journal::Unlock(owner, success);
  6066. +}
  6067. +
  6068. +
  6069. +status_t
  6070. +NoJournal::_WriteTransactionToLog()
  6071. +{
  6072. +   TRACE("NoJournal::_WriteTransactionToLog(): Ending transaction %ld\n",
  6073. +       fTransactionID);
  6074. +
  6075. +   fTransactionID = cache_end_transaction(fFilesystemBlockCache,
  6076. +       fTransactionID, _TransactionWritten, NULL);
  6077. +  
  6078. +   return B_OK;
  6079. +}
  6080. +
  6081. +
  6082. +/*static*/ void
  6083. +NoJournal::_TransactionWritten(int32 transactionID, int32 event, void* param)
  6084. +{
  6085. +   TRACE("Transaction %ld checkpointed\n", transactionID);
  6086. +}
  6087. Index: src/add-ons/kernel/file_systems/ext2/HTree.cpp
  6088. ===================================================================
  6089. --- src/add-ons/kernel/file_systems/ext2/HTree.cpp  (revision 37957)
  6090. +++ src/add-ons/kernel/file_systems/ext2/HTree.cpp  (working copy)
  6091. @@ -7,6 +7,7 @@
  6092.   */
  6093.  
  6094.  
  6095. +#include "CachedBlock.h"
  6096.  #include "HTree.h"
  6097.  
  6098.  #include <new>
  6099. @@ -17,6 +18,8 @@
  6100.  #include "Volume.h"
  6101.  
  6102.  
  6103. +//#define COLLISION_TEST
  6104. +
  6105.  //#define TRACE_EXT2
  6106.  #ifdef TRACE_EXT2
  6107.  #  define TRACE(x...) dprintf("\33[34mext2:\33[0m " x)
  6108. @@ -75,90 +78,119 @@
  6109.  
  6110.  HTree::~HTree()
  6111.  {
  6112. +   delete fRootEntry;
  6113.  }
  6114.  
  6115.  
  6116.  status_t
  6117. +HTree::PrepareForHash()
  6118. +{
  6119. +   uint32 blockNum;
  6120. +   status_t status = fDirectory->FindBlock(0, blockNum);
  6121. +   if (status != B_OK)
  6122. +       return status;
  6123. +
  6124. +   CachedBlock cached(fDirectory->GetVolume());
  6125. +   const uint8* block = cached.SetTo(blockNum);
  6126. +
  6127. +   HTreeRoot* root = (HTreeRoot*)block;
  6128. +
  6129. +   if (root == NULL)
  6130. +       return B_IO_ERROR;
  6131. +   if (!root->IsValid())
  6132. +       return B_BAD_DATA;
  6133. +
  6134. +   fHashVersion = root->hash_version;
  6135. +
  6136. +   return B_OK;
  6137. +}
  6138. +
  6139. +
  6140. +status_t
  6141.  HTree::Lookup(const char* name, DirectoryIterator** iterator)
  6142.  {
  6143. +   TRACE("HTree::Lookup()\n");
  6144.     if (!fIndexed || (name[0] == '.'
  6145.         && (name[1] == '\0' || (name[1] == '.' && name[2] == '0')))) {
  6146.         // No HTree support or looking for trivial directories
  6147. -       // TODO: Does these directories get hashed?
  6148. -       *iterator = new(std::nothrow) DirectoryIterator(fDirectory);
  6149. -      
  6150. -       if (*iterator == NULL)
  6151. -           return B_NO_MEMORY;
  6152. -       return B_OK;
  6153. +       return _FallbackToLinearIteration(iterator);
  6154.     }
  6155.    
  6156. -   HTreeRoot root;
  6157. -   size_t length = sizeof(root);
  6158. +   uint32 blockNum;
  6159. +   status_t status = fDirectory->FindBlock(0, blockNum);
  6160. +   if (status != B_OK)
  6161. +       return _FallbackToLinearIteration(iterator);
  6162. +
  6163. +   CachedBlock cached(fDirectory->GetVolume());
  6164. +   const uint8* block = cached.SetTo(blockNum);
  6165. +
  6166. +   HTreeRoot* root = (HTreeRoot*)block;
  6167.    
  6168. -   status_t status = fDirectory->ReadAt(0, (uint8*)&root, &length);
  6169. -   if (status < B_OK)
  6170. -       return status;
  6171. +   if (root == NULL || !root->IsValid())
  6172. +       return _FallbackToLinearIteration(iterator);
  6173. +
  6174. +   fHashVersion = root->hash_version;
  6175.    
  6176. -   if (length != sizeof(root) || !root.IsValid()) {
  6177. -       // Fallback to linear search
  6178. -       *iterator = new(std::nothrow) DirectoryIterator(fDirectory);
  6179. -       if (*iterator == NULL)
  6180. -           return B_NO_MEMORY;
  6181. -      
  6182. -       return B_OK;
  6183. -   }
  6184. +   size_t _nameLength = strlen(name);
  6185. +   uint8 nameLength = _nameLength >= 256 ? 255 : (uint8)_nameLength;
  6186. +
  6187. +   uint32 hash = Hash(name, nameLength);
  6188.    
  6189. -   uint32 hash = _Hash(name, root.hash_version);
  6190. -  
  6191. -   off_t start = (off_t)root.root_info_length
  6192. +   off_t start = (off_t)root->root_info_length
  6193.         + 2 * (sizeof(HTreeFakeDirEntry) + 4);
  6194.  
  6195. +   delete fRootEntry;
  6196. +
  6197.     fRootEntry = new(std::nothrow) HTreeEntryIterator(start, fDirectory);
  6198.     if (fRootEntry == NULL)
  6199.         return B_NO_MEMORY;
  6200.    
  6201. -   fRootDeleter.SetTo(fRootEntry);
  6202.     status = fRootEntry->Init();
  6203.     if (status != B_OK)
  6204.         return status;
  6205.    
  6206. -   return fRootEntry->Lookup(hash, (uint32)root.indirection_levels, iterator);
  6207. +   return fRootEntry->Lookup(hash, (uint32)root->indirection_levels, iterator);
  6208.  }
  6209.  
  6210.  
  6211.  uint32
  6212. -HTree::_Hash(const char* name, uint8 version)
  6213. +HTree::Hash(const char* name, uint8 length)
  6214.  {
  6215.     uint32 hash;
  6216.    
  6217. -   switch (version) {
  6218. +#ifndef COLLISION_TEST
  6219. +   switch (fHashVersion) {
  6220.         case HTREE_HASH_LEGACY:
  6221. -           hash = _HashLegacy(name);
  6222. +           hash = _HashLegacy(name, length);
  6223.             break;
  6224.         case HTREE_HASH_HALF_MD4:
  6225. -           hash = _HashHalfMD4(name);
  6226. +           hash = _HashHalfMD4(name, length);
  6227.             break;
  6228.         case HTREE_HASH_TEA:
  6229. -           hash = _HashTEA(name);
  6230. +           hash = _HashTEA(name, length);
  6231.             break;
  6232.         default:
  6233.             panic("Hash verification succeeded but then failed?");
  6234.             hash = 0;
  6235.     };
  6236. +#else
  6237. +   hash = 0;
  6238. +#endif
  6239.  
  6240. -   TRACE("Filename hash: %u\n", hash);
  6241. +   TRACE("HTree::_Hash(): filename hash 0x%lX\n", hash);
  6242.    
  6243.     return hash & ~1;
  6244.  }
  6245.  
  6246.  
  6247.  uint32
  6248. -HTree::_HashLegacy(const char* name)
  6249. +HTree::_HashLegacy(const char* name, uint8 length)
  6250.  {
  6251. +   TRACE("HTree::_HashLegacy()\n");
  6252.     uint32 hash = 0x12a3fe2d;
  6253.     uint32 previous = 0x37abe8f9;
  6254.    
  6255. -   for (; *name != '\0'; ++name) {
  6256. +   for (; length > 0; --length, ++name) {
  6257.         uint32 next = previous + (hash ^ (*name * 7152373));
  6258.        
  6259.         if ((next & 0x80000000) != 0)
  6260. @@ -168,7 +200,7 @@
  6261.         hash = next;
  6262.     }
  6263.    
  6264. -   return hash;
  6265. +   return hash << 1;
  6266.  }
  6267.  
  6268.  
  6269. @@ -230,8 +262,8 @@
  6270.     shifts[2] = 9;
  6271.     shifts[3] = 13;
  6272.  
  6273. -   for (int j = 0; j < 2; ++j) {
  6274. -       for (int i = j; i < 4; i += 2) {
  6275. +   for (int j = 1; j >= 0; --j) {
  6276. +       for (int i = j; i < 8; i += 2) {
  6277.             a += _MD4G(b, c, d) + blocks[i] + 013240474631UL;
  6278.             uint32 shift = shifts[i / 2];
  6279.             a = (a << shift) | (a >> (32 - shift));
  6280. @@ -247,13 +279,13 @@
  6281.  
  6282.     for (int i = 0; i < 4; ++i) {
  6283.         a += _MD4H(b, c, d) + blocks[3 - i] + 015666365641UL;
  6284. -       uint32 shift = shifts[i*2];
  6285. +       uint32 shift = shifts[i * 2 % 4];
  6286.         a = (a << shift) | (a >> (32 - shift));
  6287.        
  6288.         _MD4RotateVars(a, b, c, d);
  6289.        
  6290.         a += _MD4H(b, c, d) + blocks[7 - i] + 015666365641UL;
  6291. -       shift = shifts[i*2 + 1];
  6292. +       shift = shifts[(i * 2 + 1) % 4];
  6293.         a = (a << shift) | (a >> (32 - shift));
  6294.        
  6295.         _MD4RotateVars(a, b, c, d);
  6296. @@ -267,19 +299,21 @@
  6297.  
  6298.  
  6299.  uint32
  6300. -HTree::_HashHalfMD4(const char* name)
  6301. +HTree::_HashHalfMD4(const char* name, uint8 _length)
  6302.  {
  6303. +   TRACE("HTree::_HashHalfMD4()\n");
  6304.     uint32 buffer[4];
  6305. +   int32 length = (uint32)_length;
  6306.  
  6307.     buffer[0] = fHashSeed[0];
  6308.     buffer[1] = fHashSeed[1];
  6309.     buffer[2] = fHashSeed[2];
  6310.     buffer[3] = fHashSeed[3];
  6311.    
  6312. -   for (int length = strlen(name); length > 0; length -= 32) {
  6313. +   for (; length > 0; length -= 32) {
  6314.         uint32 blocks[8];
  6315.        
  6316. -       _PrepareBlocksForHash(name, length, blocks, 8);
  6317. +       _PrepareBlocksForHash(name, (uint32)length, blocks, 8);
  6318.         _HalfMD4Transform(buffer, blocks);
  6319.        
  6320.         name += 32;
  6321. @@ -316,19 +350,21 @@
  6322.  
  6323.  
  6324.  uint32
  6325. -HTree::_HashTEA(const char* name)
  6326. +HTree::_HashTEA(const char* name, uint8 _length)
  6327.  {
  6328. +   TRACE("HTree::_HashTEA()\n");
  6329.     uint32 buffer[4];
  6330. +   int32 length = _length;
  6331.  
  6332.     buffer[0] = fHashSeed[0];
  6333.     buffer[1] = fHashSeed[1];
  6334.     buffer[2] = fHashSeed[2];
  6335.     buffer[3] = fHashSeed[3];
  6336.    
  6337. -   for (int length = strlen(name); length > 0; length -= 16) {
  6338. +   for (; length > 0; length -= 16) {
  6339.         uint32 blocks[4];
  6340.        
  6341. -       _PrepareBlocksForHash(name, length, blocks, 4);
  6342. +       _PrepareBlocksForHash(name, (uint32)length, blocks, 4);
  6343.         TRACE("_HashTEA %lx %lx %lx\n", blocks[0], blocks[1], blocks[2]);
  6344.         _TEATransform(buffer, blocks);
  6345.        
  6346. @@ -340,21 +376,21 @@
  6347.  
  6348.  
  6349.  void
  6350. -HTree::_PrepareBlocksForHash(const char* string, int length, uint32* blocks,
  6351. -   int numBlocks)
  6352. +HTree::_PrepareBlocksForHash(const char* string, uint32 length, uint32* blocks,
  6353. +   uint32 numBlocks)
  6354.  {
  6355.     uint32 padding = (uint32)length;
  6356.     padding = (padding << 8) | padding;
  6357.     padding = (padding << 16) | padding;
  6358.    
  6359. -   int numBytes = numBlocks * 4;
  6360. +   uint32 numBytes = numBlocks * 4;
  6361.     if (length > numBytes)
  6362.         length = numBytes;
  6363.    
  6364. -   int completeIterations = length / 4;
  6365. +   uint32 completeIterations = length / 4;
  6366.    
  6367. -   for (int i = 0; i < completeIterations; ++i) {
  6368. -       uint32 value = 0 | *(string++);
  6369. +   for (uint32 i = 0; i < completeIterations; ++i) {
  6370. +       uint32 value = (padding << 8) | *(string++);
  6371.         value = (value << 8) | *(string++);
  6372.         value = (value << 8) | *(string++);
  6373.         value = (value << 8) | *(string++);
  6374. @@ -362,15 +398,24 @@
  6375.     }
  6376.    
  6377.     if (completeIterations < numBlocks) {
  6378. -       int remainingBytes = length % 4;
  6379. +       uint32 remainingBytes = length % 4;
  6380.        
  6381.         uint32 value = padding;
  6382. -       for (int i = 0; i < remainingBytes; ++i)
  6383. +       for (uint32 i = 0; i < remainingBytes; ++i)
  6384.             value = (value << 8) + *(string++);
  6385.        
  6386.         blocks[completeIterations] = value;
  6387.        
  6388. -       for (int i = completeIterations + 1; i < numBlocks; ++i)
  6389. +       for (uint32 i = completeIterations + 1; i < numBlocks; ++i)
  6390.             blocks[i] = padding;
  6391.     }
  6392.  }
  6393. +
  6394. +
  6395. +/*inline*/ status_t
  6396. +HTree::_FallbackToLinearIteration(DirectoryIterator** iterator)
  6397. +{
  6398. +   *iterator = new(std::nothrow) DirectoryIterator(fDirectory);
  6399. +
  6400. +   return *iterator == NULL ? B_NO_MEMORY : B_OK;
  6401. +}
  6402.  
  6403. Property changes on: src/add-ons/kernel/file_systems/ext2/HTree.cpp
  6404. ___________________________________________________________________
  6405. Added: svn:executable
  6406.    + *
  6407.  
  6408. Index: src/add-ons/kernel/file_systems/ext2/HTreeEntryIterator.h
  6409. ===================================================================
  6410. --- src/add-ons/kernel/file_systems/ext2/HTreeEntryIterator.h   (revision 37957)
  6411. +++ src/add-ons/kernel/file_systems/ext2/HTreeEntryIterator.h   (working copy)
  6412. @@ -14,6 +14,9 @@
  6413.  #include "DirectoryIterator.h"
  6414.  
  6415.  
  6416. +class Volume;
  6417. +
  6418. +
  6419.  class HTreeEntryIterator {
  6420.  public:
  6421.                                 HTreeEntryIterator(off_t offset,
  6422. @@ -26,7 +29,10 @@
  6423.                                     DirectoryIterator** iterator);
  6424.             bool                HasCollision() { return fHasCollision; }
  6425.                        
  6426. -           status_t            GetNext(off_t& offset);
  6427. +           status_t            GetNext(uint32& offset);
  6428. +
  6429. +           status_t            InsertEntry(uint32 hash, uint32 block,
  6430. +                                   bool hasCollision);
  6431.  private:
  6432.                                 HTreeEntryIterator(uint32 block,
  6433.                                     uint32 blockSize, Inode* directory,
  6434. @@ -34,17 +40,20 @@
  6435.                                     bool hasCollision);
  6436.  
  6437.  private:
  6438. +           Inode*              fDirectory;
  6439. +           Volume*             fVolume;
  6440. +           status_t            fInitStatus;
  6441. +
  6442.             bool                fHasCollision;
  6443.             uint16              fLimit, fCount;
  6444. +           uint16              fFirstEntry;
  6445. +           uint16              fCurrentEntry;
  6446.  
  6447.             uint32              fBlockSize;
  6448. -           Inode*              fDirectory;
  6449. -           off_t               fOffset;
  6450. -           off_t               fMaxOffset;
  6451. +           uint32              fBlockNum;
  6452.  
  6453.             HTreeEntryIterator* fParent;
  6454.             HTreeEntryIterator* fChild;
  6455. -           ObjectDeleter<HTreeEntryIterator> fChildDeleter;
  6456.  };
  6457.  
  6458.  #endif // HTREE_ENTRY_ITERATOR_H
  6459. Index: src/add-ons/kernel/file_systems/ext2/Volume.h
  6460. ===================================================================
  6461. --- src/add-ons/kernel/file_systems/ext2/Volume.h   (revision 37957)
  6462. +++ src/add-ons/kernel/file_systems/ext2/Volume.h   (working copy)
  6463. @@ -9,8 +9,12 @@
  6464.  #include <lock.h>
  6465.  
  6466.  #include "ext2.h"
  6467. +#include "BlockAllocator.h"
  6468. +#include "InodeAllocator.h"
  6469. +#include "Transaction.h"
  6470.  
  6471.  class Inode;
  6472. +class Journal;
  6473.  
  6474.  
  6475.  enum volume_flags {
  6476. @@ -18,7 +22,7 @@
  6477.  };
  6478.  
  6479.  
  6480. -class Volume {
  6481. +class Volume : public TransactionListener {
  6482.  public:
  6483.                                 Volume(fs_volume* volume);
  6484.                                 ~Volume();
  6485. @@ -40,31 +44,63 @@
  6486.  
  6487.             uint32              NumInodes() const
  6488.                                     { return fNumInodes; }
  6489. +           uint32              NumGroups() const
  6490. +                                   { return fNumGroups; }
  6491.             off_t               NumBlocks() const
  6492.                                     { return fSuperBlock.NumBlocks(); }
  6493. -           off_t               FreeBlocks() const
  6494. -                                   { return fSuperBlock.FreeBlocks(); }
  6495. +           off_t               NumFreeBlocks() const
  6496. +                                   { return fFreeBlocks; }
  6497. +           uint32              FirstDataBlock() const
  6498. +                                   { return fFirstDataBlock; }
  6499.  
  6500.             uint32              BlockSize() const { return fBlockSize; }
  6501.             uint32              BlockShift() const { return fBlockShift; }
  6502. +           uint32              BlocksPerGroup() const
  6503. +                                   { return fSuperBlock.BlocksPerGroup(); }
  6504.             uint32              InodeSize() const
  6505.                                     { return fSuperBlock.InodeSize(); }
  6506. +           uint32              InodesPerGroup() const
  6507. +                                   { return fSuperBlock.InodesPerGroup(); }
  6508.             ext2_super_block&   SuperBlock() { return fSuperBlock; }
  6509.  
  6510.             status_t            GetInodeBlock(ino_t id, uint32& block);
  6511.             uint32              InodeBlockIndex(ino_t id) const;
  6512.             status_t            GetBlockGroup(int32 index,
  6513.                                     ext2_block_group** _group);
  6514. -          
  6515. +
  6516. +           Journal*            GetJournal() { return fJournal; }
  6517. +
  6518.             bool                IndexedDirectories() const
  6519.                                     { return (fSuperBlock.CompatibleFeatures()
  6520.                                         & EXT2_FEATURE_DIRECTORY_INDEX) != 0; }
  6521. +           uint8               DefaultHashVersion() const
  6522. +                                   { return fSuperBlock.default_hash_version; }
  6523.  
  6524. +           status_t            AllocateInode(Transaction& transaction,
  6525. +                                   Inode* parent, int32 mode, ino_t& id);
  6526. +
  6527. +           status_t            AllocateBlocks(Transaction& transaction,
  6528. +                                   uint32 minimum, uint32 maximum,
  6529. +                                   uint32& blockGroup, uint32& start,
  6530. +                                   uint32& length);
  6531. +           status_t            FreeBlocks(Transaction& transaction,
  6532. +                                   uint32 start, uint32 length);
  6533. +
  6534. +           status_t            LoadSuperBlock();
  6535. +           status_t            WriteSuperBlock(Transaction& transaction);
  6536. +
  6537.             // cache access
  6538.             void*               BlockCache() { return fBlockCache; }
  6539.  
  6540. +           status_t            FlushDevice();
  6541. +           status_t            Sync();
  6542. +
  6543.     static  status_t            Identify(int fd, ext2_super_block* superBlock);
  6544.  
  6545. +           // TransactionListener functions
  6546. +           void                TransactionDone(bool success);
  6547. +           void                RemovedFromTransaction();
  6548. +
  6549.  private:
  6550.     static  uint32              _UnsupportedIncompatibleFeatures(
  6551.                                     ext2_super_block& superBlock);
  6552. @@ -76,12 +112,21 @@
  6553.             int                 fDevice;
  6554.             ext2_super_block    fSuperBlock;
  6555.             char                fName[32];
  6556. +
  6557. +           BlockAllocator      fBlockAllocator;
  6558. +           InodeAllocator      fInodeAllocator;
  6559. +           Journal*            fJournal;
  6560. +           Inode*              fJournalInode;
  6561. +
  6562.             uint32              fFlags;
  6563.             uint32              fBlockSize;
  6564.             uint32              fBlockShift;
  6565.             uint32              fFirstDataBlock;
  6566. +
  6567.             uint32              fNumInodes;
  6568.             uint32              fNumGroups;
  6569. +           uint32              fFreeBlocks;
  6570. +           uint32              fFreeInodes;
  6571.             uint32              fGroupsPerBlock;
  6572.             ext2_block_group**  fGroupBlocks;
  6573.             uint32              fInodesPerBlock;
  6574. Index: src/add-ons/kernel/file_systems/ext2/DirectoryIterator.cpp
  6575. ===================================================================
  6576. --- src/add-ons/kernel/file_systems/ext2/DirectoryIterator.cpp  (revision 37957)
  6577. +++ src/add-ons/kernel/file_systems/ext2/DirectoryIterator.cpp  (working copy)
  6578. @@ -8,6 +8,9 @@
  6579.  
  6580.  #include <string.h>
  6581.  
  6582. +#include <util/VectorSet.h>
  6583. +
  6584. +#include "CachedBlock.h"
  6585.  #include "HTree.h"
  6586.  #include "Inode.h"
  6587.  
  6588. @@ -20,11 +23,36 @@
  6589.  #endif
  6590.  
  6591.  
  6592. -DirectoryIterator::DirectoryIterator(Inode* inode)
  6593. +struct HashedEntry
  6594. +{
  6595. +   uint8*  position;
  6596. +   uint32  hash;
  6597. +
  6598. +   bool    operator<(const HashedEntry& other) const
  6599. +   {
  6600. +       return hash <= other.hash;
  6601. +   }
  6602. +
  6603. +   bool    operator>(const HashedEntry& other) const
  6604. +   {
  6605. +       return hash >= other.hash;
  6606. +   }
  6607. +};
  6608. +
  6609. +
  6610. +DirectoryIterator::DirectoryIterator(Inode* directory, off_t start,
  6611. +   HTreeEntryIterator* parent)
  6612.     :
  6613. -   fInode(inode),
  6614. -   fOffset(0)
  6615. +   fDirectory(directory),
  6616. +   fVolume(directory->GetVolume()),
  6617. +   fBlockSize(fVolume->BlockSize()),
  6618. +   fParent(parent),
  6619. +   fLogicalBlock(start / fBlockSize),
  6620. +   fDisplacement(start % fBlockSize),
  6621. +   fPreviousDisplacement(fPreviousDisplacement)
  6622.  {
  6623. +   fIndexing = parent != NULL;
  6624. +   fInitStatus = fDirectory->FindBlock(start, fPhysicalBlock);
  6625.  }
  6626.  
  6627.  
  6628. @@ -34,60 +62,597 @@
  6629.  
  6630.  
  6631.  status_t
  6632. -DirectoryIterator::GetNext(char* name, size_t* _nameLength, ino_t* _id)
  6633. +DirectoryIterator::InitCheck()
  6634.  {
  6635. -   if (fOffset + sizeof(ext2_dir_entry) >= fInode->Size()) {
  6636. -       TRACE("DirectoryIterator::GetNext() out of entries\n");
  6637. +   return fInitStatus;
  6638. +}
  6639. +
  6640. +
  6641. +status_t
  6642. +DirectoryIterator::Get(char* name, size_t* _nameLength, ino_t* _id)
  6643. +{
  6644. +   if (fLogicalBlock * fBlockSize + fDisplacement >= fDirectory->Size()) {
  6645. +       TRACE("DirectoryIterator::Get() out of entries\n");
  6646.         return B_ENTRY_NOT_FOUND;
  6647.     }
  6648.  
  6649. -   ext2_dir_entry entry;
  6650. +   CachedBlock cached(fVolume);
  6651. +   const uint8* block = cached.SetTo(fPhysicalBlock);
  6652. +   if (block == NULL)
  6653. +       return B_IO_ERROR;
  6654.  
  6655. -   while (true) {
  6656. -       size_t length = ext2_dir_entry::MinimumSize();
  6657. -       status_t status = fInode->ReadAt(fOffset, (uint8*)&entry, &length);
  6658. +   TRACE("DirectoryIterator::Get(): Displacement: %lu\n", fDisplacement);
  6659. +   const ext2_dir_entry* entry = (const ext2_dir_entry*)&block[fDisplacement];
  6660. +
  6661. +   if (entry->NameLength() != 0) {
  6662. +       size_t length = entry->NameLength();
  6663. +
  6664. +       TRACE("block %lu, displacement %lu: entry ino %lu, length %u, "
  6665. +           "name length %lu, type %lu\n", fLogicalBlock, fDisplacement,
  6666. +           entry->InodeID(), entry->Length(), (uint32)length,
  6667. +           (uint32)entry->FileType());
  6668. +
  6669. +       if (*_nameLength > 0) {
  6670. +           if (*_nameLength < length)
  6671. +               length = *_nameLength - 1;
  6672. +
  6673. +           memcpy(name, entry->name, length);
  6674. +           name[length] = '\0';
  6675. +
  6676. +           *_nameLength = length;
  6677. +       }
  6678. +
  6679. +       *_id = entry->InodeID();
  6680. +   } else
  6681. +       *_nameLength = 0;
  6682. +
  6683. +   return B_OK;
  6684. +}
  6685. +
  6686. +
  6687. +status_t
  6688. +DirectoryIterator::Next()
  6689. +{
  6690. +   TRACE("DirectoryIterator::Next()\n");
  6691. +
  6692. +   if (fLogicalBlock * fBlockSize + fDisplacement >= fDirectory->Size()) {
  6693. +       TRACE("DirectoryIterator::Next() out of entries\n");
  6694. +       return B_ENTRY_NOT_FOUND;
  6695. +   }
  6696. +
  6697. +   TRACE("DirectoryIterator::Next(): Creating cached block\n");
  6698. +
  6699. +   CachedBlock cached(fVolume);
  6700. +   ext2_dir_entry* entry;
  6701. +
  6702. +   const uint8* block = cached.SetTo(fPhysicalBlock);
  6703. +   if (block == NULL)
  6704. +       return B_IO_ERROR;
  6705. +
  6706. +   entry = (ext2_dir_entry*)(block + fDisplacement);
  6707. +
  6708. +   do {
  6709. +       TRACE("Checking entry at block %lu, displacement %lu\n", fPhysicalBlock,
  6710. +           fDisplacement);
  6711. +
  6712. +       if (entry->Length() == 0) {
  6713. +           TRACE("empty entry.\n");
  6714. +           return B_ENTRY_NOT_FOUND;
  6715. +       }
  6716. +       if (!entry->IsValid()) {
  6717. +           TRACE("invalid entry.\n");
  6718. +           return B_BAD_DATA;
  6719. +       }
  6720. +
  6721. +       fPreviousDisplacement = fDisplacement;
  6722. +       fDisplacement += entry->Length();
  6723. +
  6724. +       if (fDisplacement == fBlockSize) {
  6725. +           TRACE("Reached end of block\n");
  6726. +
  6727. +           fDisplacement = 0;
  6728. +
  6729. +           status_t status = _NextBlock();
  6730. +           if (status != B_OK)
  6731. +               return status;
  6732. +          
  6733. +           if (fLogicalBlock * fBlockSize + ext2_dir_entry::MinimumSize()
  6734. +                   < fDirectory->Size()) {
  6735. +               status_t status = fDirectory->FindBlock(
  6736. +                   fLogicalBlock * fBlockSize, fPhysicalBlock);
  6737. +               if (status != B_OK)
  6738. +                   return status;
  6739. +           } else {
  6740. +               TRACE("DirectoryIterator::Next() end of directory file\n");
  6741. +               return B_ENTRY_NOT_FOUND;
  6742. +           }
  6743. +
  6744. +           if (entry->Length() == 0) {
  6745. +               block = cached.SetTo(fPhysicalBlock);
  6746. +               if (block == NULL)
  6747. +                   return B_IO_ERROR;
  6748. +           }
  6749. +       } else if (fDisplacement > fBlockSize) {
  6750. +           TRACE("The entry isn't block aligned.\n");
  6751. +           // TODO: Is block alignment obligatory?
  6752. +           return B_BAD_DATA;
  6753. +       }
  6754. +
  6755. +       entry = (ext2_dir_entry*)(block + fDisplacement);
  6756. +
  6757. +       TRACE("DirectoryIterator::Next() skipping entry\n");
  6758. +   } while (entry->Length() == 0);
  6759. +
  6760. +   return B_OK;
  6761. +}
  6762. +
  6763. +
  6764. +status_t
  6765. +DirectoryIterator::Rewind()
  6766. +{
  6767. +   fDisplacement = 0;
  6768. +   fPreviousDisplacement = 0;
  6769. +   fLogicalBlock = 0;
  6770. +
  6771. +   return fDirectory->FindBlock(0, fPhysicalBlock);
  6772. +}
  6773. +
  6774. +
  6775. +status_t
  6776. +DirectoryIterator::AddEntry(Transaction& transaction, const char* name,
  6777. +   size_t _nameLength, ino_t id)
  6778. +{
  6779. +   // TODO: Missing file type
  6780. +   off_t inodeSize = fDirectory->Size();
  6781. +   uint8 nameLength = _nameLength > EXT2_NAME_LENGTH ? EXT2_NAME_LENGTH
  6782. +       : _nameLength;
  6783. +
  6784. +   uint32 lastBlock = (uint32)inodeSize / fBlockSize;
  6785. +   if (inodeSize % fBlockSize != 0)
  6786. +       lastBlock++;
  6787. +
  6788. +   while (fLogicalBlock < lastBlock) {
  6789. +       uint16 pos = 0;
  6790. +       uint16 newLength;
  6791. +
  6792. +       if (_AllocateBestEntryInBlock(nameLength, pos, newLength) == B_OK) {
  6793. +           return _AddEntry(transaction, name, nameLength, id, newLength,
  6794. +               pos);
  6795. +       }
  6796. +      
  6797. +       status_t status = _NextBlock();
  6798. +       if (status == B_ENTRY_NOT_FOUND)
  6799. +           return _SplitIndexedBlock(transaction, name, nameLength, id);
  6800. +       else if(status != B_OK)
  6801. +           return status;
  6802. +
  6803. +       status = fDirectory->FindBlock(fLogicalBlock, fPhysicalBlock);
  6804.         if (status != B_OK)
  6805.             return status;
  6806. -       if (length < ext2_dir_entry::MinimumSize() || entry.Length() == 0)
  6807. -           return B_ENTRY_NOT_FOUND;
  6808. -       if (!entry.IsValid())
  6809. +   }
  6810. +
  6811. +   bool firstSplit = lastBlock == 1 && fVolume->IndexedDirectories();
  6812. +   if (firstSplit) {
  6813. +       // Allocate another block
  6814. +       ++lastBlock;
  6815. +   }
  6816. +
  6817. +   status_t status = fDirectory->Resize(transaction,
  6818. +       (lastBlock + 2) * fBlockSize);
  6819. +   if (status != B_OK)
  6820. +       return status;
  6821. +
  6822. +   if (firstSplit)
  6823. +       return _SplitIndexedBlock(transaction, name, nameLength, id, true);
  6824. +
  6825. +   fLogicalBlock = lastBlock + 1;
  6826. +   status = fDirectory->FindBlock(fLogicalBlock, fPhysicalBlock);
  6827. +   if (status != B_OK)
  6828. +       return status;
  6829. +
  6830. +   return _AddEntry(transaction, name, nameLength, id, fBlockSize, 0, false);
  6831. +}
  6832. +
  6833. +
  6834. +status_t
  6835. +DirectoryIterator::FindEntry(const char* name, ino_t* _id)
  6836. +{
  6837. +   TRACE("DirectoryIterator::FindEntry(): %p %p\n", this, name);
  6838. +   char buffer[EXT2_NAME_LENGTH + 1];
  6839. +   ino_t id;
  6840. +
  6841. +   status_t status = B_OK;
  6842. +   while (status == B_OK) {
  6843. +       size_t nameLength = EXT2_NAME_LENGTH;
  6844. +       status = Get(buffer, &nameLength, &id);
  6845. +       if (status != B_OK)
  6846. +           return status;
  6847. +
  6848. +       if (strcmp(name, buffer) == 0) {
  6849. +           if (_id != NULL)
  6850. +               *_id = id;
  6851. +           return B_OK;
  6852. +       }
  6853. +
  6854. +       status = Next();
  6855. +   }
  6856. +
  6857. +   return status;
  6858. +}
  6859. +
  6860. +
  6861. +status_t
  6862. +DirectoryIterator::RemoveEntry(Transaction& transaction)
  6863. +{
  6864. +   ext2_dir_entry* previousEntry;
  6865. +   ext2_dir_entry* dirEntry;
  6866. +   CachedBlock cached(fVolume);
  6867. +
  6868. +   uint8* block = cached.SetToWritable(transaction, fPhysicalBlock);
  6869. +
  6870. +   if (fDisplacement == 0) {
  6871. +       previousEntry = (ext2_dir_entry*)&block[fDisplacement];
  6872. +
  6873. +       fPreviousDisplacement = fDisplacement;
  6874. +       fDisplacement += previousEntry->Length();
  6875. +
  6876. +       if (fDisplacement == fBlockSize) {
  6877. +           memset(&previousEntry->name_length, 0, fBlockSize - 6);
  6878. +           fDisplacement = 0;
  6879. +           return Next();
  6880. +       } else if (fDisplacement > fBlockSize) {
  6881. +           TRACE("DirectoryIterator::RemoveEntry(): Entry isn't aligned to "
  6882. +               "block entry.");
  6883.             return B_BAD_DATA;
  6884. +       }
  6885.  
  6886. -       if (entry.NameLength() != 0)
  6887. +       dirEntry = (ext2_dir_entry*)&block[fDisplacement];
  6888. +       memcpy(&block[fPreviousDisplacement], &block[fDisplacement],
  6889. +           dirEntry->Length());
  6890. +
  6891. +       previousEntry->SetLength(fDisplacement - fPreviousDisplacement
  6892. +           + previousEntry->Length());
  6893. +
  6894. +       return B_OK;
  6895. +   }
  6896. +
  6897. +   if (fPreviousDisplacement == fDisplacement) {
  6898. +       char buffer[EXT2_NAME_LENGTH + 1];
  6899. +
  6900. +       dirEntry = (ext2_dir_entry*)&block[fDisplacement];
  6901. +
  6902. +       memcpy(buffer, dirEntry->name, (uint32)dirEntry->name_length);
  6903. +
  6904. +       fDisplacement = 0;
  6905. +       status_t status = FindEntry(dirEntry->name);
  6906. +       if (status == B_ENTRY_NOT_FOUND)
  6907. +           return B_BAD_DATA;
  6908. +       if (status != B_OK)
  6909. +           return status;
  6910. +   }
  6911. +
  6912. +   previousEntry = (ext2_dir_entry*)&block[fPreviousDisplacement];
  6913. +   dirEntry = (ext2_dir_entry*)&block[fDisplacement];
  6914. +
  6915. +   previousEntry->SetLength(previousEntry->Length() + dirEntry->Length());
  6916. +
  6917. +   memset(&block[fDisplacement], 0,
  6918. +       fPreviousDisplacement + previousEntry->Length() - fDisplacement);
  6919. +
  6920. +   return B_OK;
  6921. +}
  6922. +
  6923. +
  6924. +status_t
  6925. +DirectoryIterator::_AllocateBestEntryInBlock(uint8 nameLength, uint16& pos,
  6926. +   uint16& newLength)
  6927. +{
  6928. +   CachedBlock cached(fVolume);
  6929. +   const uint8* block = cached.SetTo(fPhysicalBlock);
  6930. +
  6931. +   uint16 requiredLength = nameLength + 8;
  6932. +   if (requiredLength % 4 != 0)
  6933. +       requiredLength += 4 - requiredLength % 4;
  6934. +  
  6935. +   uint16 bestPos = fBlockSize;
  6936. +   uint16 bestLength = fBlockSize;
  6937. +   ext2_dir_entry* dirEntry;
  6938. +  
  6939. +   while (pos < fBlockSize) {
  6940. +       dirEntry = (ext2_dir_entry*)&block[pos];
  6941. +
  6942. +       uint16 realLength = dirEntry->NameLength() + 8;
  6943. +
  6944. +       if (realLength % 4 != 0)
  6945. +           realLength += 4 - realLength % 4;
  6946. +
  6947. +       uint16 emptySpace = dirEntry->Length() - realLength;
  6948. +       if (emptySpace == requiredLength) {
  6949. +           // Found an exact match
  6950. +           newLength = realLength;
  6951. +
  6952. +           return B_OK;
  6953. +       } else if (emptySpace > requiredLength && emptySpace < bestLength) {
  6954. +           bestPos = pos;
  6955. +           bestLength = emptySpace;
  6956. +           newLength = realLength;
  6957. +       }
  6958. +
  6959. +       pos += dirEntry->Length();
  6960. +   }
  6961. +  
  6962. +   if (bestPos != fBlockSize) {
  6963. +       pos = bestPos;
  6964. +   } else
  6965. +       return B_DEVICE_FULL;
  6966. +
  6967. +   return B_OK;
  6968. +}
  6969. +
  6970. +
  6971. +status_t
  6972. +DirectoryIterator::_AddEntry(Transaction& transaction, const char* name,
  6973. +   uint8 nameLength, ino_t id, uint16 newLength, uint16 pos, bool hasPrevious)
  6974. +{
  6975. +   CachedBlock cached(fVolume);
  6976. +
  6977. +   uint8* block = cached.SetToWritable(transaction, fPhysicalBlock);
  6978. +   if (block == NULL)
  6979. +       return B_IO_ERROR;
  6980. +
  6981. +   ext2_dir_entry* dirEntry = (ext2_dir_entry*)&block[pos];
  6982. +
  6983. +   if (hasPrevious) {
  6984. +       uint16 previousLength = dirEntry->Length();
  6985. +       dirEntry->SetLength(newLength);
  6986. +
  6987. +       dirEntry = (ext2_dir_entry*)&block[pos + newLength];
  6988. +       newLength = previousLength - newLength;
  6989. +   }
  6990. +
  6991. +   dirEntry->SetLength(newLength);
  6992. +   dirEntry->name_length = nameLength;
  6993. +   dirEntry->SetInodeID(id);
  6994. +   memcpy(dirEntry->name, name, nameLength);
  6995. +
  6996. +   return B_OK;
  6997. +}
  6998. +
  6999. +
  7000. +status_t
  7001. +DirectoryIterator::_SplitIndexedBlock(Transaction& transaction,
  7002. +   const char* name, uint8 nameLength, ino_t id, bool firstSplit)
  7003. +{
  7004. +   // Block is full, split required
  7005. +   // Allocate a buffer for the entries in the block
  7006. +   uint8* buffer = new(std::nothrow) uint8[fBlockSize];
  7007. +   if (buffer == NULL)
  7008. +       return B_NO_MEMORY;
  7009. +   ArrayDeleter<uint8> bufferDeleter(buffer);
  7010. +
  7011. +   uint32 firstPhysicalBlock = 0;
  7012. +
  7013. +   // Prepare block to hold the first half of the entries and fill the buffer
  7014. +   CachedBlock cachedFirst(fVolume);
  7015. +
  7016. +   if (firstSplit) {
  7017. +       // Save all entries to the buffer
  7018. +       status_t status = fDirectory->FindBlock(0, firstPhysicalBlock);
  7019. +       if (status != B_OK)
  7020. +           return status;
  7021. +
  7022. +       const uint8* srcBlock = cachedFirst.SetTo(firstPhysicalBlock);
  7023. +       if (srcBlock == NULL)
  7024. +           return B_IO_ERROR;
  7025. +
  7026. +       memcpy(buffer, srcBlock, fBlockSize);
  7027. +
  7028. +       status = fDirectory->FindBlock(fBlockSize, fPhysicalBlock);
  7029. +       if (status != B_OK)
  7030. +           return status;
  7031. +   }
  7032. +
  7033. +   uint8* firstBlock = cachedFirst.SetToWritable(transaction, fPhysicalBlock);
  7034. +   if (firstBlock == NULL)
  7035. +       return B_IO_ERROR;
  7036. +
  7037. +   if (!firstSplit) {
  7038. +       // Save all entries to the buffer
  7039. +       memcpy(buffer, firstBlock, fBlockSize);
  7040. +   }
  7041. +
  7042. +   // Prepare last block to hold the second half of the entries
  7043. +   fDisplacement = 0;
  7044. +
  7045. +   status_t status = fDirectory->FindBlock(fDirectory->Size() - 1,
  7046. +       fPhysicalBlock);
  7047. +   if (status != B_OK)
  7048. +       return status;
  7049. +
  7050. +   CachedBlock cachedSecond(fVolume);
  7051. +   uint8* secondBlock = cachedSecond.SetToWritable(transaction,
  7052. +       fPhysicalBlock);
  7053. +   if (secondBlock == NULL)
  7054. +       return B_IO_ERROR;
  7055. +
  7056. +   // Sort entries
  7057. +   VectorSet<HashedEntry> entrySet;
  7058. +
  7059. +   HTree htree(fVolume, fDirectory);
  7060. +   status = htree.PrepareForHash();
  7061. +   if (status != B_OK)
  7062. +       return B_OK;
  7063. +
  7064. +   HashedEntry entry;
  7065. +
  7066. +   uint32 displacement = 0;
  7067. +   ext2_dir_entry* dirEntry = NULL;
  7068. +
  7069. +   while (displacement < fBlockSize) {
  7070. +       entry.position = &firstBlock[displacement];
  7071. +       dirEntry = (ext2_dir_entry*)entry.position;
  7072. +
  7073. +       entry.hash = htree.Hash(dirEntry->name, dirEntry->name_length);
  7074. +
  7075. +       status = entrySet.Insert(entry);
  7076. +       if (status != B_OK)
  7077. +           return status;
  7078. +
  7079. +       displacement += dirEntry->Length();
  7080. +   }
  7081. +
  7082. +   // Prepare the new entry to be included as well
  7083. +   ext2_dir_entry newEntry;
  7084. +
  7085. +   uint16 newLength = (uint16)nameLength;
  7086. +   if (newLength % 4 != 0)
  7087. +       newLength += 4 - newLength % 4;
  7088. +
  7089. +   newEntry.name_length = nameLength;
  7090. +   newEntry.SetLength(newLength);
  7091. +   newEntry.SetInodeID(id);
  7092. +   memcpy(newEntry.name, name, nameLength);
  7093. +
  7094. +   entry.position = (uint8*)&newEntry;
  7095. +   entry.hash = htree.Hash(name, nameLength);
  7096. +
  7097. +   entrySet.Insert(entry);
  7098. +
  7099. +   // Move first half of entries to the first block
  7100. +   VectorSet<HashedEntry>::Iterator iterator = entrySet.Begin();
  7101. +   int32 median = entrySet.Count() / 2;
  7102. +   displacement = 0;
  7103. +
  7104. +   for (int32 i = 0; i < median; ++i) {
  7105. +       dirEntry = (ext2_dir_entry*)(*iterator).position;
  7106. +
  7107. +       memcpy(&firstBlock[displacement], dirEntry, dirEntry->Length());
  7108. +
  7109. +       displacement += dirEntry->Length();
  7110. +       iterator++;
  7111. +   }
  7112. +
  7113. +   // Save the hash to store in the parent
  7114. +   iterator--;
  7115. +   uint32 medianHash = (*iterator).hash;
  7116. +   iterator++;
  7117. +   bool collision = false;
  7118. +
  7119. +   while ((*iterator).hash == medianHash) {
  7120. +       // Keep collisions on the same block
  7121. +       // This isn't the ideal solution, but it is a rare occurance
  7122. +       dirEntry = (ext2_dir_entry*)(*iterator).position;
  7123. +
  7124. +       if (displacement + dirEntry->Length() > fBlockSize) {
  7125. +           // Doesn't fit on the block
  7126. +           --iterator;
  7127. +           dirEntry = (ext2_dir_entry*)(*iterator).position;
  7128. +           ++iterator;
  7129. +          
  7130. +           collision = true;
  7131.             break;
  7132. +       }
  7133.  
  7134. -       fOffset += entry.Length();
  7135. -       TRACE("DirectoryIterator::GetNext() skipping entry\n");
  7136. +       memcpy(&firstBlock[displacement], dirEntry, dirEntry->Length());
  7137. +
  7138. +       displacement += dirEntry->Length();
  7139. +       iterator++;
  7140.     }
  7141.  
  7142. -   TRACE("offset %Ld: entry ino %lu, length %u, name length %u, type %u\n",
  7143. -       fOffset, entry.InodeID(), entry.Length(), entry.NameLength(),
  7144. -       entry.FileType());
  7145. +   // Update last entry in the block
  7146. +   uint16 oldLength = dirEntry->Length();
  7147. +   dirEntry = (ext2_dir_entry*)&firstBlock[displacement - oldLength];
  7148. +   dirEntry->SetLength(fBlockSize - displacement + oldLength);
  7149.  
  7150. -   // read name
  7151. +   // Move the second half of the entries to the second block
  7152. +   VectorSet<HashedEntry>::Iterator end = entrySet.End();
  7153. +   displacement = 0;
  7154.  
  7155. -   size_t length = entry.NameLength();
  7156. -   status_t status = fInode->ReadAt(fOffset + ext2_dir_entry::MinimumSize(),
  7157. -       (uint8*)entry.name, &length);
  7158. -   if (status == B_OK) {
  7159. -       if (*_nameLength < length)
  7160. -           length = *_nameLength - 1;
  7161. -       memcpy(name, entry.name, length);
  7162. -       name[length] = '\0';
  7163. +   while (iterator != end) {
  7164. +       dirEntry = (ext2_dir_entry*)(*iterator).position;
  7165.  
  7166. -       *_id = entry.InodeID();
  7167. -       *_nameLength = length;
  7168. +       memcpy(&secondBlock[displacement], dirEntry, dirEntry->Length());
  7169.  
  7170. -       fOffset += entry.Length();
  7171. +       displacement += dirEntry->Length();
  7172. +       iterator++;
  7173.     }
  7174.  
  7175. -   return status;
  7176. +   // Update last entry in the block
  7177. +   oldLength = dirEntry->Length();
  7178. +   dirEntry = (ext2_dir_entry*)&secondBlock[displacement - oldLength];
  7179. +   dirEntry->SetLength(fBlockSize - displacement + oldLength);
  7180. +
  7181. +   // Update parent
  7182. +   if (firstSplit) {
  7183. +       // Prepare the root node
  7184. +       fDirectory->Node().SetFlag(EXT2_INODE_INDEXED);
  7185. +       HTreeRoot* root;
  7186. +
  7187. +       firstBlock = cachedFirst.SetToWritable(transaction, firstPhysicalBlock);
  7188. +       if (firstBlock == NULL)
  7189. +           return B_IO_ERROR;
  7190. +
  7191. +       status = fDirectory->WriteBack(transaction);
  7192. +       if (status != B_OK)
  7193. +           return status;
  7194. +
  7195. +       root = (HTreeRoot*)firstBlock;
  7196. +
  7197. +       root->hash_version = fVolume->DefaultHashVersion();
  7198. +       root->root_info_length = 4;
  7199. +       root->indirection_levels = 0;
  7200. +       root->flags = 0;
  7201. +
  7202. +       root->count_limit->SetLimit((fBlockSize
  7203. +           - ((uint8*)root->count_limit - firstBlock)) / sizeof(HTreeEntry));
  7204. +       root->count_limit->SetCount(2);
  7205. +
  7206. +       HTreeEntry* htreeEntry = (HTreeEntry*)root->count_limit;
  7207. +       htreeEntry->SetBlock(1);
  7208. +      
  7209. +       ++htreeEntry;
  7210. +       htreeEntry->SetBlock(2);
  7211. +       htreeEntry->SetHash(medianHash);
  7212. +
  7213. +       off_t start = (off_t)root->root_info_length
  7214. +           + 2 * (sizeof(HTreeFakeDirEntry) + 4);
  7215. +       fParent = new(std::nothrow) HTreeEntryIterator(start, fDirectory);
  7216. +       if (fParent == NULL)
  7217. +           return B_NO_MEMORY;
  7218. +      
  7219. +       fParentDeleter.SetTo(fParent);
  7220. +
  7221. +       fLogicalBlock = 1;
  7222. +       status = fDirectory->FindBlock(fLogicalBlock * fBlockSize,
  7223. +           fPhysicalBlock);
  7224. +
  7225. +       fPreviousDisplacement = fDisplacement = 0;
  7226. +
  7227. +       return fParent->Init();
  7228. +   }
  7229. +   else
  7230. +       return fParent->InsertEntry(medianHash, fLogicalBlock, collision);
  7231.  }
  7232.  
  7233.  
  7234.  status_t
  7235. -DirectoryIterator::Rewind()
  7236. +DirectoryIterator::_NextBlock()
  7237.  {
  7238. -   fOffset = 0;
  7239. +   TRACE("DirectoryIterator::_NextBlock()\n");
  7240. +   if (fIndexing) {
  7241. +       TRACE("DirectoryIterator::_NextBlock(): Indexing\n");
  7242. +       if (!fParent->HasCollision()) {
  7243. +           TRACE("IndexedDirectoryIterator::Next(): next block doesn't "
  7244. +               "contain collisions from previous block\n");
  7245. +#ifndef COLLISION_TEST
  7246. +           return B_ENTRY_NOT_FOUND;
  7247. +#endif
  7248. +       }
  7249. +
  7250. +       return fParent->GetNext(fLogicalBlock);
  7251. +   }
  7252. +
  7253. +   ++fLogicalBlock;
  7254. +
  7255.     return B_OK;
  7256.  }
  7257. Index: src/add-ons/kernel/file_systems/ext2/Journal.h
  7258. ===================================================================
  7259. --- src/add-ons/kernel/file_systems/ext2/Journal.h  (revision 0)
  7260. +++ src/add-ons/kernel/file_systems/ext2/Journal.h  (revision 0)
  7261. @@ -0,0 +1,258 @@
  7262. +/*
  7263. + * Copyright 2001-2010, Haiku Inc. All rights reserved.
  7264. + * This file may be used under the terms of the MIT License.
  7265. + *
  7266. + * Authors:
  7267. + *     Janito V. Ferreira Filho
  7268. + */
  7269. +#ifndef JOURNAL_H
  7270. +#define JOURNAL_H
  7271. +
  7272. +
  7273. +#define JOURNAL_MAGIC                              0xc03b3998U
  7274. +
  7275. +#define JOURNAL_DESCRIPTOR_BLOCK                   1
  7276. +#define JOURNAL_COMMIT_BLOCK                       2
  7277. +#define JOURNAL_SUPERBLOCK_V1                      3
  7278. +#define JOURNAL_SUPERBLOCK_V2                      4
  7279. +#define JOURNAL_REVOKE_BLOCK                       5
  7280. +
  7281. +#define JOURNAL_FLAG_ESCAPED                       1
  7282. +#define JOURNAL_FLAG_SAME_UUID                     2
  7283. +#define JOURNAL_FLAG_DELETED                       4
  7284. +#define JOURNAL_FLAG_LAST_TAG                      8
  7285. +
  7286. +#define JOURNAL_FEATURE_INCOMPATIBLE_REVOKE            1
  7287. +
  7288. +#define JOURNAL_KNOWN_READ_ONLY_COMPATIBLE_FEATURES    0
  7289. +#define JOURNAL_KNOWN_INCOMPATIBLE_FEATURES            \
  7290. +   JOURNAL_FEATURE_INCOMPATIBLE_REVOKE
  7291. +
  7292. +
  7293. +#include "Volume.h"
  7294. +
  7295. +#include <AutoDeleter.h>
  7296. +#include <util/DoublyLinkedList.h>
  7297. +
  7298. +#include "Transaction.h"
  7299. +
  7300. +
  7301. +class RevokeManager;
  7302. +
  7303. +
  7304. +struct JournalHeader {
  7305. +   uint32          magic;
  7306. +   uint32          block_type;
  7307. +   uint32          sequence;
  7308. +   char            data[0];
  7309. +
  7310. +   uint32          Magic()         const  
  7311. +       { return B_BENDIAN_TO_HOST_INT32(magic); }
  7312. +   uint32          BlockType()     const  
  7313. +       { return B_BENDIAN_TO_HOST_INT32(block_type); }
  7314. +   uint32          Sequence()      const  
  7315. +       { return B_BENDIAN_TO_HOST_INT32(sequence); }
  7316. +
  7317. +   bool            CheckMagic()    const
  7318. +       { return Magic() == JOURNAL_MAGIC; }
  7319. +
  7320. +   void            IncrementSequence()
  7321. +       { sequence = B_HOST_TO_BENDIAN_INT32(Sequence() + 1); }
  7322. +   void            DecrementSequence()
  7323. +       { sequence = B_HOST_TO_BENDIAN_INT32(Sequence() - 1); }
  7324. +   void            MakeDescriptor(uint32 sequence);
  7325. +   void            MakeCommit(uint32 sequence);
  7326. +} _PACKED;
  7327. +
  7328. +
  7329. +struct JournalBlockTag {
  7330. +   uint32          block_number;
  7331. +   uint32          flags;
  7332. +
  7333. +   uint32          BlockNumber()   const  
  7334. +       { return B_BENDIAN_TO_HOST_INT32(block_number); }
  7335. +   uint32          Flags()         const  
  7336. +       { return B_BENDIAN_TO_HOST_INT32(flags); }
  7337. +
  7338. +   void            SetBlockNumber(uint32 block)
  7339. +       { block_number = B_HOST_TO_BENDIAN_INT32(block); }
  7340. +   void            SetFlags(uint32 new_flags)
  7341. +       { flags = B_HOST_TO_BENDIAN_INT32(new_flags); }
  7342. +   void            SetLastTagFlag()
  7343. +       { flags |= B_HOST_TO_BENDIAN_INT32(JOURNAL_FLAG_LAST_TAG); }
  7344. +   void            SetEscapedFlag()
  7345. +       { flags |= B_HOST_TO_BENDIAN_INT32(JOURNAL_FLAG_ESCAPED); }
  7346. +} _PACKED;
  7347. +
  7348. +
  7349. +struct JournalRevokeHeader {
  7350. +   JournalHeader   header;
  7351. +   uint32          num_bytes;
  7352. +
  7353. +   uint32          revoke_blocks[0];
  7354. +
  7355. +   uint32          NumBytes()      const  
  7356. +       { return B_BENDIAN_TO_HOST_INT32(num_bytes); }
  7357. +   uint32          RevokeBlock(int offset) const  
  7358. +       { return B_BENDIAN_TO_HOST_INT32(revoke_blocks[offset]); }
  7359. +} _PACKED;
  7360. +
  7361. +
  7362. +struct JournalSuperBlock {
  7363. +   JournalHeader   header;
  7364. +  
  7365. +   uint32          block_size;
  7366. +   uint32          num_blocks;
  7367. +   uint32          first_log_block;
  7368. +
  7369. +   uint32          first_commit_id;
  7370. +   uint32          log_start;
  7371. +
  7372. +   uint32          error;
  7373. +
  7374. +   uint32          compatible_features;
  7375. +   uint32          incompatible_features;
  7376. +   uint32          read_only_compatible_features;
  7377. +
  7378. +   uint8           uuid[16];
  7379. +
  7380. +   uint32          num_users;
  7381. +   uint32          dynamic_superblock;
  7382. +
  7383. +   uint32          max_transaction_blocks;
  7384. +   uint32          max_transaction_data;
  7385. +
  7386. +   uint32          padding[44];
  7387. +
  7388. +   uint8           user_ids[16*48];
  7389. +
  7390. +   uint32          BlockSize() const
  7391. +       { return B_BENDIAN_TO_HOST_INT32(block_size); }
  7392. +   uint32          NumBlocks() const
  7393. +       { return B_BENDIAN_TO_HOST_INT32(num_blocks); }
  7394. +   uint32          FirstLogBlock() const
  7395. +       { return B_BENDIAN_TO_HOST_INT32(first_log_block); }
  7396. +   uint32          FirstCommitID() const
  7397. +       { return B_BENDIAN_TO_HOST_INT32(first_commit_id); }
  7398. +   uint32          LogStart() const
  7399. +       { return B_BENDIAN_TO_HOST_INT32(log_start); }
  7400. +   uint32          IncompatibleFeatures() const
  7401. +       { return B_BENDIAN_TO_HOST_INT32(incompatible_features); }
  7402. +   uint32          ReadOnlyCompatibleFeatures() const
  7403. +       { return B_BENDIAN_TO_HOST_INT32(read_only_compatible_features); }
  7404. +   uint32          MaxTransactionBlocks() const
  7405. +       { return B_BENDIAN_TO_HOST_INT32(max_transaction_blocks); }
  7406. +   uint32          MaxTransactionData() const
  7407. +       { return B_BENDIAN_TO_HOST_INT32(max_transaction_data); }
  7408. +
  7409. +   void            SetLogStart(uint32 logStart)
  7410. +       { log_start = B_HOST_TO_BENDIAN_INT32(logStart); }
  7411. +   void            SetFirstCommitID(uint32 firstCommitID)
  7412. +       { first_commit_id = B_HOST_TO_BENDIAN_INT32(firstCommitID); }
  7413. +} _PACKED;
  7414. +
  7415. +class LogEntry;
  7416. +class Transaction;
  7417. +typedef DoublyLinkedList<LogEntry> LogEntryList;
  7418. +
  7419. +
  7420. +class Journal {
  7421. +public:
  7422. +                               Journal(Volume *fsVolume, Volume *jVolume);
  7423. +   virtual                     ~Journal();
  7424. +
  7425. +   virtual status_t            InitCheck();
  7426. +   virtual status_t            Deinit();
  7427. +
  7428. +   virtual status_t            Recover();
  7429. +   virtual status_t            StartLog();
  7430. +           status_t            RestartLog();
  7431. +
  7432. +   virtual status_t            Lock(Transaction* owner,
  7433. +                                   bool separateSubTransactions);
  7434. +   virtual status_t            Unlock(Transaction* owner, bool success);
  7435. +
  7436. +   virtual status_t            MapBlock(uint32 logical, uint32& physical);
  7437. +   inline  uint32              FreeLogBlocks() const;
  7438. +          
  7439. +           status_t            FlushLogAndBlocks();
  7440. +
  7441. +           int32               TransactionID() const;
  7442. +
  7443. +           Volume*             GetFilesystemVolume()
  7444. +               { return fFilesystemVolume; }
  7445. +protected:
  7446. +                               Journal();
  7447. +  
  7448. +           status_t            _WritePartialTransactionToLog(
  7449. +                                   JournalHeader* descriptorBlock,
  7450. +                                   bool detached, uint8** escapedBlock,
  7451. +                                   uint32& logBlock, off_t& blockNumber,
  7452. +                                   long& cookie,
  7453. +                                   ArrayDeleter<uint8>& escapedDataDeleter,
  7454. +                                   uint32& blockCount, bool& finished);
  7455. +   virtual status_t            _WriteTransactionToLog();
  7456. +
  7457. +           status_t            _SaveSuperBlock();
  7458. +           status_t            _LoadSuperBlock();
  7459. +
  7460. +
  7461. +           Volume*             fJournalVolume;
  7462. +           void*               fJournalBlockCache;
  7463. +           Volume*             fFilesystemVolume;
  7464. +           void*               fFilesystemBlockCache;
  7465. +
  7466. +           recursive_lock      fLock;
  7467. +           Transaction*        fOwner;
  7468. +
  7469. +           RevokeManager*      fRevokeManager;
  7470. +
  7471. +           status_t            fInitStatus;
  7472. +           uint32              fBlockSize;
  7473. +           uint32              fFirstCommitID;
  7474. +           uint32              fFirstCacheCommitID;
  7475. +           uint32              fFirstLogBlock;
  7476. +           uint32              fLogSize;
  7477. +           uint32              fVersion;
  7478. +          
  7479. +           uint32              fLogStart;
  7480. +           uint32              fLogEnd;
  7481. +           uint32              fFreeBlocks;
  7482. +           uint32              fMaxTransactionSize;
  7483. +
  7484. +           uint32              fCurrentCommitID;
  7485. +           //uint32                fNextCommitID;
  7486. +
  7487. +           LogEntryList        fLogEntries;
  7488. +           mutex               fLogEntriesLock;
  7489. +           bool                fHasSubTransaction;
  7490. +           bool                fSeparateSubTransactions;
  7491. +           int32               fUnwrittenTransactions;
  7492. +           int32               fTransactionID;
  7493. +
  7494. +private:
  7495. +           status_t            _CheckFeatures(JournalSuperBlock* superblock);
  7496. +
  7497. +           uint32              _CountTags(JournalHeader *descriptorBlock);
  7498. +           status_t            _RecoverPassScan(uint32& lastCommitID);
  7499. +           status_t            _RecoverPassRevoke(uint32 lastCommitID);
  7500. +           status_t            _RecoverPassReplay(uint32 lastCommitID);
  7501. +
  7502. +           status_t            _FlushLog(bool canWait, bool flushBlocks);
  7503. +
  7504. +   inline  uint32              _WrapAroundLog(uint32 block);
  7505. +          
  7506. +           size_t              _CurrentTransactionSize() const;
  7507. +           size_t              _FullTransactionSize() const;
  7508. +           size_t              _MainTransactionSize() const;
  7509. +          
  7510. +   virtual status_t            _TransactionDone(bool success);
  7511. +
  7512. +   static  void                _TransactionWritten(int32 transactionID,
  7513. +                                   int32 event, void* _logEntry);
  7514. +   static  void                _TransactionIdle(int32 transactionID,
  7515. +                                   int32 event, void* _journal);
  7516. +};
  7517. +
  7518. +#endif // JOURNAL_H
  7519. +
  7520.  
  7521. Property changes on: src/add-ons/kernel/file_systems/ext2/Journal.h
  7522. ___________________________________________________________________
  7523. Added: svn:executable
  7524.    + *
  7525.  
  7526. Index: src/add-ons/kernel/file_systems/ext2/IndexedDirectoryIterator.h
  7527. ===================================================================
  7528. --- src/add-ons/kernel/file_systems/ext2/IndexedDirectoryIterator.h (revision 37957)
  7529. +++ src/add-ons/kernel/file_systems/ext2/IndexedDirectoryIterator.h (working copy)
  7530. @@ -1,36 +0,0 @@
  7531. -/*
  7532. - * Copyright 2010, Haiku Inc. All rights reserved.
  7533. - * This file may be used under the terms of the MIT License.
  7534. - *
  7535. - * Authors:
  7536. - *     Janito V. Ferreira Filho
  7537. - */
  7538. -#ifndef INDEXED_DIRECTORY_ITERATOR_H
  7539. -#define INDEXED_DIRECTORY_ITERATOR_H
  7540. -
  7541. -
  7542. -#include "DirectoryIterator.h"
  7543. -
  7544. -
  7545. -class HTreeEntryIterator;
  7546. -
  7547. -class IndexedDirectoryIterator : public DirectoryIterator {
  7548. -public:
  7549. -                               IndexedDirectoryIterator(off_t start,
  7550. -                                   uint32 blockSize, Inode* directory,
  7551. -                                   HTreeEntryIterator* parent);
  7552. -   virtual                     ~IndexedDirectoryIterator();
  7553. -  
  7554. -           status_t            GetNext(char* name, size_t* nameLength,
  7555. -                                   ino_t* id);
  7556. -          
  7557. -           status_t            Rewind();
  7558. -private:
  7559. -           bool                fIndexing;
  7560. -           HTreeEntryIterator* fParent;
  7561. -           off_t               fMaxOffset;
  7562. -           uint32              fBlockSize;
  7563. -           uint32              fMaxAttempts;
  7564. -};
  7565. -
  7566. -#endif // INDEXED_DIRECTORY_ITERATOR_H
  7567. Index: src/add-ons/kernel/file_systems/ext2/Transaction.cpp
  7568. ===================================================================
  7569. --- src/add-ons/kernel/file_systems/ext2/Transaction.cpp    (revision 0)
  7570. +++ src/add-ons/kernel/file_systems/ext2/Transaction.cpp    (revision 0)
  7571. @@ -0,0 +1,217 @@
  7572. +/*
  7573. + * Copyright 2001-2010, Haiku Inc. All rights reserved.
  7574. + * This file may be used under the terms of the MIT License.
  7575. + *
  7576. + * Authors:
  7577. + *     Janito V. Ferreira Filho
  7578. + */
  7579. +
  7580. +#include "Transaction.h"
  7581. +
  7582. +#include <string.h>
  7583. +
  7584. +#include <fs_cache.h>
  7585. +
  7586. +#include "Journal.h"
  7587. +
  7588. +
  7589. +//#define TRACE_EXT2
  7590. +#ifdef TRACE_EXT2
  7591. +#  define TRACE(x...) dprintf("\33[34mext2:\33[0m " x)
  7592. +#else
  7593. +#  define TRACE(x...) ;
  7594. +#endif
  7595. +
  7596. +
  7597. +TransactionListener::TransactionListener()
  7598. +{
  7599. +}
  7600. +
  7601. +
  7602. +TransactionListener::~TransactionListener()
  7603. +{
  7604. +}
  7605. +
  7606. +
  7607. +Transaction::Transaction()
  7608. +   :
  7609. +   fJournal(NULL),
  7610. +   fParent(NULL)
  7611. +{
  7612. +}
  7613. +
  7614. +
  7615. +Transaction::Transaction(Journal* journal)
  7616. +   :
  7617. +   fJournal(NULL),
  7618. +   fParent(NULL)
  7619. +{
  7620. +   Start(journal);
  7621. +}
  7622. +
  7623. +
  7624. +Transaction::~Transaction()
  7625. +{
  7626. +   if (IsStarted())
  7627. +       fJournal->Unlock(this, false);
  7628. +}
  7629. +
  7630. +status_t
  7631. +Transaction::Start(Journal* journal)
  7632. +{
  7633. +   if (IsStarted())
  7634. +       return B_OK;
  7635. +
  7636. +   fJournal = journal;
  7637. +   if (fJournal == NULL)
  7638. +       return B_ERROR;
  7639. +  
  7640. +   status_t status = fJournal->Lock(this, false);
  7641. +   if (status != B_OK)
  7642. +       fJournal = NULL;
  7643. +
  7644. +   return status;
  7645. +}
  7646. +
  7647. +
  7648. +status_t
  7649. +Transaction::Done(bool success)
  7650. +{
  7651. +   if (!IsStarted())
  7652. +       return B_OK;
  7653. +
  7654. +   status_t status = fJournal->Unlock(this, success);
  7655. +  
  7656. +   if (status == B_OK)
  7657. +       fJournal = NULL;
  7658. +
  7659. +   return status;
  7660. +}
  7661. +
  7662. +
  7663. +int32
  7664. +Transaction::ID() const
  7665. +{
  7666. +   if (!IsStarted())
  7667. +       return -1;
  7668. +
  7669. +   return fJournal->TransactionID();
  7670. +}
  7671. +
  7672. +
  7673. +bool
  7674. +Transaction::IsStarted() const
  7675. +{
  7676. +   return fJournal != NULL;
  7677. +}
  7678. +
  7679. +
  7680. +bool
  7681. +Transaction::HasParent() const
  7682. +{
  7683. +   return fParent != NULL;
  7684. +}
  7685. +
  7686. +
  7687. +status_t
  7688. +Transaction::WriteBlocks(off_t blockNumber, const uint8* buffer,
  7689. +   size_t numBlocks)
  7690. +{
  7691. +   if (!IsStarted())
  7692. +       return B_NO_INIT;
  7693. +
  7694. +   void* cache = GetVolume()->BlockCache();
  7695. +   size_t blockSize = GetVolume()->BlockSize();
  7696. +
  7697. +   for (size_t i = 0; i < numBlocks; ++i) {
  7698. +       void* block = block_cache_get_empty(cache, blockNumber + i, ID());
  7699. +       if (block == NULL)
  7700. +           return B_ERROR;
  7701. +      
  7702. +       memcpy(block, buffer, blockSize);
  7703. +       buffer += blockSize;
  7704. +
  7705. +       block_cache_put(cache, blockNumber + i);
  7706. +   }
  7707. +
  7708. +   return B_OK;
  7709. +}
  7710. +
  7711. +
  7712. +void
  7713. +Transaction::Split()
  7714. +{
  7715. +   cache_start_sub_transaction(fJournal->GetFilesystemVolume()->BlockCache(),
  7716. +       ID());
  7717. +}
  7718. +
  7719. +
  7720. +Volume*
  7721. +Transaction::GetVolume() const
  7722. +{
  7723. +   if (!IsStarted())
  7724. +       return NULL;
  7725. +
  7726. +   return fJournal->GetFilesystemVolume();
  7727. +}
  7728. +
  7729. +
  7730. +void
  7731. +Transaction::AddListener(TransactionListener* listener)
  7732. +{
  7733. +   if (!IsStarted())
  7734. +       panic("Transaction is not running!");
  7735. +
  7736. +   fListeners.Add(listener);
  7737. +}
  7738. +
  7739. +
  7740. +void
  7741. +Transaction::RemoveListener(TransactionListener* listener)
  7742. +{
  7743. +   if (!IsStarted())
  7744. +       panic("Transaction is not running!");
  7745. +
  7746. +   fListeners.Remove(listener);
  7747. +   listener->RemovedFromTransaction();
  7748. +}
  7749. +
  7750. +
  7751. +void
  7752. +Transaction::NotifyListeners(bool success)
  7753. +{
  7754. +   if (success) {
  7755. +       TRACE("Transaction::NotifyListeners(true): Number of listeners: %ld\n",
  7756. +           fListeners.Count());
  7757. +   } else {
  7758. +       TRACE("Transaction::NotifyListeners(false): Number of listeners: %ld\n",
  7759. +           fListeners.Count());
  7760. +   }
  7761. +
  7762. +   while (TransactionListener* listener = fListeners.RemoveHead()) {
  7763. +       listener->TransactionDone(success);
  7764. +       listener->RemovedFromTransaction();
  7765. +   }
  7766. +}
  7767. +
  7768. +
  7769. +void
  7770. +Transaction::MoveListenersTo(Transaction* transaction)
  7771. +{
  7772. +   while (TransactionListener* listener = fListeners.RemoveHead())
  7773. +       transaction->fListeners.Add(listener);
  7774. +}
  7775. +
  7776. +
  7777. +void
  7778. +Transaction::SetParent(Transaction* transaction)
  7779. +{
  7780. +   fParent = transaction;
  7781. +}
  7782. +
  7783. +
  7784. +Transaction*
  7785. +Transaction::Parent() const
  7786. +{
  7787. +   return fParent;
  7788. +}
  7789. Index: src/add-ons/kernel/file_systems/ext2/ext2.h
  7790. ===================================================================
  7791. --- src/add-ons/kernel/file_systems/ext2/ext2.h (revision 37957)
  7792. +++ src/add-ons/kernel/file_systems/ext2/ext2.h (working copy)
  7793. @@ -13,6 +13,8 @@
  7794.  #include <KernelExport.h>
  7795.  
  7796.  
  7797. +#define TRACE_EXT2
  7798. +
  7799.  #define EXT2_SUPER_BLOCK_OFFSET    1024
  7800.  
  7801.  struct ext2_super_block {
  7802. @@ -108,9 +110,16 @@
  7803.         { return B_LENDIAN_TO_HOST_INT32(read_only_features); }
  7804.     uint32 IncompatibleFeatures() const
  7805.         { return B_LENDIAN_TO_HOST_INT32(incompatible_features); }
  7806. +   ino_t  JournalInode() const
  7807. +       { return B_LENDIAN_TO_HOST_INT32(journal_inode); }
  7808.     uint32 HashSeed(uint8 i) const
  7809.         { return B_LENDIAN_TO_HOST_INT32(hash_seed[i]); }
  7810.  
  7811. +   void SetFreeInodes(uint32 freeInodes)
  7812. +       { free_inodes = B_HOST_TO_LENDIAN_INT32(freeInodes); }
  7813. +   void SetFreeBlocks(uint32 freeBlocks)
  7814. +       { free_blocks = B_HOST_TO_LENDIAN_INT32(freeBlocks); }
  7815. +
  7816.     bool IsValid();
  7817.         // implemented in Volume.cpp
  7818.  } _PACKED;
  7819. @@ -162,8 +171,16 @@
  7820.     uint16  _padding;
  7821.     uint32  _reserved[3];
  7822.  
  7823. +   uint32 BlockBitmap() const
  7824. +       { return B_LENDIAN_TO_HOST_INT32(block_bitmap); }
  7825. +   uint32 InodeBitmap() const
  7826. +       { return B_LENDIAN_TO_HOST_INT32(inode_bitmap); }
  7827.     uint32 InodeTable() const
  7828.         { return B_LENDIAN_TO_HOST_INT32(inode_table); }
  7829. +   uint16 FreeBlocks() const
  7830. +       { return B_LENDIAN_TO_HOST_INT16(free_blocks); }
  7831. +   uint16 FreeInodes() const
  7832. +       { return B_LENDIAN_TO_HOST_INT16(free_inodes); }
  7833.  } _PACKED;
  7834.  
  7835.  #define EXT2_DIRECT_BLOCKS         12
  7836. @@ -175,6 +192,24 @@
  7837.     uint32 indirect;
  7838.     uint32 double_indirect;
  7839.     uint32 triple_indirect;
  7840. +
  7841. +   uint32  Direct(int index)   const
  7842. +       { return B_LENDIAN_TO_HOST_INT32(direct[index]); }
  7843. +   uint32  Indirect()          const
  7844. +       { return B_LENDIAN_TO_HOST_INT32(indirect); }
  7845. +   uint32  DoubleIndirect()    const
  7846. +       { return B_LENDIAN_TO_HOST_INT32(double_indirect); }
  7847. +   uint32  TripleIndirect()    const
  7848. +       { return B_LENDIAN_TO_HOST_INT32(triple_indirect); }
  7849. +
  7850. +   void    SetDirect(int index, uint32 value)
  7851. +       { direct[index] = B_HOST_TO_LENDIAN_INT32(value); }
  7852. +   void    SetIndirect(uint32 value)
  7853. +       { indirect = B_HOST_TO_LENDIAN_INT32(value); }
  7854. +   void    SetDoubleIndirect(uint32 value)
  7855. +       { double_indirect = B_HOST_TO_LENDIAN_INT32(value); }
  7856. +   void    SetTripleIndirect(uint32 value)
  7857. +       { triple_indirect = B_HOST_TO_LENDIAN_INT32(value); }
  7858.  } _PACKED;
  7859.  
  7860.  struct ext2_inode {
  7861. @@ -214,6 +249,7 @@
  7862.     uint16 Mode() const { return B_LENDIAN_TO_HOST_INT16(mode); }
  7863.     uint32 Flags() const { return B_LENDIAN_TO_HOST_INT32(flags); }
  7864.     uint16 NumLinks() const { return B_LENDIAN_TO_HOST_INT16(num_links); }
  7865. +   uint32 NumBlocks() const { return B_LENDIAN_TO_HOST_INT32(num_blocks); }
  7866.  
  7867.     time_t AccessTime() const { return B_LENDIAN_TO_HOST_INT32(access_time); }
  7868.     time_t CreationTime() const { return B_LENDIAN_TO_HOST_INT32(creation_time); }
  7869. @@ -241,6 +277,60 @@
  7870.         return B_LENDIAN_TO_HOST_INT16(gid)
  7871.             | (B_LENDIAN_TO_HOST_INT16(gid_high) << 16);
  7872.     }
  7873. +
  7874. +   void SetMode(uint16 newMode)
  7875. +   {
  7876. +       mode = B_LENDIAN_TO_HOST_INT16(newMode);
  7877. +   }
  7878. +
  7879. +   void SetFlag(uint32 mask)
  7880. +   {
  7881. +       flags |= B_HOST_TO_LENDIAN_INT32(mask);
  7882. +   }
  7883. +
  7884. +   void SetFlags(uint32 newFlags)
  7885. +   {
  7886. +       flags = B_HOST_TO_LENDIAN_INT32(newFlags);
  7887. +   }
  7888. +
  7889. +   void SetNumLinks(uint16 numLinks)
  7890. +   {
  7891. +       num_links = B_HOST_TO_LENDIAN_INT16(numLinks);
  7892. +   }
  7893. +
  7894. +   void SetNumBlocks(uint32 numBlocks)
  7895. +   {
  7896. +       num_blocks = B_HOST_TO_LENDIAN_INT32(numBlocks);
  7897. +   }
  7898. +
  7899. +   void SetCreationTime(time_t creationTime)
  7900. +   {
  7901. +       creation_time = B_HOST_TO_LENDIAN_INT32(creationTime);
  7902. +   }
  7903. +
  7904. +   void SetModificationTime(time_t modificationTime)
  7905. +   {
  7906. +       modification_time = B_HOST_TO_LENDIAN_INT32(modificationTime);
  7907. +   }
  7908. +
  7909. +   void SetSize(off_t newSize)
  7910. +   {
  7911. +       size = B_HOST_TO_LENDIAN_INT32(newSize & 0xFFFFFFFF);
  7912. +       if (S_ISREG(Mode()))
  7913. +           size_high = B_HOST_TO_LENDIAN_INT32(newSize >> 32);
  7914. +   }
  7915. +
  7916. +   void SetUserID(uint32 newUID)
  7917. +   {
  7918. +       uid = B_HOST_TO_LENDIAN_INT16(newUID & 0xFFFF);
  7919. +       uid_high = B_HOST_TO_LENDIAN_INT16(newUID >> 16);
  7920. +   }
  7921. +
  7922. +   void SetGroupID(uint32 newGID)
  7923. +   {
  7924. +       gid = B_HOST_TO_LENDIAN_INT16(newGID & 0xFFFF);
  7925. +       gid_high = B_HOST_TO_LENDIAN_INT16(newGID >> 16);
  7926. +   }
  7927.  } _PACKED;
  7928.  
  7929.  #define EXT2_SUPER_BLOCK_MAGIC         0xef53
  7930. @@ -270,11 +360,26 @@
  7931.     uint8   file_type;
  7932.     char    name[EXT2_NAME_LENGTH];
  7933.  
  7934. -   uint32 InodeID() const { return B_LENDIAN_TO_HOST_INT32(inode_id); }
  7935. -   uint16 Length() const { return B_LENDIAN_TO_HOST_INT16(length); }
  7936. -   uint8 NameLength() const { return name_length; }
  7937. -   uint8 FileType() const { return file_type; }
  7938. +   uint32  InodeID() const { return B_LENDIAN_TO_HOST_INT32(inode_id); }
  7939. +   uint16  Length() const { return B_LENDIAN_TO_HOST_INT16(length); }
  7940. +   uint8   NameLength() const { return name_length; }
  7941. +   uint8   FileType() const { return file_type; }
  7942.  
  7943. +   void    SetInodeID(uint32 id) { inode_id = B_HOST_TO_LENDIAN_INT32(id); }
  7944. +
  7945. +   void    SetLength(uint8 nameLength)
  7946. +   {
  7947. +       name_length = nameLength;
  7948. +
  7949. +       if (nameLength % 4 == 0) {
  7950. +           length = B_HOST_TO_LENDIAN_INT16(
  7951. +               (short)(nameLength + MinimumSize()));
  7952. +       } else {
  7953. +           length = B_HOST_TO_LENDIAN_INT16(
  7954. +               (short)(nameLength % 4 + 1 + MinimumSize()));
  7955. +       }
  7956. +   }
  7957. +
  7958.     bool IsValid() const
  7959.     {
  7960.         return Length() > MinimumSize();
  7961. @@ -370,6 +475,16 @@
  7962.  } _PACKED;
  7963.  
  7964.  
  7965. +struct file_cookie {
  7966. +   bigtime_t   last_notification;
  7967. +   off_t       last_size;
  7968. +   int         open_mode;
  7969. +};
  7970. +
  7971. +
  7972. +#define INODE_NOTIFICATION_INTERVAL        10000000LL
  7973. +
  7974. +
  7975.  extern fs_volume_ops gExt2VolumeOps;
  7976.  extern fs_vnode_ops gExt2VnodeOps;
  7977.  
  7978. Index: src/add-ons/kernel/file_systems/ext2/CachedBlock.h
  7979. ===================================================================
  7980. --- src/add-ons/kernel/file_systems/ext2/CachedBlock.h  (revision 37957)
  7981. +++ src/add-ons/kernel/file_systems/ext2/CachedBlock.h  (working copy)
  7982. @@ -9,32 +9,40 @@
  7983.  
  7984.  #include <fs_cache.h>
  7985.  
  7986. +#include "Transaction.h"
  7987.  #include "Volume.h"
  7988.  
  7989.  
  7990.  class CachedBlock {
  7991.  public:
  7992. -                   CachedBlock(Volume* volume);
  7993. -                   CachedBlock(Volume* volume, uint32 block);
  7994. -                   ~CachedBlock();
  7995. +                           CachedBlock(Volume* volume);
  7996. +                           CachedBlock(Volume* volume, uint32 block);
  7997. +                           ~CachedBlock();
  7998.  
  7999. -           void    Keep();
  8000. -           void    Unset();
  8001. +           void            Keep();
  8002. +           void            Unset();
  8003.  
  8004. -   const   uint8*  SetTo(uint32 block);
  8005. +           const uint8*    SetTo(uint32 block);
  8006. +           uint8*          SetToWritable(Transaction& transaction,
  8007. +                               uint32 block, bool empty = false);
  8008. +           uint8*          SetToWritableWithoutTransaction(uint32 block,
  8009. +                               bool empty = false);
  8010.  
  8011. -   const   uint8*  Block() const { return fBlock; }
  8012. -           off_t   BlockNumber() const { return fBlockNumber; }
  8013. +           const uint8*    Block() const { return fBlock; }
  8014. +           off_t           BlockNumber() const { return fBlockNumber; }
  8015.  
  8016.  private:
  8017. -                   CachedBlock(const CachedBlock &);
  8018. -                   CachedBlock &operator=(const CachedBlock &);
  8019. -                       // no implementation
  8020. +                           CachedBlock(const CachedBlock &);
  8021. +                           CachedBlock &operator=(const CachedBlock &);
  8022. +                               // no implementation
  8023. +                      
  8024. +           uint8*          _SetToWritableEtc(int32 transaction, uint32 block,
  8025. +                               bool empty);
  8026.  
  8027.  protected:
  8028. -   Volume*         fVolume;
  8029. -   uint32          fBlockNumber;
  8030. -   uint8*          fBlock;
  8031. +           Volume*         fVolume;
  8032. +           uint32          fBlockNumber;
  8033. +           uint8*          fBlock;
  8034.  };
  8035.  
  8036.  
  8037. @@ -94,4 +102,35 @@
  8038.     return fBlock = (uint8 *)block_cache_get(fVolume->BlockCache(), block);
  8039.  }
  8040.  
  8041. +
  8042. +inline uint8*
  8043. +CachedBlock::SetToWritable(Transaction& transaction, uint32 block, bool empty)
  8044. +{
  8045. +   return _SetToWritableEtc(transaction.ID(), block, empty);
  8046. +}
  8047. +
  8048. +
  8049. +inline uint8*
  8050. +CachedBlock::SetToWritableWithoutTransaction(uint32 block, bool empty)
  8051. +{
  8052. +   return _SetToWritableEtc((int32)-1, block, empty);
  8053. +}
  8054. +
  8055. +inline uint8*
  8056. +CachedBlock::_SetToWritableEtc(int32 transaction, uint32 block, bool empty)
  8057. +{
  8058. +   Unset();
  8059. +   fBlockNumber = block;
  8060. +
  8061. +   if (empty) {
  8062. +       fBlock = (uint8*)block_cache_get_empty(fVolume->BlockCache(),
  8063. +           block, transaction);
  8064. +   } else {
  8065. +       fBlock = (uint8*)block_cache_get_writable(fVolume->BlockCache(),
  8066. +           block, transaction);
  8067. +   }
  8068. +
  8069. +   return fBlock;
  8070. +}
  8071. +
  8072.  #endif // CACHED_BLOCK_H
  8073. Index: src/add-ons/kernel/file_systems/ext2/HashRevokeManager.cpp
  8074. ===================================================================
  8075. --- src/add-ons/kernel/file_systems/ext2/HashRevokeManager.cpp  (revision 0)
  8076. +++ src/add-ons/kernel/file_systems/ext2/HashRevokeManager.cpp  (revision 0)
  8077. @@ -0,0 +1,158 @@
  8078. +/*
  8079. + * Copyright 2001-2010, Haiku Inc. All rights reserved.
  8080. + * This file may be used under the terms of the MIT License.
  8081. + *
  8082. + * Authors:
  8083. + *     Janito V. Ferreira Filho
  8084. + */
  8085. +
  8086. +#include "HashRevokeManager.h"
  8087. +
  8088. +#include <new>
  8089. +
  8090. +
  8091. +//#define TRACE_EXT2
  8092. +#ifdef TRACE_EXT2
  8093. +#  define TRACE(x...) dprintf("\33[34mext2:\33[0m " x)
  8094. +#else
  8095. +#  define TRACE(x...) ;
  8096. +#endif
  8097. +
  8098. +
  8099. +HashRevokeManager::HashRevokeManager()
  8100. +   :
  8101. +   fHash(NULL),
  8102. +   kInitialHashSize(128)
  8103. +       // TODO: Benchmark and find an optimal value
  8104. +{
  8105. +}
  8106. +
  8107. +
  8108. +HashRevokeManager::~HashRevokeManager()
  8109. +{
  8110. +   if (fHash != NULL)
  8111. +       hash_uninit(fHash);
  8112. +}
  8113. +
  8114. +
  8115. +status_t
  8116. +HashRevokeManager::Init()
  8117. +{
  8118. +   RevokeElement dummyElement;
  8119. +  
  8120. +   fHash = hash_init(kInitialHashSize, offset_of_member(dummyElement, next),
  8121. +       &HashRevokeManager::Compare,
  8122. +       &HashRevokeManager::Hash);
  8123. +
  8124. +   if (fHash == NULL)
  8125. +       return B_NO_MEMORY;
  8126. +
  8127. +   return B_OK;
  8128. +}
  8129. +
  8130. +
  8131. +status_t
  8132. +HashRevokeManager::Insert(uint32 block, uint32 commitID)
  8133. +{
  8134. +   RevokeElement* element = (RevokeElement*)hash_lookup(fHash, &block);
  8135. +  
  8136. +   if (element != NULL) {
  8137. +       TRACE("HashRevokeManager::Insert(): Already has an element\n");
  8138. +       if (element->commitID < commitID) {
  8139. +           TRACE("HashRevokeManager::Insert(): Deleting previous element\n");
  8140. +           status_t retValue = hash_remove(fHash, element);
  8141. +          
  8142. +           if (retValue != B_OK)
  8143. +               return retValue;
  8144. +
  8145. +           delete element;
  8146. +       }
  8147. +       else {
  8148. +           return B_OK;
  8149. +               // We already have a newer version of the block
  8150. +       }
  8151. +   }
  8152. +
  8153. +   return _ForceInsert(block, commitID);
  8154. +}
  8155. +
  8156. +
  8157. +status_t
  8158. +HashRevokeManager::Remove(uint32 block)
  8159. +{
  8160. +   RevokeElement* element = (RevokeElement*)hash_lookup(fHash, &block);
  8161. +
  8162. +   if (element == NULL)
  8163. +       return B_ERROR; // TODO: Perhaps we should just ignore?
  8164. +
  8165. +   status_t retValue = hash_remove(fHash, element);
  8166. +  
  8167. +   if (retValue == B_OK)
  8168. +       delete element;
  8169. +
  8170. +   return retValue;
  8171. +}
  8172. +
  8173. +
  8174. +bool
  8175. +HashRevokeManager::Lookup(uint32 block, uint32 commitID)
  8176. +{
  8177. +   RevokeElement* element = (RevokeElement*)hash_lookup(fHash, &block);
  8178. +
  8179. +   if (element == NULL)
  8180. +       return false;
  8181. +
  8182. +   return element->commitID >= commitID;
  8183. +}
  8184. +
  8185. +
  8186. +/*static*/ int
  8187. +HashRevokeManager::Compare(void* _revoked, const void *_block)
  8188. +{
  8189. +   RevokeElement* revoked = (RevokeElement*)_revoked;
  8190. +   uint32 block = *(uint32*)_block;
  8191. +
  8192. +   if (revoked->block == block)
  8193. +       return 0;
  8194. +
  8195. +   return (revoked->block > block) ? 1 : -1;
  8196. +}
  8197. +
  8198. +
  8199. +/*static*/ uint32
  8200. +HashRevokeManager::Hash(void* _revoked, const void* _block, uint32 range)
  8201. +{
  8202. +   TRACE("HashRevokeManager::Hash(): revoked: %p, block: %p, range: %lu\n",
  8203. +       _revoked, _block, range);
  8204. +   RevokeElement* revoked = (RevokeElement*)_revoked;
  8205. +
  8206. +   if (revoked != NULL)
  8207. +       return revoked->block % range;
  8208. +
  8209. +   uint32 block = *(uint32*)_block;
  8210. +   return block % range;
  8211. +}
  8212. +
  8213. +
  8214. +status_t
  8215. +HashRevokeManager::_ForceInsert(uint32 block, uint32 commitID)
  8216. +{
  8217. +   RevokeElement* element = new(std::nothrow) RevokeElement;
  8218. +
  8219. +   if (element == NULL)
  8220. +       return B_NO_MEMORY;
  8221. +
  8222. +   element->block = block;
  8223. +   element->commitID = commitID;
  8224. +
  8225. +   status_t retValue = hash_insert_grow(fHash, element);
  8226. +
  8227. +   if (retValue == B_OK) {
  8228. +       fRevokeCount++;
  8229. +       TRACE("HashRevokeManager::_ForceInsert(): revoke count: %lu\n",
  8230. +           fRevokeCount);
  8231. +   }
  8232. +
  8233. +   return retValue;
  8234. +}
  8235. +
  8236.  
  8237. Property changes on: src/add-ons/kernel/file_systems/ext2/HashRevokeManager.cpp
  8238. ___________________________________________________________________
  8239. Added: svn:executable
  8240.    + *
  8241.  
  8242. Index: src/add-ons/kernel/file_systems/ext2/RevokeManager.h
  8243. ===================================================================
  8244. --- src/add-ons/kernel/file_systems/ext2/RevokeManager.h    (revision 0)
  8245. +++ src/add-ons/kernel/file_systems/ext2/RevokeManager.h    (revision 0)
  8246. @@ -0,0 +1,35 @@
  8247. +/*
  8248. + * Copyright 2001-2010, Haiku Inc. All rights reserved.
  8249. + * This file may be used under the terms of the MIT License.
  8250. + *
  8251. + * Authors:
  8252. + *     Janito V. Ferreira Filho
  8253. + */
  8254. +#ifndef REVOKEMANAGER_H
  8255. +#define REVOKEMANAGER_H
  8256. +
  8257. +#include "Journal.h"
  8258. +
  8259. +
  8260. +struct JournalRevokeHeader;
  8261. +
  8262. +class RevokeManager {
  8263. +public:
  8264. +                       RevokeManager();
  8265. +   virtual             ~RevokeManager() = 0;
  8266. +
  8267. +   virtual status_t    Insert(uint32 block, uint32 commitID) = 0;
  8268. +   virtual status_t    Remove(uint32 block) = 0;
  8269. +   virtual bool        Lookup(uint32 block, uint32 commitID) = 0;
  8270. +          
  8271. +           uint32      NumRevokes() { return fRevokeCount; }
  8272. +
  8273. +           status_t    ScanRevokeBlock(JournalRevokeHeader* revokeBlock,
  8274. +                           uint32 commitID);
  8275. +
  8276. +protected:
  8277. +           uint32      fRevokeCount;
  8278. +};
  8279. +
  8280. +#endif // REVOKEMANAGER_H
  8281. +
  8282.  
  8283. Property changes on: src/add-ons/kernel/file_systems/ext2/RevokeManager.h
  8284. ___________________________________________________________________
  8285. Added: svn:executable
  8286.    + *
  8287.  
  8288. Index: src/add-ons/kernel/file_systems/ext2/BitmapBlock.h
  8289. ===================================================================
  8290. --- src/add-ons/kernel/file_systems/ext2/BitmapBlock.h  (revision 0)
  8291. +++ src/add-ons/kernel/file_systems/ext2/BitmapBlock.h  (revision 0)
  8292. @@ -0,0 +1,48 @@
  8293. +/*
  8294. + * Copyright 2001-2010, Haiku Inc. All rights reserved.
  8295. + * This file may be used under the terms of the MIT License.
  8296. + *
  8297. + * Authors:
  8298. + *     Janito V. Ferreira Filho
  8299. + */
  8300. +#ifndef BITMAPBLOCK_H
  8301. +#define BITMAPBLOCK_H
  8302. +
  8303. +#include "CachedBlock.h"
  8304. +
  8305. +
  8306. +class BitmapBlock : public CachedBlock {
  8307. +public:
  8308. +                           BitmapBlock(Volume* volume, uint32 numBits);
  8309. +                           ~BitmapBlock();
  8310. +
  8311. +           bool            SetTo(uint32 block);
  8312. +           bool            SetToWritable(Transaction& transaction,
  8313. +                               uint32 block, bool empty = false);
  8314. +
  8315. +           bool            CheckMarked(uint32 start, uint32 length);
  8316. +           bool            CheckUnmarked(uint32 start, uint32 length);
  8317. +
  8318. +           bool            Mark(uint32 start, uint32 length,
  8319. +                               bool force = false);
  8320. +           bool            Unmark(uint32 start, uint32 length,
  8321. +                               bool force = false);
  8322. +
  8323. +           void            FindNextMarked(uint32& pos);
  8324. +           void            FindNextUnmarked(uint32& pos);
  8325. +
  8326. +           void            FindPreviousMarked(uint32& pos);
  8327. +
  8328. +           void            FindLargestUnmarkedRange(uint32& start,
  8329. +                               uint32& length);
  8330. +
  8331. +           uint32          NumBits() const;
  8332. +
  8333. +protected:
  8334. +           uint32*         fData;
  8335. +           const uint32*   fReadOnlyData;
  8336. +
  8337. +           uint32          fNumBits;
  8338. +};
  8339. +
  8340. +#endif // BITMAPBLOCK_H
  8341.  
  8342. Property changes on: src/add-ons/kernel/file_systems/ext2/BitmapBlock.h
  8343. ___________________________________________________________________
  8344. Added: svn:executable
  8345.    + *
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement