debugfs: implement fallocate

Implement a fallocate function for debugfs, and add some tests to
demonstrate that it works (more or less).

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
debian
Darrick J. Wong 2015-06-10 20:01:24 -04:00 committed by Theodore Ts'o
parent 4f868703f6
commit 2f8c0d028c
13 changed files with 544 additions and 0 deletions

View File

@ -157,6 +157,9 @@ request do_dirsearch, "Search a directory for a particular filename",
request do_bmap, "Calculate the logical->physical block mapping for an inode",
bmap;
request do_fallocate, "Allocate uninitialized blocks to an inode",
fallocate;
request do_punch, "Punch (or truncate) blocks from an inode by deallocating them",
punch, truncate;

View File

@ -306,6 +306,13 @@ from the file \fIfilespec\fR.
Expand the directory
.IR filespec .
.TP
.BI fallocate " filespec start_block [end_block]
Allocate and map uninitialized blocks into \fIfilespec\fR between
logical block \fIstart_block\fR and \fIend_block\fR, inclusive. If
\fIend_block\fR is not supplied, this function maps until it runs out
of free disk blocks or the maximum file size is reached. Existing
mappings are left alone.
.TP
.BI feature " [fs_feature] [-fs_feature] ..."
Set or clear various filesystem features in the superblock. After setting
or clearing any filesystem features that were requested, print the current

View File

@ -2195,6 +2195,42 @@ void do_punch(int argc, char *argv[])
return;
}
}
void do_fallocate(int argc, char *argv[])
{
ext2_ino_t ino;
blk64_t start, end;
int err;
errcode_t errcode;
if (common_args_process(argc, argv, 3, 4, argv[0],
"<file> start_blk [end_blk]",
CHECK_FS_RW | CHECK_FS_BITMAPS))
return;
ino = string_to_inode(argv[1]);
if (!ino)
return;
err = strtoblk(argv[0], argv[2], "logical block", &start);
if (err)
return;
if (argc == 4) {
err = strtoblk(argv[0], argv[3], "logical block", &end);
if (err)
return;
} else
end = ~0;
errcode = ext2fs_fallocate(current_fs, EXT2_FALLOCATE_INIT_BEYOND_EOF,
ino, NULL, ~0ULL, start, end - start + 1);
if (errcode) {
com_err(argv[0], errcode,
"while fallocating inode %u from %llu to %llu\n", ino,
(unsigned long long) start, (unsigned long long) end);
return;
}
}
#endif /* READ_ONLY */
void do_symlink(int argc, char *argv[])

View File

@ -166,6 +166,7 @@ extern void do_imap(int argc, char **argv);
extern void do_set_current_time(int argc, char **argv);
extern void do_supported_features(int argc, char **argv);
extern void do_punch(int argc, char **argv);
extern void do_fallocate(int argc, char **argv);
extern void do_symlink(int argc, char **argv);
extern void do_dump_mmp(int argc, char **argv);

BIN
tests/d_fallocate/expect.gz Normal file

Binary file not shown.

1
tests/d_fallocate/name Normal file
View File

@ -0,0 +1 @@
fallocate sparse files and big files

175
tests/d_fallocate/script Normal file
View File

