Conversione di file sparsi in non sparsi in atto


8

Su Linux, dato un file sparse, come renderlo non sparse, sul posto?
Potrebbe essere copiato cp --sparse=never ..., ma se il file dice 10G e il buco è 2G (ovvero lo spazio allocato è 8G), come fare per assegnare al file system il rimanente 2G senza copiare l'8G originale in un nuovo file?

Risposte:


11

A prima vista, è un semplice dd:

dd if=sparsefile of=sparsefile conv=notrunc bs=1M

Questo legge l'intero file e vi riscrive l'intero contenuto.

Per scrivere solo il buco stesso, devi prima determinare dove si trovano quei buchi. Puoi farlo usando filefrago hdparm:

filefrag:

# filefrag -e sparsefile
Filesystem type is: 58465342
File size of sparsefile is 10737418240 (2621440 blocks of 4096 bytes)
 ext:     logical_offset:        physical_offset: length:   expected: flags:
   0:        0.. 1048575:  187357696.. 188406271: 1048576:            
   1:  1572864.. 2621439:  200704128.. 201752703: 1048576:  188406272: last,eof
sparsefile: 2 extents found

hdparm:

# hdparm --fibmap sparsefile

sparsefile:
 filesystem blocksize 4096, begins at LBA 0; assuming 512 byte sectors.
 byte_offset  begin_LBA    end_LBA    sectors
           0 1498861568 1507250175    8388608
  6442450944 1605633024 1614021631    8388608

Questo file di esempio è, come dici tu, 10Gdi dimensioni con un 2Gbuco. Ha due estensioni, la prima che copre 0-1048575, la seconda 1572864-2621439, il che significa che il foro è 1048576-1572864(in blocchi di dimensioni 4k, come mostrato da filefrag). Le informazioni mostrate da hdparmsono le stesse, visualizzate in modo diverso (la prima estensione copre 8388608settori a 512 byte a partire da 0, quindi sono 0-4294967295byte, quindi il foro è 4294967296-6442450944in byte.

Tieni presente che in caso di frammentazione potrebbero essere mostrate molte più estensioni. Sfortunatamente, nessun comando mostra direttamente i buchi e non ne conosco uno che lo faccia, quindi devi dedurlo dagli offset logici mostrati.

Ora, riempiendo quel 1048576-1572864buco con ddcome mostrato sopra, può essere fatto aggiungendo appropriati (identici) seek/ skipvalori e count. Si noti che è bs=stato adattato per utilizzare i 4ksettori utilizzati in filefragprecedenza. (Per bs=1M, dovresti adattare i valori seek / skip / count per riflettere 1Mblocchi di dimensioni).

dd if=sparsefile of=sparsefile conv=notrunc \
   bs=4k seek=1048576 skip=1048576 count=$((-1048576+1572864))

Mentre potresti riempire i buchi /dev/zeroinvece di leggere il buco del file stesso (il che produrrà anche zero), è comunque più sicuro leggere da sparsefilecosì non corromperai i tuoi dati nel caso in cui tu abbia sbagliato un offset.

Nelle versioni più recenti di GNU dd, è possibile attenersi a una dimensione di blocco più grande e specificare tutti i valori in byte:

dd if=sparsefile of=sparsefile conv=notrunc bs=1M \
   iflag=skip_bytes,count_bytes oflag=seek_bytes \
   seek=4294967296 skip=4294967296 count=$((-4294967296+6442450944))

filefrag dopo averlo eseguito:

# sync
# filefrag -e sparsefile 
Filesystem type is: 58465342
File size of sparsefile is 10737418240 (2621440 blocks of 4096 bytes)
 ext:     logical_offset:        physical_offset: length:   expected: flags:
   0:        0.. 1572863:  187357696.. 188930559: 1572864:            
   1:  1572864.. 2621439:  200704128.. 201752703: 1048576:  188930560: last,eof
sparsefile: 2 extents found

A causa della frammentazione, sono ancora due estensioni. Tuttavia, gli offset logici mostrano che questa volta non ci sono buchi, quindi il file non è più scarso.

Naturalmente, questa ddsoluzione è l'approccio molto manuale alle cose. Se ne hai bisogno su base regolare, sarebbe facile scrivere un piccolo programma che colmi tali lacune. Se esiste già come strumento standard, non ne ho ancora sentito parlare.


Dopotutto c'è uno strumento, fallocatesembra funzionare, dopo una moda:

fallocate -l $(stat --format="%s" sparsefile) sparsefile

Tuttavia, alla fine, nel caso di XFS, mentre alloca area fisica per questo file, non lo azzera. filefragmostra le estensioni assegnate, ma non scritte.

   2:        3..      15:    7628851..   7628863:     13:    7629020: unwritten

Questo non è abbastanza buono se l'intenzione è quella di poter leggere i dati corretti direttamente dal dispositivo a blocchi. Si riserva solo lo spazio di archiviazione necessario per le scritture future.


1
Or cat sparsefile 1<> sparsefile. Potresti essere in grado di utilizzare fallocatesu Linux per evitare di dover scrivere quei byte NUL se tutto ciò che vuoi è lo spazio da allocare.
Stéphane Chazelas,

@ StéphaneChazelas, grazie, dimenticato fallocate. Ha --dig-holesma no --fill-holes. Tuttavia, sembra funzionare abbastanza bene quando si specifica la dimensione. Modificherò la mia risposta.
frostschutz,

Su NFS o ext3 fallocate non è supportato.
Ivan,

Più recenti fallocatehanno un -zche può essere usato in Linux 3.14 e versioni successive su ext4 e xfs (dovresti eseguirlo con -oe -lper tutte le sezioni sparse suppongo).
Stéphane Chazelas,

@ StéphaneChazelas, sì, ma questo -znon mantiene i tuoi dati se ti capita di avere un offset sbagliato, quindi mi dd
atterrò
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.