1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "format.h"
6 
7 namespace minfs {
8 
9 // TODO(ZX-2781): Break up transactions into chunks so that journal size
10 //                is not dependent on block bitmap size.
11 
12 // Calculates and returns the maximum number of block bitmap blocks, based on |info_|.
13 blk_t GetBlockBitmapBlocks(const Superblock& info);
14 
15 // Calculates the required number of blocks into |num_req_blocks| for a write at the given |offset|
16 // and |length|.
17 zx_status_t GetRequiredBlockCount(size_t offset, size_t length, uint32_t* num_req_blocks);
18 
19 // Calculates and tracks the number of Minfs metadata / data blocks that can be modified within one
20 // transaction, as well as the corresponding Journal sizes.
21 // Once we can grow the block bitmap, we will need to be able to recalculate these limits.
22 class TransactionLimits {
23 public:
24     TransactionLimits(const Superblock& info);
25 
26     // Returns the maximum number of metadata blocks that we expect to be modified in the data
27     // section within one transaction. For data vnodes, based on a max write size of 64kb, this is
28     // currently expected to be 3 indirect blocks (would be 4 with the introduction of more doubly
29     // indirect blocks). For directories, with a max dirent size of 268b, this is expected to be 5
30     // blocks.
GetMaximumMetaDataBlocks()31     blk_t GetMaximumMetaDataBlocks() const { return max_meta_data_blocks_; }
32 
33     // Returns the maximum number of data blocks (including indirects) that we expect to be
34     // modified within one transaction. Based on a max write size of 64kb, this is currently
35     // expected to be 9 direct blocks + 3 indirect blocks = 11 total blocks. With the addition of
36     // more doubly indirect blocks, this would increase to 4 indirect blocks for a total of 12
37     // blocks.
GetMaximumDataBlocks()38     blk_t GetMaximumDataBlocks() const { return max_data_blocks_; }
39 
40     // Returns the maximum number of data blocks that can be included in a journal entry,
41     // i.e. the total number of blocks that can be held in a WriteTxn enqueued to the journal.
GetMaximumEntryDataBlocks()42     blk_t GetMaximumEntryDataBlocks() const { return max_entry_data_blocks_; }
43 
44     // Returns the total number of blocks required for the maximum size journal entry.
GetMaximumEntryBlocks()45     blk_t GetMaximumEntryBlocks() const { return max_entry_blocks_; }
46 
47     // Returns the minimum number of blocks required to create a journal guaranteed large enough to
48     // hold at least a single journal entry of maximum size.
GetMinimumJournalBlocks()49     blk_t GetMinimumJournalBlocks() const { return min_journal_blocks_; }
50 
51     // Returns the ideal number of blocks to allocate to the journal section, provided enough space
52     // is available.
GetRecommendedJournalBlocks()53     blk_t GetRecommendedJournalBlocks() const { return rec_journal_blocks_; }
54 
55     // Maximum number of superblock blocks that can be modified within one transaction.
56     // Since there is only 1 superblock, there can be only 1 block updated on each transaction.
57     static constexpr blk_t kMaxSuperblockBlocks = 1;
58 
59     // TODO(planders): Enforce all of the following limits.
60     //                 (Perhaps by tracking modified counts within the Transaction).
61     // Maximum number of inode bitmap blocks that can be modified within one transaction.
62     // A maximum of 1 inode can be created or deleted during a single transaction.
63     static constexpr blk_t kMaxInodeBitmapBlocks = 1;
64 
65     // Maximum number of inode table blocks that can be modified within one transaction.
66     // No more than 2 inodes will be modified during a single transaction.
67     // (In the case of Create, the parent directory and the child inode will be modified.)
68     static constexpr blk_t kMaxInodeTableBlocks = 2;
69 
70     // The largest amount of data that Write() should able to process at once. This is currently
71     // constrainted by external factors to (1 << 13), but with the switch to FIDL we expect
72     // incoming requests to be NO MORE than (1 << 16). Even so, we should update Write() to handle
73     // cases beyond this.
74     // TODO(planders): Internally break up large write requests so they fit within this constraint.
75     static constexpr size_t kMaxWriteBytes = (1 << 16);
76 
77     // Number of metadata blocks required for the whole journal - 1 Superblock.
78     static constexpr blk_t kJournalMetadataBlocks = 1;
79 
80     // Default number of blocks which should be allocated to the journal, if the minimum
81     // requirement does not exceed it.
82     static constexpr blk_t kDefaultJournalBlocks = 256;
83 
84 private:
85     // Calculates the maximum number of data and metadata blocks that can be updated during a
86     // single transaction.
87     void CalculateDataBlocks();
88 
89     // Calculates the maximum journal entry size and the minimum size required for the journal.
90     void CalculateJournalBlocks(blk_t block_bitmap_blocks);
91 
92     blk_t max_meta_data_blocks_;
93     blk_t max_data_blocks_;
94     blk_t max_entry_data_blocks_;
95     blk_t max_entry_blocks_;
96     blk_t min_journal_blocks_;
97     blk_t rec_journal_blocks_;
98 };
99 
100 } // namespace minfs