@ -0,0 +1,175 @@
if test -x $DEBUGFS_EXE; then
FSCK_OPT=-fy
OUT=$test_name.log
if [ -f $test_dir/expect.gz ]; then
EXP=$test_name.tmp
gunzip < $test_dir/expect.gz > $EXP
else
EXP=$test_dir/expect
fi
cp /dev/null $OUT
cat > $TMPFILE.conf << ENDL
[fs_types]
ext4 = {
base_features = sparse_super,filetype,resize_inode,dir_index,ext_attr,^has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,64bit
blocksize = 1024
inode_size = 256
inode_ratio = 16384
}
ENDL
MKE2FS_CONFIG=$TMPFILE.conf $MKE2FS -F -o Linux -b 1024 -O ^bigalloc -T ext4 $TMPFILE 65536 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1
rm -rf $TMPFILE.conf
$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1
status=$?
echo Exit status is $status >> $OUT.new
sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT
rm -f $OUT.new
echo "debugfs write files" >> $OUT
make_file() {
name="$1"
start="$2"
flag="$3"
cat << ENDL
write /dev/null $name
sif /$name size 40960
eo /$name
set_bmap $flag 10 $((start + 10))
set_bmap $flag 13 $((start + 13))
set_bmap $flag 26 $((start + 26))
set_bmap $flag 29 $((start + 29))
ec
sif /$name blocks 8
setb $((start + 10))
setb $((start + 13))
setb $((start + 26))
setb $((start + 29))
ENDL
}
#Files we create:
# a: fallocate a 40k file
# b*: falloc sparse file starting at b*
# c*: falloc spare file ending at c*
# d: midcluster to midcluster, surrounding sparse
# e: partial middle cluster alloc
# f: one big file
# g*: falloc sparse init file starting at g*
# h*: falloc sparse init file ending at h*
# i: midcluster to midcluster, surrounding sparse init
# j: partial middle cluster alloc
# k: one big init file
base=5000
cat > $TMPFILE.cmd << ENDL
write /dev/null a
sif /a size 40960
fallocate /a 0 39
ENDL
echo "ex /a" >> $TMPFILE.cmd2
make_file sample $base --uninit >> $TMPFILE.cmd
echo "ex /sample" >> $TMPFILE.cmd2
base=10000
for i in 8 9 10 11 12 13 14 15; do
make_file b$i $(($base + (40 * ($i - 8)))) --uninit >> $TMPFILE.cmd
echo "fallocate /b$i $i 39" >> $TMPFILE.cmd
echo "ex /b$i" >> $TMPFILE.cmd2
done
for i in 24 25 26 27 28 29 30 31; do
make_file c$i $(($base + 320 + (40 * ($i - 24)))) --uninit >> $TMPFILE.cmd
echo "fallocate /c$i 0 $i" >> $TMPFILE.cmd
echo "ex /c$i" >> $TMPFILE.cmd2
done
make_file d $(($base + 640)) --uninit >> $TMPFILE.cmd
echo "fallocate /d 4 35" >> $TMPFILE.cmd
echo "ex /d" >> $TMPFILE.cmd2
make_file e $(($base + 680)) --uninit >> $TMPFILE.cmd
echo "fallocate /e 19 20" >> $TMPFILE.cmd
echo "ex /e" >> $TMPFILE.cmd2
cat >> $TMPFILE.cmd << ENDL
write /dev/null f
sif /f size 1024
eo /f
set_bmap --uninit 0 9000
ec
sif /f blocks 2
setb 9000
fallocate /f 0 8999
ENDL
echo "ex /f" >> $TMPFILE.cmd2
# Now do it again, but with initialized blocks
base=20000
for i in 8 9 10 11 12 13 14 15; do
make_file g$i $(($base + (40 * ($i - 8)))) >> $TMPFILE.cmd
echo "fallocate /g$i $i 39" >> $TMPFILE.cmd
echo "ex /g$i" >> $TMPFILE.cmd2
done
for i in 24 25 26 27 28 29 30 31; do
make_file h$i $(($base + 320 + (40 * ($i - 24)))) >> $TMPFILE.cmd
echo "fallocate /h$i 0 $i" >> $TMPFILE.cmd
echo "ex /h$i" >> $TMPFILE.cmd2
done
make_file i $(($base + 640)) >> $TMPFILE.cmd
echo "fallocate /i 4 35" >> $TMPFILE.cmd
echo "ex /i" >> $TMPFILE.cmd2
make_file j $(($base + 680)) >> $TMPFILE.cmd
echo "fallocate /j 19 20" >> $TMPFILE.cmd
echo "ex /j" >> $TMPFILE.cmd2
cat >> $TMPFILE.cmd << ENDL
write /dev/null k
sif /k size 1024
eo /k
set_bmap 0 19000
ec
sif /k blocks 2
setb 19000
fallocate /k 0 8999
sif /k size 9216000
ENDL
echo "ex /k" >> $TMPFILE.cmd2
$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE > /dev/null 2>&1
$DEBUGFS_EXE -f $TMPFILE.cmd2 $TMPFILE >> $OUT.new 2>&1
sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT
rm -rf $OUT.new $TMPFILE.cmd $TMPFILE.cmd2
$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1
status=$?
echo Exit status is $status >> $OUT.new
sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT
rm -f $OUT.new
rm -f $TMPFILE
cmp -s $OUT $EXP
status=$?
if [ "$status" = 0 ] ; then
echo "$test_name: $test_description: ok"
touch $test_name.ok
else
echo "$test_name: $test_description: failed"
diff $DIFF_OPTS $EXP $OUT > $test_name.failed
rm -f $test_name.tmp
fi
unset IMAGE FSCK_OPT OUT EXP
else #if test -x $DEBUGFS_EXE; then
echo "$test_name: $test_description: skipped"
fi

