Advertisement
Guest User

Untitled

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