Debian
在 ext3/4 中的特定偏移處分配文件
出於基準測試和測試目的,我需要能夠在從分區開始的特定偏移量處分配文件。當我正常創建一個新文件時,它的塊被放置在文件系統決定的任何地方,但我想控制它。換句話說,我想手動選擇分配給文件的塊。
我查看了 debugfs,但找不到任何方法來做我想做的事。雖然我可以將塊標記為已分配並修改 inode,但這僅適用於前 12 個塊。之後,我還需要能夠創建間接和雙重間接塊,看起來 debugfs 沒有任何能力。
有沒有辦法做到這一點?有什麼工具可以幫助我嗎?您可以假設文件系統是 ext3 或 ext4 並且它已經被重新格式化(不存在其他文件)。
提前致謝。
我設法找到了一種方法來做到這一點。它使用一個 python 腳本,該腳本首先用於
debugfs
查找文件需要的必要塊數(包括間接塊)。然後它手動將間接塊寫入磁碟,並debugfs
再次呼叫以將塊標記為已使用並更新文件的 inode。唯一的問題是,
debugfs
當您使用setb
. 雖然我可以手動設置該參數,但似乎沒有任何方法可以列印目前值,因此我無法計算正確的值。據我所知,它沒有任何真正的負面後果,並且fsck.ext3
可以在需要時用於更正值,因此出於基準目的,它可以做到。如果我遺漏了任何其他文件系統一致性問題,請告訴我,但由於
fsck.ext3
除了不正確的空閒塊計數之外沒有報告任何內容,我應該是安全的。import sys import tempfile import struct import subprocess SECTOR_SIZE = 512 BLOCK_SIZE = 4096 DIRECT_BLOCKS = 12 BLOCKS_PER_INDIRECT_BLOCK = BLOCK_SIZE / 4 def write_indirect_block(device, indirect_block, blocks): print "writing indirect block ", indirect_block dev = open(device, "wb") dev.seek(indirect_block * BLOCK_SIZE) # Write blocks for block in blocks: bin_block = struct.pack("<I", int(block)) dev.write(bin_block) zero = struct.pack("<I", 0) # Zero out the rest of the block for x in range(len(blocks), BLOCKS_PER_INDIRECT_BLOCK): dev.write(zero) dev.close() def main(argv): if len(argv) < 5: print "Usage: ext3allocfile.py [device] [file] [sizeInMB] [offsetInMB]" return device = argv[1] # device containing the ext3 file system, e.g. "/dev/sdb1" file = argv[2] # file name relative to the root of the device, e.g. "/myfile" size = int(argv[3]) * 1024 * 1024 # Size in MB offset = int(argv[4]) * 1024 * 1024 # Offset from the start of the device in MB if size > 0xFFFFFFFF: # Supporting this requires two things: triple indirect block support, and proper handling of size_high when changing the inode print "Unable to allocate files over 4GB." return # Because size is specified in MB, it should always be exactly divisable by BLOCK_SIZE. size_blocks = size / BLOCK_SIZE # We need 1 indirect block for each 1024 blocks over 12 blocks. ind_blocks = (size_blocks - DIRECT_BLOCKS) / BLOCKS_PER_INDIRECT_BLOCK if (size_blocks - DIRECT_BLOCKS) % BLOCKS_PER_INDIRECT_BLOCK != 0: ind_blocks += 1 # We need a double indirect block if we have more than one indirect block has_dind_block = ind_blocks > 1 total_blocks = size_blocks + ind_blocks if has_dind_block: total_blocks += 1 # Find free blocks we can use at the offset offset_block = offset / BLOCK_SIZE print "Finding ", total_blocks, " free blocks from block ", offset_block process = subprocess.Popen(["debugfs", device, "-R", "ffb %d %d" % (total_blocks, offset_block)], stdout=subprocess.PIPE) output = process.stdout # The first three entries after splitting are "Free", "blocks", "found:", so we skip those. blocks = output.readline().split(" ")[3:] output.close() # The last entry may contain a line-break. Removing it this way to be safe. blocks = filter(lambda x: len(x.strip(" \n")) > 0, blocks) if len(blocks) != total_blocks: print "Not enough free blocks found for the file." return # The direct blocks in the inode are blocks 0-11 # Write the first indirect block, listing the blocks for file blocks 12-1035 (inclusive) if ind_blocks > 0: write_indirect_block(device, int(blocks[DIRECT_BLOCKS]), blocks[DIRECT_BLOCKS + 1 : DIRECT_BLOCKS + 1 + BLOCKS_PER_INDIRECT_BLOCK]) if has_dind_block: dind_block_index = DIRECT_BLOCKS + 1 + BLOCKS_PER_INDIRECT_BLOCK dind_block = blocks[dind_block_index] ind_block_indices = [dind_block_index+1+(i*(BLOCKS_PER_INDIRECT_BLOCK+1)) for i in range(ind_blocks-1)] # Write the double indirect block, listing the blocks for the remaining indirect block write_indirect_block(device, int(dind_block), [blocks[i] for i in ind_block_indices]) # Write the remaining indirect blocks, listing the relevant file blocks for i in ind_block_indices: write_indirect_block(device, int(blocks[i]), blocks[i+1:i+1+BLOCKS_PER_INDIRECT_BLOCK]) # Time to generate a script for debugfs script = tempfile.NamedTemporaryFile(mode = "w", delete = False) # Mark all the blocks as in-use for block in blocks: script.write("setb %s\n" % (block,)) # Change direct blocks in the inode for i in range(DIRECT_BLOCKS): script.write("sif %s block[%d] %s\n" % (file, i, blocks[i])) # Change indirect block in the inode if size_blocks > DIRECT_BLOCKS: script.write("sif %s block[IND] %s\n" % (file, blocks[DIRECT_BLOCKS])) # Change double indirect block in the inode if has_dind_block: script.write("sif %s block[DIND] %s\n" % (file, dind_block)) # Set total number of blocks in the inode (this value seems to actually be sectors script.write("sif %s blocks %d\n" % (file, total_blocks * (BLOCK_SIZE / SECTOR_SIZE))) # Set file size in the inode # TODO: Need support of size_high for large files script.write("sif %s size %d\n" % (file, size)) script.close() # execute the script print "Modifying file" subprocess.call(["debugfs", "-w", device, "-f", script.name]) script.unlink(script.name) if __name__ == "__main__": main(sys.argv)
該腳本可用於在偏移量 200GB 處創建一個 1GB 文件(您需要是 root):
touch /mount/point/myfile sync python ext3allocfile.py /dev/sdb1 /myfile 1024 204800 umount /dev/sdb1 mount /dev/sdb1
umount/mount 組合對於讓系統辨識更改是必要的。您可以在呼叫腳本之前解除安裝,但這會使呼叫
debugfs
速度變慢。如果有人想使用它:我不保證它會正常工作,如果您失去任何數據,我不承擔任何責任。通常,不要在包含任何重要內容的文件系統上使用它。