Advertisement
Guest User

Untitled

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