Binary file not shown.

View File

@ -0,0 +1 @@
fallocate sparse files and big files with bigalloc

View File

@ -0,0 +1,176 @@
if test -x $DEBUGFS_EXE; then
FSCK_OPT=-fy
OUT=$test_name.log
if [ -f $test_dir/expect.gz ]; then
EXP=$test_name.tmp
gunzip < $test_dir/expect.gz > $EXP
else
EXP=$test_dir/expect
fi
cp /dev/null $OUT
cat > $TMPFILE.conf << ENDL
[fs_types]
ext4 = {
cluster_size = 8192
base_features = sparse_super,filetype,resize_inode,dir_index,ext_attr,^has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,64bit
blocksize = 1024
inode_size = 256
inode_ratio = 16384
}
ENDL
MKE2FS_CONFIG=$TMPFILE.conf $MKE2FS -F -o Linux -b 1024 -O bigalloc -T ext4 $TMPFILE 65536 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1
rm -rf $TMPFILE.conf
$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1
status=$?
echo Exit status is $status >> $OUT.new
sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT
rm -f $OUT.new
echo "debugfs write files" >> $OUT
make_file() {
name="$1"
start="$2"
flag="$3"
cat << ENDL
write /dev/null $name
sif /$name size 40960
eo /$name
set_bmap $flag 10 $((start + 10))
set_bmap $flag 13 $((start + 13))
set_bmap $flag 26 $((start + 26))
set_bmap $flag 29 $((start + 29))
ec
sif /$name blocks 32
setb $((start + 10))
setb $((start + 13))
setb $((start + 26))
setb $((start + 29))
ENDL
}
#Files we create:
# a: fallocate a 40k file
# b*: falloc sparse file starting at b*
# c*: falloc spare file ending at c*
# d: midcluster to midcluster, surrounding sparse
# e: partial middle cluster alloc
# f: one big file
# g*: falloc sparse init file starting at g*
# h*: falloc sparse init file ending at h*
# i: midcluster to midcluster, surrounding sparse init
# j: partial middle cluster alloc
# k: one big init file
base=5000
cat > $TMPFILE.cmd << ENDL
write /dev/null a
sif /a size 40960
fallocate /a 0 39
ENDL
echo "ex /a" >> $TMPFILE.cmd2
make_file sample $base --uninit >> $TMPFILE.cmd
echo "ex /sample" >> $TMPFILE.cmd2
base=10000
for i in 8 9 10 11 12 13 14 15; do
make_file b$i $(($base + (40 * ($i - 8)))) --uninit >> $TMPFILE.cmd
echo "fallocate /b$i $i 39" >> $TMPFILE.cmd
echo "ex /b$i" >> $TMPFILE.cmd2
done
for i in 24 25 26 27 28 29 30 31; do
make_file c$i $(($base + 320 + (40 * ($i - 24)))) --uninit >> $TMPFILE.cmd
echo "fallocate /c$i 0 $i" >> $TMPFILE.cmd
echo "ex /c$i" >> $TMPFILE.cmd2
done
make_file d $(($base + 640)) --uninit >> $TMPFILE.cmd
echo "fallocate /d 4 35" >> $TMPFILE.cmd
echo "ex /d" >> $TMPFILE.cmd2
make_file e $(($base + 680)) --uninit >> $TMPFILE.cmd
echo "fallocate /e 19 20" >> $TMPFILE.cmd
echo "ex /e" >> $TMPFILE.cmd2
cat >> $TMPFILE.cmd << ENDL
write /dev/null f
sif /f size 1024
eo /f
set_bmap --uninit 0 9000
ec
sif /f blocks 16
setb 9000
fallocate /f 0 8999
ENDL
echo "ex /f" >> $TMPFILE.cmd2
# Now do it again, but with initialized blocks
base=20000
for i in 8 9 10 11 12 13 14 15; do
make_file g$i $(($base + (40 * ($i - 8)))) >> $TMPFILE.cmd
echo "fallocate /g$i $i 39" >> $TMPFILE.cmd
echo "ex /g$i" >> $TMPFILE.cmd2
done
for i in 24 25 26 27 28 29 30 31; do
make_file h$i $(($base + 320 + (40 * ($i - 24)))) >> $TMPFILE.cmd
echo "fallocate /h$i 0 $i" >> $TMPFILE.cmd
echo "ex /h$i" >> $TMPFILE.cmd2
done
make_file i $(($base + 640)) >> $TMPFILE.cmd
echo "fallocate /i 4 35" >> $TMPFILE.cmd
echo "ex /i" >> $TMPFILE.cmd2
make_file j $(($base + 680)) >> $TMPFILE.cmd
echo "fallocate /j 19 20" >> $TMPFILE.cmd
echo "ex /j" >> $TMPFILE.cmd2
cat >> $TMPFILE.cmd << ENDL
write /dev/null k
sif /k size 1024
eo /k
set_bmap 0 19000
ec
sif /k blocks 16
setb 19000
fallocate /k 0 8999
sif /k size 9216000
ENDL
echo "ex /k" >> $TMPFILE.cmd2
$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE > /dev/null 2>&1
$DEBUGFS_EXE -f $TMPFILE.cmd2 $TMPFILE >> $OUT.new 2>&1
sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT
rm -rf $OUT.new $TMPFILE.cmd $TMPFILE.cmd2
$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1
status=$?
echo Exit status is $status >> $OUT.new
sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT
rm -f $OUT.new
rm -f $TMPFILE
cmp -s $OUT $EXP
status=$?
if [ "$status" = 0 ] ; then
echo "$test_name: $test_description: ok"
touch $test_name.ok
else
echo "$test_name: $test_description: failed"
diff $DIFF_OPTS $EXP $OUT > $test_name.failed
rm -f $test_name.tmp
fi
unset IMAGE FSCK_OPT OUT EXP
else #if test -x $DEBUGFS_EXE; then
echo "$test_name: $test_description: skipped"
fi

