Aloca arquivo em um deslocamento específico em ext3 / 4

3

Para fins de teste e benchmark, preciso poder alocar um arquivo em um deslocamento específico a partir do início da partição. Quando eu crio um novo arquivo normalmente, seus blocos são colocados onde quer que o sistema de arquivos decida, mas eu quero controlar isso. Em outras palavras, quero escolher manualmente quais blocos são atribuídos a um arquivo.

Eu olhei para debugfs, mas não consigo encontrar nenhuma maneira de fazer o que eu quero. Embora eu possa marcar blocos como alocados e modificar o inode, isso só funciona nos primeiros 12 blocos. Depois disso, eu preciso ser capaz de criar blocos indiretos e indiretos, o que não parece que o debugfs tenha capacidade.

Existe alguma maneira de fazer isso? Alguma ferramenta que poderia me ajudar? Você pode assumir que o sistema de arquivos é ext3 ou ext4 e que foi recém-formatado (nenhum outro arquivo existe).

Obrigado antecipadamente.

    
por Sven 19.09.2011 / 04:28

2 respostas

2

Eu consegui encontrar uma maneira de fazer isso. Ele usa um script python que primeiro usa debugfs para encontrar o número necessário de blocos (incluindo blocos indiretos) que o arquivo precisará. Em seguida, grava manualmente os blocos indiretos no disco e invoca debugfs novamente para marcar os blocos usados e atualizar o inode do arquivo.

O único problema é que debugfs aparentemente não atualiza a contagem de blocos livres do grupo de blocos quando você usa setb . Embora eu possa definir esse parâmetro manualmente, parece não haver nenhuma maneira de imprimir o valor atual, portanto, não consigo calcular o valor correto. Tanto quanto eu posso dizer que não tem quaisquer consequências negativas reais, e fsck.ext3 pode ser usado para corrigir os valores, se necessário, então, para fins de benchmark, isso será suficiente.

Se houver algum outro problema de consistência do sistema de arquivos que eu tenha perdido, avise-me, mas como fsck.ext3 não informa nada além da contagem incorreta de blocos livres, eu devo estar seguro.

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)

O script pode ser usado da seguinte forma para criar um arquivo de 1 GB no deslocamento de 200 GB (você precisa ser root):

touch /mount/point/myfile
sync
python ext3allocfile.py /dev/sdb1 /myfile 1024 204800
umount /dev/sdb1
mount /dev/sdb1

O umount / mount combo é necessário para fazer o sistema reconhecer a mudança. Você pode desmontar antes de invocar o script, mas isso invoca debugfs mais devagar.

Se alguém quiser usar isso: não garanto que funcionará corretamente, não assumo a responsabilidade se você perder algum dado. Em geral, não use em um sistema de arquivos que contenha algo importante.

    
por 20.09.2011 / 06:58
0

Esta não é a resposta que você quer, e eu percebo isso. mas o método é o sistema de arquivos independente.

APENAS UMA VEZ

encontre o tamanho do bloco; faça um loop em torno da criação de arquivos desse tamanho de bloco do início ao fim; Uma vez feito; exclua todos os arquivos exceto o (s) desejado (s).

Uma vez feito, faça uma cópia bruta do dispositivo em um arquivo compactado

dd if=/dev/sdp1 |bzip2 -9 > /tmp/my-fs-image.bz2

Voila! Uma imagem do sistema de arquivos que não é realmente grande e tem apenas um bloco no onde você quiser. alocado.

para restaurar, crie uma partição com exatamente o mesmo número / tamanho físico blocos de disco

bzip2 -d < /tmp/my-fs-image.bz2|dd of=/dev/sdq1

Na primeira vez, será um incômodo.

    
por 26.02.2012 / 01:44