alloc.rs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. use super::Ext4;
  2. use crate::constants::*;
  3. use crate::ext4_defs::*;
  4. use crate::prelude::*;
  5. impl Ext4 {
  6. /// Allocate a new data block for an inode, return the physical block number
  7. pub fn alloc_block(&mut self, inode_ref: &mut Ext4InodeRef, goal: PBlockId) -> PBlockId {
  8. let bgid = goal / self.blocks_per_group as u64;
  9. let idx_in_bg = goal % self.blocks_per_group as u64;
  10. // Load block group descriptor
  11. let mut bg =
  12. Ext4BlockGroupDesc::load(self.block_device.clone(), &self.super_block, bgid as usize)
  13. .unwrap();
  14. let block_bmap_offset = bg.get_block_bitmap_block(&self.super_block) as usize * BLOCK_SIZE;
  15. // Load block bitmap
  16. let raw_bitmap = &mut self.block_device.read_offset(block_bmap_offset);
  17. let mut bitmap = Bitmap::new(raw_bitmap);
  18. // Find and first free block
  19. let fblock = bitmap.find_and_set_first_clear_bit(idx_in_bg as usize, 8 * BLOCK_SIZE);
  20. if fblock.is_none() {
  21. return 0;
  22. }
  23. // Set block group checksum
  24. bg.set_block_bitmap_csum(&self.super_block, &bitmap);
  25. self.block_device
  26. .write_offset(block_bmap_offset, bitmap.as_raw());
  27. // Update superblock free blocks count
  28. let free_blocks = self.super_block.free_blocks_count();
  29. self.super_block.set_free_blocks_count(free_blocks); // TODO: why not - 1?
  30. self.super_block.sync_to_disk(self.block_device.clone());
  31. // Update inode blocks (different block size!) count
  32. let inode_blocks = inode_ref.inode.blocks_count();
  33. inode_ref.inode.set_blocks_count(inode_blocks as u32 + 8); // TODO: why + 8?
  34. self.write_back_inode_with_csum(inode_ref);
  35. // Update block group free blocks count
  36. let fb_cnt = bg.get_free_blocks_count();
  37. bg.set_free_blocks_count(fb_cnt - 1);
  38. bg.sync_to_disk_with_csum(self.block_device.clone(), bgid as usize, &self.super_block);
  39. fblock.unwrap() as PBlockId
  40. }
  41. /// Append a data block for an inode, return a pair of (logical block id, physical block id)
  42. pub fn inode_append_block(&mut self, inode_ref: &mut Ext4InodeRef) -> (LBlockId, PBlockId) {
  43. let inode_size = inode_ref.inode.size();
  44. // The new logical block id
  45. let iblock = ((inode_size + BLOCK_SIZE as u64 - 1) / BLOCK_SIZE as u64) as u32;
  46. // Check the extent tree to get the physical block id
  47. let fblock = self.extent_get_pblock_create(inode_ref, iblock, 1);
  48. // Update the inode
  49. inode_ref.inode.set_size(inode_size + BLOCK_SIZE as u64);
  50. self.write_back_inode_with_csum(inode_ref);
  51. (iblock, fblock)
  52. }
  53. pub fn ext4_fs_inode_blocks_init(inode_ref: &mut Ext4InodeRef) {
  54. let inode = &mut inode_ref.inode;
  55. let mode = inode.mode;
  56. let inode_type = InodeMode::from_bits(mode & EXT4_INODE_MODE_TYPE_MASK as u16).unwrap();
  57. match inode_type {
  58. InodeMode::S_IFDIR => {}
  59. InodeMode::S_IFREG => {}
  60. /* Reset blocks array. For inode which is not directory or file, just
  61. * fill in blocks with 0 */
  62. _ => {
  63. log::info!("inode_type {:?}", inode_type);
  64. return;
  65. }
  66. }
  67. /* Initialize extents */
  68. inode.set_flags(EXT4_INODE_FLAG_EXTENTS as u32);
  69. /* Initialize extent root header */
  70. inode.extent_tree_init();
  71. // log::info!("inode iblock {:x?}", inode.block);
  72. // inode_ref.dirty = true;
  73. }
  74. /// Allocate a new inode in the filesystem, returning the inode and its number
  75. pub fn alloc_inode(&mut self, filetype: FileType) -> Ext4InodeRef {
  76. // Allocate an inode
  77. let is_dir = filetype == FileType::Directory;
  78. let id = self.do_alloc_inode(is_dir);
  79. // Initialize the inode
  80. let mut inode = Ext4Inode::default();
  81. let mode = if filetype == FileType::Directory {
  82. 0o777 | EXT4_INODE_MODE_DIRECTORY as u16
  83. } else if filetype == FileType::SymLink {
  84. 0o777 | EXT4_INODE_MODE_SOFTLINK as u16
  85. } else {
  86. 0o666 | file_type2inode_mode(filetype) as u16
  87. };
  88. inode.set_mode(mode);
  89. if self.super_block.inode_size() > EXT4_GOOD_OLD_INODE_SIZE {
  90. inode.set_extra_isize(self.super_block.extra_size());
  91. }
  92. let mut inode_ref = Ext4InodeRef::new(id, inode);
  93. // Sync the inode to disk
  94. self.write_back_inode_with_csum(&mut inode_ref);
  95. inode_ref
  96. }
  97. /// Allocate a new inode in the filesystem, returning its number.
  98. fn do_alloc_inode(&mut self, is_dir: bool) -> u32 {
  99. let mut bgid = self.last_inode_bg_id;
  100. let bg_count = self.super_block.block_groups_count();
  101. while bgid <= bg_count {
  102. // Load block group descriptor
  103. let mut bg = Ext4BlockGroupDesc::load(
  104. self.block_device.clone(),
  105. &self.super_block,
  106. bgid as usize,
  107. )
  108. .unwrap();
  109. // If there are no free inodes in this block group, try the next one
  110. if bg.free_inodes_count() == 0 {
  111. bgid += 1;
  112. continue;
  113. }
  114. // Load inode bitmap
  115. let inode_bitmap_block = bg.get_inode_bitmap_block(&self.super_block);
  116. let mut raw_data = self
  117. .block_device
  118. .read_offset(inode_bitmap_block as usize * BLOCK_SIZE);
  119. let inode_count = self.super_block.inode_count_in_group(bgid);
  120. let bitmap_size: u32 = inode_count / 0x8;
  121. let mut bitmap_data = &mut raw_data[..bitmap_size as usize];
  122. let mut bitmap = Bitmap::new(&mut bitmap_data);
  123. // Find a free inode
  124. let idx_in_bg = bitmap
  125. .find_and_set_first_clear_bit(0, inode_count as usize)
  126. .unwrap() as u32;
  127. // Update bitmap in disk
  128. self.block_device
  129. .write_offset(inode_bitmap_block as usize * BLOCK_SIZE, &bitmap.as_raw());
  130. bg.set_inode_bitmap_csum(&self.super_block, &bitmap);
  131. // Modify filesystem counters
  132. let free_inodes = bg.free_inodes_count() - 1;
  133. bg.set_free_inodes_count(&self.super_block, free_inodes);
  134. // Increment used directories counter
  135. if is_dir {
  136. let used_dirs = bg.get_used_dirs_count(&self.super_block) - 1;
  137. bg.set_used_dirs_count(&self.super_block, used_dirs);
  138. }
  139. // Decrease unused inodes count
  140. let mut unused = bg.get_itable_unused(&self.super_block);
  141. let free = inode_count - unused as u32;
  142. if idx_in_bg >= free {
  143. unused = inode_count - (idx_in_bg + 1);
  144. bg.set_itable_unused(&self.super_block, unused);
  145. }
  146. bg.sync_to_disk_with_csum(self.block_device.clone(), bgid as usize, &self.super_block);
  147. // Update superblock
  148. self.super_block.decrease_free_inodes_count();
  149. self.super_block.sync_to_disk(self.block_device.clone());
  150. // Compute the absolute i-node number
  151. let inodes_per_group = self.super_block.inodes_per_group();
  152. let inode_num = bgid * inodes_per_group + (idx_in_bg + 1);
  153. log::info!("alloc inode {:x?}", inode_num);
  154. return inode_num;
  155. }
  156. log::info!("no free inode");
  157. 0
  158. }
  159. }