Advertisement
Guest User

Untitled

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