searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

探索sysfs无法删除文件或目录原因

2024-07-22 08:51:16
8
0
  • sysfs中的目录或文件是无法删除的

    [root@localhost block]# pwd
    /sys/block
    [root@localhost block]# ls
    dm-0  dm-1  dm-2  sr0  vda  vdb  vdc
    [root@localhost block]# rm -rf dm-0
    rm: cannot remove 'dm-0': Operation not permitted
  • 使用strace跟踪用户空间和内核的交互

strace rm -rf dm-0

unlinkat(AT_FDCWD, "dm-0", 0) = -1 EPERM (Operation not permitted)

strace rm -rf blkio.bfq.io_service_bytes

unlinkat(AT_FDCWD, "blkio.bfq.io_service_bytes", 0) = -1 EPERM (Operation not permitted)

  • 在源码目录中查找unlinkat

    arch/arm/tools/syscall.tbl:345:328      common  unlinkat                sys_unlinkat
    arch/sw_64/kernel/syscalls/syscall.tbl:466:456  common  unlinkat                        sys_unlinkat
    arch/x86/entry/syscalls/syscall_32.tbl:315:301  i386    unlinkat                sys_unlinkat                    __ia32_sys_unlinkat
    arch/x86/entry/syscalls/syscall_64.tbl:274:263  common  unlinkat                __x64_sys_unlinkat
    fs/namei.c:4127:SYSCALL_DEFINE3(unlinkat, int, dfd, const char __user *, pathname, int, flag)
    scripts/checksyscalls.sh:21:#define __IGNORE_unlink             /* unlinkat */
    scripts/checksyscalls.sh:26:#define __IGNORE_rmdir              /* unlinkat */
    tools/perf/arch/s390/entry/syscalls/syscall.tbl:304:294  common unlinkat                sys_unlinkat                    compat_sys_unlinkat
    tools/perf/arch/x86/entry/syscalls/syscall_64.tbl:274:263       common  unlinkat                __x64_sys_unlinkat
    tools/perf/builtin-trace.c:834: { .name     = "unlinkat",

    可以看到unlinkat的系统调用定义在fs/namei.c文件中,进一步调用了do_unlinkat, 代码如下:

    SYSCALL_DEFINE3(unlinkat, int, dfd, const char __user *, pathname, int, flag)
    {
            if ((flag & ~AT_REMOVEDIR) != 0)
                    return -EINVAL;
    ​
            if (flag & AT_REMOVEDIR)
                    return do_rmdir(dfd, pathname);
    ​
            return do_unlinkat(dfd, getname(pathname));
    }
  • 继续从do_unlinkat开始探索函数调用路径,例如,可以使用gdb单步调试的方法定位问题的具体发生位置

GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-120.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/xxx/vmlinux...done.
(gdb) target remote :1234
Remote debugging using :1234
native_safe_halt () at ./arch/x86/include/asm/irqflags.h:61
61      ./arch/x86/include/asm/irqflags.h: No such file or directory.
(gdb) b do_unlinkat
Breakpoint 1 at 0xffffffff813540b0: file fs/namei.c, line 4057.
(gdb) c
Continuing.
[New Thread 6]
[Switching to Thread 6]
​
Breakpoint 1, do_unlinkat (dfd=-100, name=0xffff8881716a4740) at fs/namei.c:4057
4057    fs/namei.c: No such file or directory.
(gdb) bt
#0  do_unlinkat (dfd=-100, name=0xffff8881716a4740) at fs/namei.c:4057
#1  0xffffffff81004374 in do_syscall_64 (nr=<optimized out>, regs=0xffff8881716a4740) at arch/x86/entry/common.c:293
#2  0xffffffff81a00088 in entry_SYSCALL_64 () at arch/x86/entry/entry_64.S:238
#3  0x000056059bb3e6b0 in ?? ()
#4  0x0000000000000000 in ?? ()
(gdb) s
4065    in fs/namei.c
(gdb) s
4057    in fs/namei.c
(gdb) s
4064    in fs/namei.c
(gdb) s
4067    in fs/namei.c
(gdb) s
filename_parentat (dfd=-100, name=0xffff8881716a4740, flags=0, parent=0xffffc900018e3ee0, last=0xffffc900018e3ef0, type=0xffffc900018e3ed4)
    at fs/namei.c:2389
2389    in fs/namei.c
  • 在函数调用路径上可以看到一个关键函数vfs_unlink,其中会调用inode实例中i_op成员的unlink函数指针。i_op成员是一个inode_operations结构指针。

int vfs_unlink(struct inode *dir, struct dentry *dentry, struct inode **delegated_inode)
{
    struct inode *target = dentry->d_inode;
    int error = may_delete(dir, dentry, 0);
​
    if (error)
        return error;
​
    if (!dir->i_op->unlink)
        return -EPERM;
​
    inode_lock(target);
    if (is_local_mountpoint(dentry))
        error = -EBUSY;
    else {
        error = security_inode_unlink(dir, dentry);
        if (!error) {
            error = try_break_deleg(target, delegated_inode);
            if (error)
                goto out;
            error = dir->i_op->unlink(dir, dentry);
            if (!error) {
                dont_mount(dentry);
                detach_mounts(dentry);
            }
        }
    }
out:
    inode_unlock(target);
​
    /* We don't d_delete() NFS sillyrenamed files--they still exist. */
    if (!error && !(dentry->d_flags & DCACHE_NFSFS_RENAMED)) {
        fsnotify_link_count(target);
        d_delete(dentry);
    }
​
    return error;
}
EXPORT_SYMBOL(vfs_unlink);
  • 各种文件系统,需要按照inode_operations中的规范,完成unlink的实现,向kernel vfs注册,而sysfs没有实现unlink。

0条评论
0 / 1000
c****w
5文章数
0粉丝数
c****w
5 文章 | 0 粉丝
原创

探索sysfs无法删除文件或目录原因

2024-07-22 08:51:16
8
0
  • sysfs中的目录或文件是无法删除的

    [root@localhost block]# pwd
    /sys/block
    [root@localhost block]# ls
    dm-0  dm-1  dm-2  sr0  vda  vdb  vdc
    [root@localhost block]# rm -rf dm-0
    rm: cannot remove 'dm-0': Operation not permitted
  • 使用strace跟踪用户空间和内核的交互

strace rm -rf dm-0

unlinkat(AT_FDCWD, "dm-0", 0) = -1 EPERM (Operation not permitted)

strace rm -rf blkio.bfq.io_service_bytes

unlinkat(AT_FDCWD, "blkio.bfq.io_service_bytes", 0) = -1 EPERM (Operation not permitted)

  • 在源码目录中查找unlinkat

    arch/arm/tools/syscall.tbl:345:328      common  unlinkat                sys_unlinkat
    arch/sw_64/kernel/syscalls/syscall.tbl:466:456  common  unlinkat                        sys_unlinkat
    arch/x86/entry/syscalls/syscall_32.tbl:315:301  i386    unlinkat                sys_unlinkat                    __ia32_sys_unlinkat
    arch/x86/entry/syscalls/syscall_64.tbl:274:263  common  unlinkat                __x64_sys_unlinkat
    fs/namei.c:4127:SYSCALL_DEFINE3(unlinkat, int, dfd, const char __user *, pathname, int, flag)
    scripts/checksyscalls.sh:21:#define __IGNORE_unlink             /* unlinkat */
    scripts/checksyscalls.sh:26:#define __IGNORE_rmdir              /* unlinkat */
    tools/perf/arch/s390/entry/syscalls/syscall.tbl:304:294  common unlinkat                sys_unlinkat                    compat_sys_unlinkat
    tools/perf/arch/x86/entry/syscalls/syscall_64.tbl:274:263       common  unlinkat                __x64_sys_unlinkat
    tools/perf/builtin-trace.c:834: { .name     = "unlinkat",

    可以看到unlinkat的系统调用定义在fs/namei.c文件中,进一步调用了do_unlinkat, 代码如下:

    SYSCALL_DEFINE3(unlinkat, int, dfd, const char __user *, pathname, int, flag)
    {
            if ((flag & ~AT_REMOVEDIR) != 0)
                    return -EINVAL;
    ​
            if (flag & AT_REMOVEDIR)
                    return do_rmdir(dfd, pathname);
    ​
            return do_unlinkat(dfd, getname(pathname));
    }
  • 继续从do_unlinkat开始探索函数调用路径,例如,可以使用gdb单步调试的方法定位问题的具体发生位置

GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-120.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/xxx/vmlinux...done.
(gdb) target remote :1234
Remote debugging using :1234
native_safe_halt () at ./arch/x86/include/asm/irqflags.h:61
61      ./arch/x86/include/asm/irqflags.h: No such file or directory.
(gdb) b do_unlinkat
Breakpoint 1 at 0xffffffff813540b0: file fs/namei.c, line 4057.
(gdb) c
Continuing.
[New Thread 6]
[Switching to Thread 6]
​
Breakpoint 1, do_unlinkat (dfd=-100, name=0xffff8881716a4740) at fs/namei.c:4057
4057    fs/namei.c: No such file or directory.
(gdb) bt
#0  do_unlinkat (dfd=-100, name=0xffff8881716a4740) at fs/namei.c:4057
#1  0xffffffff81004374 in do_syscall_64 (nr=<optimized out>, regs=0xffff8881716a4740) at arch/x86/entry/common.c:293
#2  0xffffffff81a00088 in entry_SYSCALL_64 () at arch/x86/entry/entry_64.S:238
#3  0x000056059bb3e6b0 in ?? ()
#4  0x0000000000000000 in ?? ()
(gdb) s
4065    in fs/namei.c
(gdb) s
4057    in fs/namei.c
(gdb) s
4064    in fs/namei.c
(gdb) s
4067    in fs/namei.c
(gdb) s
filename_parentat (dfd=-100, name=0xffff8881716a4740, flags=0, parent=0xffffc900018e3ee0, last=0xffffc900018e3ef0, type=0xffffc900018e3ed4)
    at fs/namei.c:2389
2389    in fs/namei.c
  • 在函数调用路径上可以看到一个关键函数vfs_unlink,其中会调用inode实例中i_op成员的unlink函数指针。i_op成员是一个inode_operations结构指针。

int vfs_unlink(struct inode *dir, struct dentry *dentry, struct inode **delegated_inode)
{
    struct inode *target = dentry->d_inode;
    int error = may_delete(dir, dentry, 0);
​
    if (error)
        return error;
​
    if (!dir->i_op->unlink)
        return -EPERM;
​
    inode_lock(target);
    if (is_local_mountpoint(dentry))
        error = -EBUSY;
    else {
        error = security_inode_unlink(dir, dentry);
        if (!error) {
            error = try_break_deleg(target, delegated_inode);
            if (error)
                goto out;
            error = dir->i_op->unlink(dir, dentry);
            if (!error) {
                dont_mount(dentry);
                detach_mounts(dentry);
            }
        }
    }
out:
    inode_unlock(target);
​
    /* We don't d_delete() NFS sillyrenamed files--they still exist. */
    if (!error && !(dentry->d_flags & DCACHE_NFSFS_RENAMED)) {
        fsnotify_link_count(target);
        d_delete(dentry);
    }
​
    return error;
}
EXPORT_SYMBOL(vfs_unlink);
  • 各种文件系统,需要按照inode_operations中的规范,完成unlink的实现,向kernel vfs注册,而sysfs没有实现unlink。

文章来自个人专栏
文章 | 订阅
0条评论
0 / 1000
请输入你的评论
0
0