alloc.rs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. use super::Ext4;
  2. use crate::constants::*;
  3. use crate::ext4_defs::*;
  4. use crate::format_error;
  5. use crate::prelude::*;
  6. use crate::return_error;
  7. impl Ext4 {
  8. /// Create a new inode, returning the inode and its number
  9. pub(super) fn create_inode(&self, mode: InodeMode) -> Result<InodeRef> {
  10. // Allocate an inode
  11. let is_dir = mode.file_type() == FileType::Directory;
  12. let id = self.alloc_inode(is_dir)?;
  13. // Initialize the inode
  14. let mut inode = Inode::default();
  15. inode.set_mode(mode);
  16. inode.extent_init();
  17. let mut inode_ref = InodeRef::new(id, inode);
  18. // Sync the inode to disk
  19. self.write_inode_with_csum(&mut inode_ref);
  20. info!("Alloc inode {} ok", inode_ref.id);
  21. Ok(inode_ref)
  22. }
  23. /// Create(initialize) the root inode of the file system
  24. pub(super) fn create_root_inode(&self) -> Result<InodeRef> {
  25. let mut inode = Inode::default();
  26. inode.set_mode(InodeMode::from_type_and_perm(
  27. FileType::Directory,
  28. InodeMode::ALL_RWX,
  29. ));
  30. inode.extent_init();
  31. let mut root = InodeRef::new(EXT4_ROOT_INO, inode);
  32. let root_self = root.clone();
  33. // Add `.` and `..` entries
  34. self.dir_add_entry(&mut root, &root_self, ".")?;
  35. self.dir_add_entry(&mut root, &root_self, "..")?;
  36. self.write_inode_with_csum(&mut root);
  37. Ok(root)
  38. }
  39. /// Free an allocated inode and all data blocks allocated for it
  40. pub(super) fn free_inode(&self, inode: &mut InodeRef) -> Result<()> {
  41. // Free the data blocks allocated for the inode
  42. let pblocks = self.extent_all_data_blocks(&inode);
  43. for pblock in pblocks {
  44. // Deallocate the block
  45. self.dealloc_block(inode, pblock)?;
  46. // Update inode block count
  47. inode.inode.set_block_count(inode.inode.block_count() - 1);
  48. // Clear the block content
  49. self.write_block(&Block::new(pblock, [0; BLOCK_SIZE]));
  50. }
  51. // Free extent tree
  52. let pblocks = self.extent_all_tree_blocks(&inode);
  53. for pblock in pblocks {
  54. // Deallocate the block
  55. self.dealloc_block(inode, pblock)?;
  56. // Tree blocks are not counted in `inode.block_count`
  57. // Clear the block content
  58. self.write_block(&Block::new(pblock, [0; BLOCK_SIZE]));
  59. }
  60. // Deallocate the inode
  61. self.dealloc_inode(&inode)?;
  62. // Clear the inode content
  63. inode.inode = unsafe { core::mem::zeroed() };
  64. self.write_inode_without_csum(inode);
  65. Ok(())
  66. }
  67. /// Append a data block for an inode, return a pair of (logical block id, physical block id)
  68. ///
  69. /// Only data blocks allocated by `inode_append_block` will be counted in `inode.block_count`.
  70. /// Blocks allocated by calling `alloc_block` directly will not be counted, i.e., blocks
  71. /// allocated for the inode's extent tree.
  72. ///
  73. /// Appending a block does not increase `inode.size`, because `inode.size` records the actual
  74. /// size of the data content, not the number of blocks allocated for it.
  75. ///
  76. /// If the inode is a file, `inode.size` will be increased when writing to end of the file.
  77. /// If the inode is a directory, `inode.size` will be increased when adding a new entry to the
  78. /// newly created block.
  79. pub(super) fn inode_append_block(&self, inode: &mut InodeRef) -> Result<(LBlockId, PBlockId)> {
  80. // The new logical block id
  81. let iblock = inode.inode.block_count() as LBlockId;
  82. // Check the extent tree to get the physical block id
  83. let fblock = self.extent_query_or_create(inode, iblock, 1)?;
  84. // Update block count
  85. inode.inode.set_block_count(inode.inode.block_count() + 1);
  86. self.write_inode_without_csum(inode);
  87. Ok((iblock, fblock))
  88. }
  89. /// Allocate a new physical block for an inode, return the physical block number
  90. pub(super) fn alloc_block(&self, inode: &mut InodeRef) -> Result<PBlockId> {
  91. let mut sb = self.read_super_block();
  92. // Calc block group id
  93. let inodes_per_group = sb.inodes_per_group();
  94. let bgid = ((inode.id - 1) / inodes_per_group) as BlockGroupId;
  95. // Load block group descriptor
  96. let mut bg = self.read_block_group(bgid);
  97. // Load block bitmap
  98. let bitmap_block_id = bg.desc.block_bitmap_block(&sb);
  99. let mut bitmap_block = self.read_block(bitmap_block_id);
  100. let mut bitmap = Bitmap::new(&mut bitmap_block.data);
  101. // Find the first free block
  102. let fblock = bitmap
  103. .find_and_set_first_clear_bit(0, 8 * BLOCK_SIZE)
  104. .ok_or(format_error!(
  105. ErrCode::ENOSPC,
  106. "No free blocks in block group {}",
  107. bgid
  108. ))? as PBlockId;
  109. // Set block group checksum
  110. bg.desc.set_block_bitmap_csum(&sb, &bitmap);
  111. self.write_block(&bitmap_block);
  112. // Update superblock free blocks count
  113. let free_blocks = sb.free_blocks_count() - 1;
  114. sb.set_free_blocks_count(free_blocks);
  115. self.write_super_block(&sb);
  116. // Update block group free blocks count
  117. let fb_cnt = bg.desc.get_free_blocks_count() - 1;
  118. bg.desc.set_free_blocks_count(fb_cnt);
  119. self.write_block_group_with_csum(&mut bg);
  120. info!("Alloc block {} ok", fblock);
  121. Ok(fblock)
  122. }
  123. /// Deallocate a physical block allocated for an inode
  124. pub(super) fn dealloc_block(&self, inode: &mut InodeRef, pblock: PBlockId) -> Result<()> {
  125. let mut sb = self.read_super_block();
  126. // Calc block group id
  127. let inodes_per_group = sb.inodes_per_group();
  128. let bgid = ((inode.id - 1) / inodes_per_group) as BlockGroupId;
  129. // Load block group descriptor
  130. let mut bg = self.read_block_group(bgid);
  131. // Load block bitmap
  132. let bitmap_block_id = bg.desc.block_bitmap_block(&sb);
  133. let mut bitmap_block = self.read_block(bitmap_block_id);
  134. let mut bitmap = Bitmap::new(&mut bitmap_block.data);
  135. // Free the block
  136. if bitmap.is_bit_clear(pblock as usize) {
  137. return_error!(ErrCode::EINVAL, "Block {} is already free", pblock);
  138. }
  139. bitmap.clear_bit(pblock as usize);
  140. // Set block group checksum
  141. bg.desc.set_block_bitmap_csum(&sb, &bitmap);
  142. self.write_block(&bitmap_block);
  143. // Update superblock free blocks count
  144. let free_blocks = sb.free_blocks_count() + 1;
  145. sb.set_free_blocks_count(free_blocks);
  146. self.write_super_block(&sb);
  147. // Update block group free blocks count
  148. let fb_cnt = bg.desc.get_free_blocks_count() + 1;
  149. bg.desc.set_free_blocks_count(fb_cnt);
  150. self.write_block_group_with_csum(&mut bg);
  151. info!("Free block {} ok", pblock);
  152. Ok(())
  153. }
  154. /// Allocate a new inode, returning the inode number.
  155. fn alloc_inode(&self, is_dir: bool) -> Result<InodeId> {
  156. let mut sb = self.read_super_block();
  157. let bg_count = sb.block_group_count();
  158. let mut bgid = 0;
  159. while bgid <= bg_count {
  160. // Load block group descriptor
  161. let mut bg = self.read_block_group(bgid);
  162. // If there are no free inodes in this block group, try the next one
  163. if bg.desc.free_inodes_count() == 0 {
  164. bgid += 1;
  165. continue;
  166. }
  167. // Load inode bitmap
  168. let bitmap_block_id = bg.desc.inode_bitmap_block(&sb);
  169. let mut bitmap_block = self.read_block(bitmap_block_id);
  170. let inode_count = sb.inode_count_in_group(bgid) as usize;
  171. let mut bitmap = Bitmap::new(&mut bitmap_block.data[..inode_count / 8]);
  172. // Find a free inode
  173. let idx_in_bg =
  174. bitmap
  175. .find_and_set_first_clear_bit(0, inode_count)
  176. .ok_or(format_error!(
  177. ErrCode::ENOSPC,
  178. "No free inodes in block group {}",
  179. bgid
  180. ))? as u32;
  181. // Update bitmap in disk
  182. bg.desc.set_inode_bitmap_csum(&sb, &bitmap);
  183. self.write_block(&bitmap_block);
  184. // Modify filesystem counters
  185. let free_inodes = bg.desc.free_inodes_count() - 1;
  186. bg.desc.set_free_inodes_count(&sb, free_inodes);
  187. // Increase used directories counter
  188. if is_dir {
  189. let used_dirs = bg.desc.used_dirs_count(&sb) + 1;
  190. bg.desc.set_used_dirs_count(&sb, used_dirs);
  191. }
  192. // Decrease unused inodes count
  193. let mut unused = bg.desc.itable_unused(&sb);
  194. let free = inode_count as u32 - unused;
  195. if idx_in_bg >= free {
  196. unused = inode_count as u32 - (idx_in_bg + 1);
  197. bg.desc.set_itable_unused(&sb, unused);
  198. }
  199. self.write_block_group_with_csum(&mut bg);
  200. // Update superblock
  201. sb.decrease_free_inodes_count();
  202. self.write_super_block(&sb);
  203. // Compute the absolute i-node number
  204. let inodes_per_group = sb.inodes_per_group();
  205. let inode_id = bgid * inodes_per_group + (idx_in_bg + 1);
  206. return Ok(inode_id);
  207. }
  208. log::info!("no free inode");
  209. return_error!(ErrCode::ENOSPC, "No free inodes in block group {}", bgid);
  210. }
  211. /// Free an inode
  212. fn dealloc_inode(&self, inode_ref: &InodeRef) -> Result<()> {
  213. let mut sb = self.read_super_block();
  214. // Calc block group id and index in block group
  215. let inodes_per_group = sb.inodes_per_group();
  216. let bgid = ((inode_ref.id - 1) / inodes_per_group) as BlockGroupId;
  217. let idx_in_bg = (inode_ref.id - 1) % inodes_per_group;
  218. // Load block group descriptor
  219. let mut bg = self.read_block_group(bgid);
  220. // Load inode bitmap
  221. let bitmap_block_id = bg.desc.inode_bitmap_block(&sb);
  222. let mut bitmap_block = self.read_block(bitmap_block_id);
  223. let inode_count = sb.inode_count_in_group(bgid) as usize;
  224. let mut bitmap = Bitmap::new(&mut bitmap_block.data[..inode_count / 8]);
  225. // Free the inode
  226. if bitmap.is_bit_clear(idx_in_bg as usize) {
  227. return_error!(
  228. ErrCode::EINVAL,
  229. "Inode {} is already free in block group {}",
  230. inode_ref.id,
  231. bgid
  232. );
  233. }
  234. bitmap.clear_bit(idx_in_bg as usize);
  235. // Update bitmap in disk
  236. bg.desc.set_inode_bitmap_csum(&sb, &bitmap);
  237. self.write_block(&bitmap_block);
  238. // Modify filesystem counters
  239. let free_inodes = bg.desc.free_inodes_count() + 1;
  240. bg.desc.set_free_inodes_count(&sb, free_inodes);
  241. // Increase used directories counter
  242. if inode_ref.inode.is_dir() {
  243. let used_dirs = bg.desc.used_dirs_count(&sb) - 1;
  244. bg.desc.set_used_dirs_count(&sb, used_dirs);
  245. }
  246. // Decrease unused inodes count
  247. let unused = bg.desc.itable_unused(&sb) + 1;
  248. bg.desc.set_itable_unused(&sb, unused);
  249. self.write_block_group_with_csum(&mut bg);
  250. // Update superblock
  251. sb.decrease_free_inodes_count();
  252. self.write_super_block(&sb);
  253. Ok(())
  254. }
  255. }