LTP(Linux Test Project)学习(六)—— 问题分析:chattr命令的限制

(挑选本人之前发现的bug,可以更加深入讲解下问题分析历程)
对应补丁commit:9af831cdf6d2328e6f6fcd85dd1d5523fd8681d3

BUG发现

个人在学习linux或linux相关代码实践时,喜欢使用qemu启动虚拟机(启动快,方便替换内核)。
在刚开始接触ltp时候,便开始跨平台执行ltp(想看下ltp的兼容性),当时FAIL很多用例,然后逐个开始分析,直到utimensat_tests.sh,报错:” chattr: Inappropriate ioctl for device while reading flags on testfile”。

BUG分析

1.初步分析
使用过LTP的都知道,LTP的成功、提示或者失败都伴随着TPASS/TCONF/TFAIL,但是” chattr: Inappropriate ioctl for device while reading flags on testfile”错误前面并没有LTP内置的提示信息标记,所以首次看到就感觉是一个异常情况,用例中未发现的异常情况。

2.问题复现&定位
对于shell脚本的定位方法,最好的办法就是sh –x command方式。
1)首先cd到testcases/bin目录下,直接sh utimensat_tests.sh,这样是为了复现问题。可能会无法执行,原因是需要添加LTP_ROOT环境变量、将脚本中 . xxx.sh改成 . ./xxx.sh(小问题,你可以试着解决)。
2)然后 sh utimensat_tests.sh发现问题既然可以复现,则执sh –x utimensat_tests.sh &>log。 -x参数会将shell脚本的执行流程打印出来,包括中间变量赋值,执行日志导入log。
3)最后打开utimensat_tests.sh和log执行流程每行对比,即可找到报错位置所在(此时双屏更好哦)。
最终发现命令挂在 chattr –ai F I L E ( FILE可以在出错位置添加echo $FILE打印出来)
复现步骤:

# echo "testfile" > testfile
# chattr +a testfile
chattr: Inappropriate ioctl for device while reading flags on testfile

3.问题分析
对于分析问题,个人总结了几种方法,其中按照优先级来说:
google搜索答案 > 查阅特性资料(chattr资料) > 看源码(需要首先明白是linux报错还是chattr错误) > LTP社区发邮件提问

我们一步一步来:
1)google搜索答案(你可以百度试试,基本不会得到你想要的答案)
通过google搜索,可以看到很多相关的报错问题与讨论。对于我们来说,需要每条每条看过去,然后搜索有用信息
比如
https://www.linuxquestions.org/questions/linux-software-2/lsattr-inappropriate-ioctl-for-device-while-reading-flags-910119/

I have turned off Selinux on this computer. So the issue of Selinux should not arise. Thanks

或者
https://bugs.launchpad.net/ubuntu/+source/ecryptfs-utils/+bug/469664

eCryptfs doesn’t support lsattr. It is an ext[345] specific tool that is shipped in e2fsprogs. It simply just isn’t supposed to work on eCryptfs.

等等,其实大部分答案就藏在这里。

中间你可以在你环境本地试试,排除一些可能。比如Selinux,我qemu肯定没装,可以排除;eCryptfs我系统也没有(mount查看文件系统挂载类型),但是中间有很重要的一条信息,” It is an ext[345] specific tool that is shipped in e2fsprogs”,这里It就是指chattr。这条很像,因为我qemu虚拟机的文件系统挂载类型是tmpfs,也就是内存文件系统,并不是ext[345]。
但是以上只是猜测,我们带着猜测继续看下去。

2)查阅特性资料
这里仅讲几个比较好的查阅命令或者系统调用的方式,其实我其他博客也提到过
google chattr:如果你对chattr不了解,建议百度或者google,了解下它是什么功能;
man chattr:官方文档,绝对值得一看;
其他不太建议去看了,有这些足够了。通过上面可以大概分析到chattr是给file追加属性,比如+是增加属性,-是删除。

3) 看源码
linux问题区分是内核态问题还是用户态问题(有不同的报错标志)。对于初学者,推荐strace命令:

#strace chattr +a testfile
…
openat(AT_FDCWD, "testfile", O_RDONLY|O_NONBLOCK) = 3
ioctl(3, FS_IOC32_GETFLAGS or FS_IOC_GETFLAGS, 0xfffffd1b9ca4) = -1 ENOTTY (Inappropriate ioctl for device)
close(3)                                = 0
…

关键报错就在ioctl(3, FS_IOC32_GETFLAGS or FS_IOC_GETFLAGS, 0xfffffd1b9ca4) = -1 ENOTTY (Inappropriate ioctl for device),这个错误是哪里报出来的呢,根据命令走向:命令->相关系统调用实现->libc库->linux内核,我们一项一项搜索。

a. chattr源码

# which chattr
/usr/bin/chattr
# rpm -qf /usr/bin/chattr
e2fsprogs-xxx.aarch64 (我隐藏了版本号哈)

所有命令都可以通过上面方法查阅包来源
然后google对应版本包,下载解压搜索:
对应网址:https://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git
我下载的最新版,理论上要下载跟你对应版本的哈

$ tar -xvf e2fsprogs-1.44.3.tar.gz
$ cd e2fsprogs-1.44.3
$ grep "Inappropriate ioctl for device" -rn *
$ 

其他结果:
glibc:

