The resizing of the filesystem require multiple operations:
The advantage of migrating data to a new filesystem is that no data can be lost if the migration process is interrupted. The only sensitive operation is the packing of the filesystem. But a simple normal repair using fsckddumbfs can fix any problem.
Block devices are a less flexible to handle than regular files. Even if your a using LVM the resize operation is a lot more complex. Be sure to have a good understanding of how ddumbfs works before to start resizing.
The size of the block addresses used in the index and in the DataFiles are optimized. For example, if the maximum number of block is under 16777216 (16M), the size of the address is stored in 3 bytes to save space. If the new size cross such a boundary the DataFiles must be migrated too. The index is always migrated anyway. This is what migrateddumbfs does.
The size of the IndexFile is defined at creation time and never changes. The position of every entries in the index depend of the total capacity of the filesystem. Any change of the capacity requires to move the entries inside the index.
Increasing the filesystem size don’t require to do anything to the BlockFile. You don’t need to pack it.
To shrink the BlockFile, all blocks allocated beyond the new limit must be moved at the beginning. Any block move require to update its address in the index and in each DataFile. See How does packing works.
Pack will swap all the free blocks at the beginning with used blocks located at the end to finally get all the free space at the end of the BlockFile. After that the BlockFile can be truncated without losing data.
Here is a sample with 10 used blocks:
1
01234567890123456789
AB C DE FG HIJ
Block F, G, H, I and J will be moved to free space at the beginning, blocks A, B, C, D, and E stay at the same place.:
1
01234567890123456789
ABFCGHDEIJ
This is part of my regression suite. They are lot of test operations that you don’t need for a real migration. This show you how it works and how I test it.
I first create a 500Mo ddumbfs filesystem in a temporary directory:
# mkddumbfs -s 500M -B 4k -i '' -b '' -o 1.3 -H TIGER /s0/tmp/ddumbfs
Initialize ddumb filesystem in directory: /s0/tmp/ddumbfs
BlockFile initialized: /s0/tmp/ddumbfs/ddfsblocks
IndexFile initialized: /s0/tmp/ddumbfs/ddfsidx
ddfs.cfg file initialized: /s0/tmp/ddumbfs/ddfs.cfg
ddumbfs initialized in /s0/tmp/ddumbfs
file_header_size: 16
hash: TIGER
hash_size: 24
block_size: 4096
index_block_size: 4096
node_overflow: 1.30
reuse_asap: 0
auto_buffer_flush: 60
auto_sync: 120
partition_size: 524288000
block_count: 128000
addr_size: 3
node_size: 27
node_count: 167177
node_block_count: 1102
freeblock_offset: 65536
freeblock_size: 16000
node_offset: 131072
index_size: 4644864
index_block_count: 1134
root_directory: ddfsroot
block_filename: ddfsblocks
index_filename: ddfsidx
Then mount it:
# ddumbfs /ddumbfs -o parent=/s0/tmp/ddumbfs -o nodio
file_header_size 16
hash TIGER
hash_size 24
block_size 4096
index_block_size 4096
node_overflow 1.30
reuse_asap 0
auto_buffer_flush 60
auto_sync 120
partition_size 524288000
block_count 128000
addr_size 3
node_size 27
node_count 167177
node_block_count 1102
freeblock_offset 65536
freeblock_size 16000
node_offset 131072
index_size 4644864
index_block_count 1134
root_directory ddfsroot
block_filename ddfsblocks
index_filename ddfsidx
hash: TIGER
direct_io: 0 disable
reclaim: 95
writer pool: 2 cpus
root directory: /s0/tmp/ddumbfs/ddfsroot
blockfile: /s0/tmp/ddumbfs/ddfsblocks
indexfile: /s0/tmp/ddumbfs/ddfsidx
Then populate it with some test files. testddumbfs creates files with random data that can be checked later:
# testddumbfs -o F -B 4096 -S 300M -f -m 0x0 -s 2 /ddumbfs/file2 &
# testddumbfs -o F -B 4096 -S 50M -f -m 0x0 -s 1 /ddumbfs/file1
# testddumbfs -o F -B 4096 -S 50M -f -m 0x0 -s 3 /ddumbfs/file3
# wait
Process are running in parallel and blocks are mixed in the BlockFiles. Now I remove the big one and umount the filesystem:
# rm -f /ddumbfs/file2
# umount /ddumbfs
I check the filesystem integrity:
# fsckddumbfs -C /s0/tmp/ddumbfs
root directory: /s0/tmp/ddumbfs/ddfsroot
blockfile: /s0/tmp/ddumbfs/ddfsblocks
indexfile: /s0/tmp/ddumbfs/ddfsidx
started 2 hashing thread(s)
== Check index
== Checked 167177 nodes in 0.0s
== Check block hash
== Checked 102402 blocks in 3.5s
== Check unmatching 0 block
== Checked 0 unmatching blocks in 0.0s
== Read files
== Read 2 files in 0.1s
filesystem cleanly shut down: skip 'last recently added' blocks check
== Summary
Used blocks : 102402
Free blocks : 25598
Last used blocks : 102401
Total blocks : 128000
Blocks usage : ********0.
Index errors : 0 OK
Index blocks : 102402
Index blocks dup : 0 OK
Block errors : 0 OK
Files : 2
Files errors : 0 OK
Files blocks : 25602
Files lost blocks : 0 OK
Tested hashes : 0
Wrong hashes : 0 OK
in index & not in files : 76800 OK can be reclaimed
in files & not in index : 0 OK
in files & in index : 25602
in blocks & not in files : 76800 OK can be reclaimed
in files & not in blocks : 0 OK
Filesystem status : OK blocks can be reclaimed
As you can see in the Blocks usage line, the first 80% of the BlocFile is full. 0 means than between 0 and 10% of the part is filled. . (a dot) means the part is completely empty. You can also see that 76800 blocks can be reclaimed.
Now I reclaims the free space and pack the BlockFile. Any non *read-only fsckddumbfs operation reclaims the free blocks, here I choose -n for a normal repair. The -k is for pack:
# fsckddumbfs -n -v -p -k /s0/tmp/ddumbfs
root directory: /s0/tmp/ddumbfs/ddfsroot
blockfile: /s0/tmp/ddumbfs/ddfsblocks
indexfile: /s0/tmp/ddumbfs/ddfsidx
04:21:25 INF Check and repair node order in index: fixed 0 errors.
04:21:25 INF Search files for nodes missing in the index.
04:21:25 INF Read 2 files in 0.0s.
04:21:25 INF 25602 blocks used in files.
04:21:25 INF 0 more suspect blocks.
04:21:25 INF Found 0 duplicate addresses in index.
04:21:25 INF filesystem cleanly shut down: skip 'last recently added' blocks check
04:21:25 INF Re-hash all 0 suspect blocks.
04:21:25 INF Re-hash errors: 0
04:21:25 INF Fix files.
04:21:25 INF Calculated 0 hashes.
04:21:25 INF Fixed:0 Corrupted:0 Total:2 files in 0.0s.
04:21:25 INF Deleted 76800 useless nodes.
04:21:25 INF blocks in use: 25602 blocks free: 102398.
04:21:25 INF 102402 blocks used in nodes.
04:21:25 INF Resolve Index conflicts and re-hash 0 suspect blocks.
04:21:25 INF 0 nodes fixed.
Pack
== Move 12804 (used=25602, total=128000) blocks to the beginning.
== Update files
== Updated 2 files in 0.1s
Update index
Update free block list
OK
You can see that 76800 node have been deleted. 76800*4k=300Mo, this our 300Mo file that we have deleted. Rerun fsckddumbfs to see what happened:
# fsckddumbfs -c -v -p /s0/tmp/ddumbfs
root directory: /s0/tmp/ddumbfs/ddfsroot
blockfile: /s0/tmp/ddumbfs/ddfsblocks
indexfile: /s0/tmp/ddumbfs/ddfsidx
== Check index
== Checked 167177 nodes in 0.0s
== Read files
== Read 2 files in 0.1s
filesystem cleanly shut down: skip 'last recently added' blocks check
== Summary
Used blocks : 25602
Free blocks : 102398
Last used blocks : 25601
Total blocks : 128000
Blocks usage : **0.......
Index errors : 0 OK
Index blocks : 25602
Index blocks dup : 0 OK
Block errors : 0 OK
Files : 2
Files errors : 0 OK
Files blocks : 25602
Files lost blocks : 0 OK
Tested hashes : 0
Wrong hashes : 0 OK
in index & not in files : 0 OK
in files & not in index : 0 OK
in files & in index : 25602
in blocks & not in files : 0 OK
in files & not in blocks : 0 OK
Filesystem status : OK
OK
The last 70% of the BlockFile are completely empty (line Blocks usage ). I mount the filesystem to check the file integrity and see if packing was fine:
# ddumbfs /ddumbfs -o parent=/s0/tmp/ddumbfs -o nodio
file_header_size 16
hash TIGER
hash_size 24
block_size 4096
index_block_size 4096
node_overflow 1.30
reuse_asap 0
auto_buffer_flush 60
auto_sync 120
partition_size 524288000
block_count 128000
addr_size 3
node_size 27
node_count 167177
node_block_count 1102
freeblock_offset 65536
freeblock_size 16000
node_offset 131072
index_size 4644864
index_block_count 1134
root_directory ddfsroot
block_filename ddfsblocks
index_filename ddfsidx
hash: TIGER
direct_io: 0 disable
reclaim: 95
writer pool: 2 cpus
root directory: /s0/tmp/ddumbfs/ddfsroot
blockfile: /s0/tmp/ddumbfs/ddfsblocks
indexfile: /s0/tmp/ddumbfs/ddfsidx
First I will add some new files to be sure they will not overwrite existing data:
# testddumbfs -o F -B 4096 -S 15M -f -m 0x0 -s 4 /ddumbfs/file4
# testddumbfs -o F -B 4096 -S 15M -f -m 0x0 -s 5 /ddumbfs/file5
# testddumbfs -o F -B 4096 -S 50M -f -m 0x0 -s 2 /ddumbfs/file2
And then test old and new files:
# testddumbfs -o C -B 4096 -S 50M -f -m 0x0 -s 1 /ddumbfs/file1
# testddumbfs -o C -B 4096 -S 50M -f -m 0x0 -s 2 /ddumbfs/file2
# testddumbfs -o C -B 4096 -S 50M -f -m 0x0 -s 3 /ddumbfs/file3
# testddumbfs -o C -B 4096 -S 15M -f -m 0x0 -s 4 /ddumbfs/file4
# testddumbfs -o C -B 4096 -S 15M -f -m 0x0 -s 5 /ddumbfs/file5
The packing is a success ! Now I start migrating the data to a new filesystem:
# umount /ddumbfs
# mv /s0/tmp/ddumbfs /s0/tmp/ddumbfs.save
# mkdir /s0/tmp/ddumbfs
Then I create a smaller filesystem. 240Mo is smaller than 256Mo=65K*4Ko. This means that in this tiny filesystem, block addresses are only 2 bytes long:
# mkddumbfs -s 240M -B 4k -i '' -b '' -o 1.3 -H TIGER /s0/tmp/ddumbfs
Initialize ddumb filesystem in directory: /s0/tmp/ddumbfs
BlockFile initialized: /s0/tmp/ddumbfs/ddfsblocks
IndexFile initialized: /s0/tmp/ddumbfs/ddfsidx
ddfs.cfg file initialized: /s0/tmp/ddumbfs/ddfs.cfg
ddumbfs initialized in /s0/tmp/ddumbfs
file_header_size: 16
hash: TIGER
hash_size: 24
block_size: 4096
index_block_size: 4096
node_overflow: 1.30
reuse_asap: 0
auto_buffer_flush: 60
auto_sync: 120
partition_size: 251658240
block_count: 61440
addr_size: 2
node_size: 26
node_count: 80659
node_block_count: 512
freeblock_offset: 65536
freeblock_size: 7680
node_offset: 131072
index_size: 2228224
index_block_count: 544
root_directory: ddfsroot
block_filename: ddfsblocks
index_filename: ddfsidx
And I migrate the filesystem using the migrateddumbfs command:
# migrateddumbfs -v -p /s0/tmp/ddumbfs.save /s0/tmp/ddumbfs
mounting destination: /s0/tmp/ddumbfs
file_header_size 16
hash TIGER
hash_size 24
block_size 4096
index_block_size 4096
node_overflow 1.30
reuse_asap 0
auto_buffer_flush 60
auto_sync 120
partition_size 251658240
block_count 61440
addr_size 2
node_size 26
node_count 80659
node_block_count 512
freeblock_offset 65536
freeblock_size 7680
node_offset 131072
index_size 2228224
index_block_count 544
root_directory ddfsroot
block_filename ddfsblocks
index_filename ddfsidx
mounting source: /s0/tmp/ddumbfs.save
check source and destination compatibility
== migrating index
migrate bit list
migrating free block list
== migrating file
== Migrated 5 files in 0.0s
don't forget to handle the blockfile manually
Now I must manually handle the BlockFile:
# mv /s0/tmp/ddumbfs.save/ddfsblocks /s0/tmp/ddumbfs/ddfsblocks
Thats it ! I can mount the filesystem and check once more for the filesystem integrity:
# ddumbfs /ddumbfs -o parent=/s0/tmp/ddumbfs -o nodio
file_header_size 16
hash TIGER
hash_size 24
block_size 4096
index_block_size 4096
node_overflow 1.30
reuse_asap 0
auto_buffer_flush 60
auto_sync 120
partition_size 251658240
block_count 61440
addr_size 2
node_size 26
node_count 80659
node_block_count 512
freeblock_offset 65536
freeblock_size 7680
node_offset 131072
index_size 2228224
index_block_count 544
root_directory ddfsroot
block_filename ddfsblocks
index_filename ddfsidx
hash: TIGER
direct_io: 0 disable
reclaim: 95
writer pool: 2 cpus
root directory: /s0/tmp/ddumbfs/ddfsroot
blockfile: /s0/tmp/ddumbfs/ddfsblocks
indexfile: /s0/tmp/ddumbfs/ddfsidx
# testddumbfs -o C -B 4096 -S 50M -f -m 0x0 -s 1 /ddumbfs/file1
# testddumbfs -o C -B 4096 -S 50M -f -m 0x0 -s 2 /ddumbfs/file2
# testddumbfs -o C -B 4096 -S 50M -f -m 0x0 -s 3 /ddumbfs/file3
# testddumbfs -o C -B 4096 -S 15M -f -m 0x0 -s 4 /ddumbfs/file4
# testddumbfs -o C -B 4096 -S 15M -f -m 0x0 -s 5 /ddumbfs/file5
That’s it