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", request do_bmap, "Calculate the logical->physical block mapping for an inode",
bmap; bmap;
request do_fallocate, "Allocate uninitialized blocks to an inode",
fallocate;
request do_punch, "Punch (or truncate) blocks from an inode by deallocating them", request do_punch, "Punch (or truncate) blocks from an inode by deallocating them",
punch, truncate; punch, truncate;

View File

@ -306,6 +306,13 @@ from the file \fIfilespec\fR.
Expand the directory Expand the directory
.IR filespec . .IR filespec .
.TP .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] ..." .BI feature " [fs_feature] [-fs_feature] ..."
Set or clear various filesystem features in the superblock. After setting Set or clear various filesystem features in the superblock. After setting
or clearing any filesystem features that were requested, print the current 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; 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 */ #endif /* READ_ONLY */
void do_symlink(int argc, char *argv[]) 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_set_current_time(int argc, char **argv);
extern void do_supported_features(int argc, char **argv); extern void do_supported_features(int argc, char **argv);
extern void do_punch(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_symlink(int argc, char **argv);
extern void do_dump_mmp(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