View File

@ -0,0 +1,58 @@
Creating filesystem with 65536 1k blocks and 4096 inodes
Superblock backups stored on blocks:
8193, 24577, 40961, 57345
Allocating group tables: done
Writing inode tables: done
Writing superblocks and filesystem accounting information: done
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
test_filesys: 11/4096 files (0.0% non-contiguous), 2340/65536 blocks
Exit status is 0
debugfs write files
debugfs: stat /a
Inode: 12 Type: regular Mode: 0666 Flags: 0x0
Generation: 0 Version: 0x00000000:00000000
User: 0 Group: 0 Size: 40960
File ACL: 0 Directory ACL: 0
Links: 1 Blockcount: 82
Fragment: Address: 0 Number: 0 Size: 0
Size of extra inode fields: 28
BLOCKS:
(0-1):1312-1313, (2-11):8000-8009, (IND):8010, (12-39):8011-8038
TOTAL: 41
debugfs: stat /b
Inode: 13 Type: regular Mode: 0666 Flags: 0x0
Generation: 0 Version: 0x00000000:00000000
User: 0 Group: 0 Size: 10240000
File ACL: 0 Directory ACL: 0
Links: 1 Blockcount: 20082
Fragment: Address: 0 Number: 0 Size: 0
Size of extra inode fields: 28
BLOCKS:
(0-11):10000-10011, (IND):10012, (12-267):10013-10268, (DIND):10269, (IND):10270, (268-523):10271-10526, (IND):10527, (524-779):10528-10783, (IND):10784, (780-1035):10785-11040, (IND):11041, (1036-1291):11042-11297, (IND):11298, (1292-1547):11299-11554, (IND):11555, (1548-1803):11556-11811, (IND):11812, (1804-2059):11813-12068, (IND):12069, (2060-2315):12070-12325, (IND):12326, (2316-2571):12327-12582, (IND):12583, (2572-2827):12584-12839, (IND):12840, (2828-3083):12841-13096, (IND):13097, (3084-3339):13098-13353, (IND):13354, (3340-3595):13355-13610, (IND):13611, (3596-3851):13612-13867, (IND):13868, (3852-4107):13869-14124, (IND):14125, (4108-4363):14126-14381, (IND):14382, (4364-4619):14383-14638, (IND):14639, (4620-4875):14640-14895, (IND):14896, (4876-5131):14897-15152, (IND):15153, (5132-5387):15154-15409, (IND):15410, (5388-5643):15411-15666, (IND):15667, (5644-5899):15668-15923, (IND):15924, (5900-6155):15925-16180, (IND):16181, (6156-6411):16182-16437, (IND):16438, (6412-6667):16439-16694, (IND):16695, (6668-6923):16696-16951, (IND):16952, (6924-7179):16953-17208, (IND):17209, (7180-7435):17210-17465, (IND):17466, (7436-7691):17467-17722, (IND):17723, (7692-7947):17724-17979, (IND):17980, (7948-8203):17981-18236, (IND):18237, (8204-8459):18238-18493, (IND):18494, (8460-8715):18495-18750, (IND):18751, (8716-8971):18752-19007, (IND):19008, (8972-9227):19009-19264, (IND):19265, (9228-9483):19266-19521, (IND):19522, (9484-9739):19523-19778, (IND):19779, (9740-9995):19780-20035, (IND):20036, (9996-9999):20037-20040
TOTAL: 10041
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
Free blocks count wrong for group #0 (6841, counted=6840).
Fix? yes
Free blocks count wrong for group #1 (1551, counted=1550).
Fix? yes
Free blocks count wrong (53116, counted=53114).
Fix? yes
test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
test_filesys: 13/4096 files (7.7% non-contiguous), 12422/65536 blocks
Exit status is 1