$ grep "Inappropriate ioctl for device" -rn *
sysdeps/unix/bsd/bsd4.4/bits/errno.h:66:#define ENOTTY          25              /* Inappropriate ioctl for device */
sysdeps/gnu/errlist.c:285:    [ERR_REMAP (ENOTTY)] = N_("Inappropriate ioctl for device"),
sysdeps/mach/hurd/bits/errno.h:63:#define       ENOTTY          _HURD_ERRNO (25)/* Inappropriate ioctl for device */

linux:

$ grep "Inappropriate ioctl for device" -rn *
fs/fat/file.c:137:              return -ENOTTY; /* Inappropriate ioctl for device */

分析后发现没什么太大价值。

4)再回头看官方资料(man chattr)
定位问题就是这样,有可能会直接发现,也有可能会碰壁,没关系,我们再深入看一下(个人认为这时候才是成长经历)。

BUGS AND LIMITATIONS
The ‘c’, ‘s’, and ‘u’ attributes are not honored by the ext2, ext3, and ext4 filesystems as implemented in the current mainline Linux kernels.
The ‘j’ option is only useful if the filesystem is mounted as ext3 or ext4.
The ‘D’ option is only useful on Linux kernel 2.5.19 and later.

还有

Not all flags are supported or utilized by all filesystems; refer to
filesystem-specific man pages such as btrfs(5), ext4(5), and xfs(5)
for more filesystem-specific details.

结合上面的疑问,是不是有点柳暗花明的感觉,并不是所有文件系统类型均支持这个特性。我们做个试验:
挂载ext3文件系统的目录(/dev/sda2 on / type ext3 (rw,relatime)),如下

# cd /
# echo "testfile" > testfile
# chattr +a testfile

挂载tmpfs文件系统的目录(tmpfs on /run type tmpfs )(rw,nosuid,nodev,mode=755),如下

# cd /run
# echo "testfile" > testfile
# chattr +a testfile
chattr: Inappropriate ioctl for device while reading flags on testfile

原来跟文件系统类型有关系呀。后面再查查资料,就会发现attr特性在ext[234]均支持,tmpfs不支持。

提交Patch

具体提交patch方式在我后面的博客(https://blog.csdn.net/cui841923894/article/details/81545627
这里仅贴一下补丁内容(加一个check)

commit 9af831cdf6d2328e6f6fcd85dd1d5523fd8681d3
Author: Cui Bixuan <cuibixuan@huawei.com>
Date:   Wed Apr 29 08:53:40 2015 +0800

    syscalls/utimensat01: "chattr" command error

    The "chattr" command in case failed in some file system(such as memory fs):
    'chattr: Inappropriate ioctl for device while reading flags on'

    I learn that chattr command only can be used in ext2 or ext3 (ext4 is ok now).
    So we check it before running.

    Signed-off-by: Cui Bixuan <cuibixuan@huawei.com>

diff --git a/testcases/kernel/syscalls/utimensat/utimensat_tests.sh b/testcases/kernel/syscalls/utimensat/utimensat_tests.sh
index 6bc2030..6adc042 100755
--- a/testcases/kernel/syscalls/utimensat/utimensat_tests.sh
+++ b/testcases/kernel/syscalls/utimensat/utimensat_tests.sh
@@ -295,6 +295,15 @@ nuke_sudoers()
 }
sudo $s_arg -u $test_user mkdir -p $TEST_DIR
+
+# Make sure chattr command is supported
+touch $TEST_DIR/tmp_file
+chattr +a $TEST_DIR/tmp_file
+if [ $? -ne 0 ] ; then
+       rm -rf $TEST_DIR
+       tst_brkm TCONF "chattr not supported"
+fi
+
 cd $TEST_DIR
 chown root $LTPROOT/testcases/bin/$TEST_PROG
 chmod ugo+x,u+s $LTPROOT/testcases/bin/$TEST_PROG

其他类似:

commit 34bf3e86ab1a14b2d38f5bb4ab2ffae65b5ec68d
Author: Cui Bixuan <cuibixuan@huawei.com>
Date:   Mon May 18 20:40:57 2015 +0800

    open/open12: Check the kernel version for 'MS_STRICTATIME'

    Call tst_kvercmp() to check the kernel version(newer than 2.6.30) before
    calling SAFE_MOUNT( MS_STRICTATIME ).

    Signed-off-by: Cui Bixuan <cuibixuan@huawei.com>

diff --git a/testcases/kernel/syscalls/open/open12.c b/testcases/kernel/syscalls/open/open12.c
index af3fab3..5bbf9ee 100644
--- a/testcases/kernel/syscalls/open/open12.c
+++ b/testcases/kernel/syscalls/open/open12.c
@@ -90,6 +90,14 @@ static void setup(void)
        if (tst_path_has_mnt_flags(cleanup, NULL, mount_flags)) {
                const char *fs_type;

+               if ((tst_kvercmp(2, 6, 30)) < 0) {
+                       tst_resm(TCONF,
+                               "MS_STRICTATIME flags for mount(2) needs kernel 2.6.30 "
+                               "or higher");
+                       skip_noatime = 1;
+                       return;
+               }
+

源于

man mount(2)
MS_STRICTATIME (since Linux 2.6.30)
              Always  update  the last access time (atime) when files on this filesystem are accessed.  (This was the default behavior before Linux 2.6.30.)  Specifying this flag overrides the effect of
              setting the MS_NOATIME and MS_RELATIME flags.

这里写图片描述

猜你喜欢

转载自blog.csdn.net/cui841923894/article/details/81568336