Advertisement
Guest User

Untitled

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