View File

@ -0,0 +1 @@
fallocate sparse files and big files on a blockmap fs

View File

@ -0,0 +1,85 @@
if test -x $DEBUGFS_EXE; then
FSCK_OPT=-fy
OUT=$test_name.log
if [ -f $test_dir/expect.gz ]; then
EXP=$test_name.tmp
gunzip < $test_dir/expect.gz > $EXP1
else
EXP=$test_dir/expect
fi
cp /dev/null $OUT
cat > $TMPFILE.conf << ENDL
[fs_types]
ext4 = {
base_features = sparse_super,filetype,resize_inode,dir_index,ext_attr,^has_journal,^extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,^64bit
blocksize = 1024
inode_size = 256
inode_ratio = 16384
}
ENDL
MKE2FS_CONFIG=$TMPFILE.conf $MKE2FS -F -o Linux -b 1024 -O ^bigalloc -T ext4 $TMPFILE 65536 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1
rm -rf $TMPFILE.conf
$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1
status=$?
echo Exit status is $status >> $OUT.new
sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT
rm -f $OUT.new
echo "debugfs write files" >> $OUT
#Files we create:
# a: fallocate a 40k file
# k: one big file
base=5000
cat > $TMPFILE.cmd << ENDL
write /dev/null a
sif /a bmap[2] 8000
sif /a size 40960
sif /a i_blocks 2
setb 8000
fallocate /a 0 39
write /dev/null b
sif /b size 10240000
sif /b bmap[0] 10000
sif /b i_blocks 2
setb 10000
fallocate /b 0 9999
ENDL
echo "stat /a" >> $TMPFILE.cmd2
echo "stat /b" >> $TMPFILE.cmd2
$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE > /dev/null 2>&1
$DEBUGFS_EXE -f $TMPFILE.cmd2 $TMPFILE >> $OUT.new 2>&1
sed -f $cmd_dir/filter.sed -e '/^.*time:.*$/d' < $OUT.new >> $OUT
rm -rf $OUT.new $TMPFILE.cmd $TMPFILE.cmd2
$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1
status=$?
echo Exit status is $status >> $OUT.new
sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT
rm -f $OUT.new
rm -f $TMPFILE
cmp -s $OUT $EXP
status=$?
if [ "$status" = 0 ] ; then
echo "$test_name: $test_description: ok"
touch $test_name.ok
else
echo "$test_name: $test_description: failed"
diff $DIFF_OPTS $EXP $OUT > $test_name.failed
rm -f $test_name.tmp
fi
unset IMAGE FSCK_OPT OUT EXP
else #if test -x $DEBUGFS_EXE; then
echo "$test_name: $test_description: skipped"
fi