zoukankan      html  css  js  c++  java
  • fuse的mount机制 2 -系统调用mount

    经过上一篇的分析,目前已经知道mount函数最终进入到mount.c 中的 int fuse_kern_mount(const char *mountpoint, struct fuse_args *args)

    而主题函数进入到fuse.c中的 fuse_new_common

    这两个函数都会在helper.c中的fuse_setup_common中返回,返回后进入helper.c的 fuse_daemonize 。fuse_daemonize使用 foreground参数也即-f参数。

    如果-f参数为真,则进入fuse_daemonize的循环体,否则fuse_daemonize直接返回,然后fuse_setup_common也返回到fuse_main_common,进入fuse_loop_mt循环。

    本篇主要研究fuse_kern_mount函数。

    1. 该函数调用栈:

        fuse_setup_common-> 

            fuse_mount_common(const char *mountpoint,struct fuse_args *args) -> 

             fuse_mount_compat25(const char *mountpoint, struct fuse_args *args)  -> 

            fuse_kern_mount(const char *mountpoint, struct fuse_args *args)

    2.  mountpoint就是命令行提供的目录参数。args也是根据命令行的参数生成的,struct fuse_args args = FUSE_ARGS_INIT(argc, argv);

    #define FUSE_ARGS_INIT(argc, argv) { argc, argv, 0 }

    在fuse_opt.h

    struct fuse_args {
      /** Argument count */
      int argc;

      /** Argument vector. NULL terminated */
      char **argv;

      /** Is 'argv' allocated? */
      int allocated;
    };

    也在fuse_opt.h

    注意,在fuse_setup_common中,将命令行的参数进行了规整,处理出mountpoint和args。mountpoint是挂载点的全路径字符串. 如果命令行是./ssfs dir1 -f , args含有两个字符串,第一个字符串是 ./ssfs,第二个字符串是-osubtype=ssfs

    3. fuse_kern_mount首先构建struct mount_opts mo; 

    struct mount_opts {
    int allow_other;
    int allow_root;
    int ishelp;
    int flags;
    int nonempty;
    int auto_unmount;
    int blkdev;
    char *fsname;
    char *subtype;
    char *subtype_opt;
    char *mtab_opts;

    char *fusermount_opts;
    char *kernel_opts;
    };

     然后调用 fuse_mount_sys(mountpoint, &mo, mnt_opts);函数,这里因为 mo->auto_unmount为真,该函数将返回-2,即fallback to fusermount ,

    转而调用fuse_mount_fusermount,这里会调用第一个,并返回3.

    fuse_mount_fusermount(mountpoint, &mo, tmp_opts, 1);

    注意:fuse_mount_sys中主要是open了/dev/fuse以及使用了mount系统调用。 fuse_mount_fusermount中主要使用 socketpair系统调用。

    注意2:fuse_mount_fusermount使用了fork,然后子线程做了一系列操作后_exit了。一个重要操作是 exec_fusermount(argv); argv里包含mountpint以及mount程序名即fusermount。

    static void exec_fusermount(const char *argv[])
    {
      execv(FUSERMOUNT_DIR "/" FUSERMOUNT_PROG, (char **) argv);
      execvp(FUSERMOUNT_PROG, (char **) argv);
    }

    FUSERMOUNT_DIR打印字符串显示的是 /usr/local/bin

    FUSERMOUNT_DIR "/" FUSERMOUNT_PROG打印字符串显示的是/usr/local/bin/fusermount

    原来c语言里将几个字符串直接放在一起就是连起来!

     从这里看来,mount函数最终调用了 fusermount程序,一个自带main函数的程序。该程序的源代码就是 util目录下的fusermount.c

    注意:后入如果需要打印到屏幕,需要在fuse_mount_fusermount注销掉改变sdio的代码。

    4. fusermount.c最终调用了系统调用mount。

    调用栈:

    fusermount.c:main ->

      mount_fuse(const char *mnt, const char *opts) ->

      do_mount(const char *mnt, char **typep, mode_t rootmode,

          int fd, const char *opts, const char *dev, char **sourcep, char **mnt_optsp, off_t rootsize) ->

      mount(source, mnt, type, flags, optbuf).

    在mount_fuse向do_mount传递mnt参数之前,调用了check_perm函数,该函数使用chdir将当前的工作路径改为mnt,然后使用"."即当前路径作为mnt。

    后面的几个函数均使用"."作为mnt。

    问题:自己写的程序按照上述的方式使用root调用mount,会出现errno=22即EINVAL source had an invalid superblock. 那么,为什么fuse就可以这样掉用mount呢?

    经验证,在fuse的mount调用中,可以随意改变source,type,flags变量。改变source和type有时会反映到mount列表,有时却不会。

      也可以随便改变mnt变量,但是必须是一个存在可访问的路径,改变mnt变量不会反映到mount列表。

    注意:貌似这里的mount返回了-1,errno为19表示filesystemtype not configured in the kernel. 但是不影响程序正确执行,而且,strace监测不到这个mount。继续发现,只要type里设置了fuse或fuse.xx就返回0,source可随意设置。 strace追踪不到的原因是mount在fork的子程序里运行的。

    如果使用strace -f可以追中到子进程的mount,然而结果显示Operation not permitted。

    使用sudo的话,实际运行的mount代码是fuse_mount_sys函数里的。

  • 相关阅读:
    卷积操作特征图输出大小
    python函数式编程
    python函数
    列表和元组
    Crontab 执行时没有环境变量!
    github 解决 Agent admitted failure to sign using the key
    Lightgbm 随笔
    btrfs-snapper 实现Linux 文件系统快照回滚
    Ansible playbook API 开发 调用测试
    Linux终端下安装jdk
  • 原文地址:https://www.cnblogs.com/bettersky/p/6745210.html
Copyright © 2011-2022 走看看