精华内容
下载资源
问答
  • 无根容器的FUSE中的overlay + shiftfs实现。 用法: $ fuse-overlayfs -o lowerdir=lowerdir/a:lowerdir/b,upperdir=up,workdir=workdir merged 指定不同的UID / GID映射: $ fuse-overlayfs -o uidmapping=0:10:...
  • vue-fuse模糊搜索库的Vue.js插件Fuse.js有两种使用此插件的方法。 vue-fuse组件或$ search方法。 成为vue-fuse模糊搜索库的Vue.js插件Fuse.js有两种使用此插件的方法。 vue-fuse组件或$ search方法。 确保查看下面两...
  • bazil.org/fuse-Go中的文件系统 bazil.org/fuse是一个Go库,用于编写FUSE用户空间文件系统。 它是内核-用户空间通信协议的从零开始的实现,并且未使用项目FUSE中的C库。 bazil.org/fuse完全采用Go语言,以确保安全...
  • s3fs允许Linux和macOS通过FUSE挂载S3存储桶。 s3fs保留文件的本机对象格式,从而允许使用其他工具,例如 。 产品特点 POSIX的较大子集,包括读/写文件,目录,符号链接,模式,uid / gid和扩展属性 与Amazon S3和...
  • Fuse-ext2是用于的EXT2 / EXT3 / EXT4文件系统,并构建为可与一起。 依存关系 Fuse-ext2至少需要Linux的Fuse版本2.6.0。 对于macOS 2.7.5或更高版本, Fuse-ext2至少需要Fuse 。 Linux: macOS: 适用于macOS的...
  • android4.4 的时候vold,也是利用fuse文件系统达到,将sd卡的目录(storage目录)获取sd实际挂载目录(mnt/media_rw)的权限。但是android4.4的时候vold只是写属性而已,然后init监测这个属性,属性改变时,才会去...
  • HL7Fuse是.Net框架中满足您HL7开发需求的“瑞士小刀”。 HL7Fuse基于SuperSocket并结合了NHapi和NHapiTools。 这种组合为构建HL7应用程序或HL7测试框架提供了强大而坚实的基础。 实际上,如果按原样使用HL7Fuse,则...
  • 本文仅针对Fuse(熔断器)选型,PPTC&CPTC及其他过流保护装置或电路不在其列。针对Fuse设计选型相关基础知识介绍及选型参考标准、选型方法介绍等内容。
  • Go的跨平台FUSE库 Cgofuse是Go的跨平台FUSE库。 它在多个平台上受支持,并且可以移植到具有FUSE实现的任何平台上。 根据平台的不同,它具有和 (“ nocgo”)变体。 视窗 苹果系统 Linux FreeBSD的 NetBSD * ...
  • Fuse Studio是用于Fuse框架的可视化桌面工具套件。 有关下载链接和文档,请单击。 在Windows上构建 在Windows上进行构建的前提条件是 -Community Edition效果很好安装了.NET桌面开发组件 通过运行build.bat或使用...
  • FUSE(用户空间文件系统)作为类UNIX系统平台上可加载的内核模块,允许非特权用户创建功能完备的文件系统,而不需要重新编译内核。FUSE模块仅仅提供kernel模块的接入口,而本身的主要实现代码位于用户空间中。对于...
  • jnr-fuse是Java中使用Java本机运行时(JNR)的FUSE实现。 项目目标 该项目的主要目标是提供一种在用户空间中创建高性能文件系统的简便方法。 关于技术 (用户空间中的文件系统)是一种用于类Unix操作系统的操作...
  • FUSE

    2019-01-03 10:57:00
    第二段代码说明,fuse_user可以用过读写fuse设备文件来与kernel FUSE通信,也就是说,fuse_user可以通过read函数主动读取了kernel FUSE的请求。 至此1号折线走完 。 图中2号曲线过程 fuse_user 收到kernel ...

    FUSE

    什么是FUSE

    Filesystem in Userspace顾名思义,即在用户空间的文件系统。
    为什么要强调用户空间呢?接触过Linux内核的同学大概会知道,文件系统一般是实现在内核里面的,比如,Ext4、Fat32、NTFS(Kernel原生版)等常见的文件系统,其代码都在内核中,而FUSE特殊之处就是,其文件系统的核心逻辑是在用户空间实现的。

    为什么FUSE会存在

    事物的存在的原因之一是其优势大于劣势,下面是它的优劣描述。

    优势

    • 文件系统的改动不用更新内核
      FUSE的核心逻辑在用户空间,所以修改文件系统的行为绝大部分修改会在用户空间。这在很多场合是一件很方便的事情。
    • 很容易实现自己的文件系统
      理论上它可以实现任何天马行空的文件系统,只要一个开发者实现了基本的文件操作。而这个所谓的文件操作也是自己定义的,甚至可以这个操作可能只是一句打印而已,或者是一件超级复杂的事情,只要这个操作符合开发者的要求,他就完成了一个符合开发者需求的文件系统(也许本质上并不是文件系统了,这种情况是有现实例子的)。

    劣势

    • 效率较低
      这是显而易见的,就针对块设备的文件系统而言,用户层肯定不如内核实现的效率高,毕竟用户态/内核态切换的开销是少不了的。这也是符合一般软件规律的,越高层次的软件易用性越高,效率越低。

    FUSE实现原理

    下面这张图体现了FUSE工作的基本套路,是根据WIki里的画的,这张图感觉更符合我看到的代码的状况。

    4df5565a9558d0d94417430d3164d9de5e9.jpg

    图中体现了FUSE的2个关键部分(绿色方框),分别是Kernel中的那个FUSE(这里简称kernel FUSE)和user space中的那个fuse_user程序。其中kernel FUSE是负责把从用户层过来的文件系统操作请求传递给fuse_user程序的,而这个fuse_user程序实现了前面所说的文件系统的核心逻辑。
    下面分步描述一下在用户对一个FUSE分区上的文件执行ls命令时发生了什么,当然,这里隐含了个前提,即这个系统的/tmp目录已经属于某个FUSE分区了,为了达到这种状况,前面还需要有一个mount的过程。

    图中1号折线过程

    • 用户敲ls -l /tmp/file_on_fuse_fs+回车
      这时ls会调用一些系统调用(例如stat(2))。
    • kernel FUSE接收用户请求
      文件相关的系统调用会进入VFS处理,然后VFS会根据这个分区的文件系统,找到对应文件系统的实现接口,这里当然是找到kernel FUSE。
    • kernel FUSE会把收到的操作请求按照FUSE定义的通信协议发送给fuse_user程序
      那么问题来了,kernel FUSE凭什么把消息给fuse_user,却没给别人呢?
      如果看得懂,请体会如下两段代码
    // kernel/fs/fuse/dev.c
    const struct file_operations fuse_dev_operations = {
        .owner      = THIS_MODULE,
        .open       = fuse_dev_open,
        .llseek     = no_llseek,
        .read_iter  = fuse_dev_read,
        .splice_read    = fuse_dev_splice_read,
        .write_iter = fuse_dev_write,
        .splice_write   = fuse_dev_splice_write,
        .poll       = fuse_dev_poll,
        .release    = fuse_dev_release,
        .fasync     = fuse_dev_fasync,
        .unlocked_ioctl = fuse_dev_ioctl,
        .compat_ioctl   = fuse_dev_ioctl,
    };
    EXPORT_SYMBOL_GPL(fuse_dev_operations);
    
    static struct miscdevice fuse_miscdevice = {
        .minor = FUSE_MINOR,
        .name  = "fuse",
        .fops = &fuse_dev_operations,
    };
    
    // fuse_user
    int fd = open("/dev/fuse", ...);
    read(fd, ...);
    write(fd, ...);

    1.第一段代码说明,FUSE会创建一个名为fuse的混杂设备文件(简称fuse设备文件);
    2.第二段代码说明,fuse_user可以用过读写fuse设备文件来与kernel FUSE通信,也就是说,fuse_user可以通过read函数主动读取了kernel FUSE的请求。
    至此1号折线走完

    图中2号曲线过程

    • fuse_user收到kernel FUSE发来的请求
      这个收发请求的机制在文末的参考资料中有提及,感兴趣的同学可以研究一下。
    • fuse_user处理这个请求
      这个“处理”完全是开发者自己定义的,只要符合开发者的要求就是合适的处理方式,不过本文讨论的是针对块设备的货真价实的文件系统,所以这个“处理”必须能够读写块设备上面的内容。
      那么一个很简单的问题来了,如果不使用fwrite(3)write(2)这种方式,怎么写入文件呢?

    答案要回到事物的本源,文件是个抽象概念,它本质上只是块设备(例如磁盘、优盘或SD卡)上字节的有序排列而已,所以只要能写入块设备,写入文件当然就可以实现。

    那么如何读写块设备呢?请想象插入一个优盘,然后体会下面代码。

    int fd = open("/dev/block/sda");//或者sda1
    pwrite(fd, buf, count, offset);

    解释一下上面代码。当我们插入一个优盘到linux系统时,常见的情况是系统会自动生成/dev/block/sda/dev/block/sda1两个块设备文件,所以第一句open就是在获取块设备的fd(file descriptor),然后再用pwrite访问这个fd,将buf的内容向offset位置写count个字节。其中offset是写入位置,即从块设备的哪个字节开始写。虽然这里也是用了write一类的函数,但是write的对象不同哦。
    综上所述,再加上pread函数,我们对块设备就可以为所欲为了。
    至此,2号曲线走完。

    图中3号折线过程

    1. fuse_user将处理结果返回给kernel FUSE
    2. 继续顺着1号折线的来路,原路返回处理结果
      至此,3号折线走完。

    说完了代码,下面我们用2个实际使用的case(Android和NTFS-3G)进行说明。

    FUSE的实现代码

    如前面所讲,FUSE分为2部分,分别在user、kernel spcae中,在kernel space中的部分由kernel官方维护,user space中的部分(仅是个框架,不包括开发者的实现)有一个开源库叫libfuse,NTFS-3G就是基于这个FUSE框架的实现,另一个我接触到实现是Android 8.0的中SD卡的文件系统的实现,它没有用libfuse,完全是谷歌自己写的一个实现。

    NTFS-3G与FUSE

    关于NTFS-3G

    NTFS-3G是一个叫Szabolcs Szakacsits的开发者2006年创建的项目,后来他创建了一个公司叫Tuxera,从事很多NTFS文件系统相关的业务,NTFS-3G这个开源项目,也由这个公司维护至今,它就是一份典型的FUSE文件系统实现源码

    代码导读

    根据上面所说的原理,这个文件系统中必然存在着块设备fuse设备open/close/read/write。下面着重描述3个重要动作,分别是打开块设备打开fuse设备处理kernel FUSE请求,啥也不说了,都在代码里了,撸!。

    ntfs-3g.c
    main——打开块设备
    {
        ...
        //打开块设备,opts.device就是块设备的名字,例如"/dev/block/sda1"
        //这里就是前面代码中的open来获得fd的动作
        err = ntfs_open(opts.device);
        ==> ctx->vol = ntfs_mount(device, flags);
            {
            dev = ntfs_device_alloc(name, 0, &ntfs_device_default_io_ops, NULL);
                {
                //埋下伏笔(1)!!!
                //注册了设备文件操作函数
                //dev->d_ops->open = ntfs_device_unix_io_open
                //dev->d_ops->write = ntfs_device_unix_io_write
                dev->d_ops = dops;
                dev->d_private = priv_data;
                }
            ...
            vol = ntfs_device_mount(dev, flags);
            ==> vol = ntfs_volume_startup(dev, flags);
                {
                if ((dev->d_ops->open)(dev, ...)) 
                    //为什么会call 到这呢,请看前面的伏笔(1)!!!
                    ==> ntfs_device_unix_io_open(struct ntfs_device *dev, int flags)
                        //注意了!注意了!open块设备了啊!
                        //例如,dev->d_name = "/dev/block/sda1"
                        ==> *(int*)dev->d_private = open(dev->d_name, flags);
                //埋下伏笔(7)!!!
                //注册了设备文件操作函数
                vol->dev = dev;
                }
            }
        ...
    }
    

    从上述代码中可以看到,块设备确实被打开了。

    ntfs-3g.c
    main——打开fuse设备
    {
        //前面已经open了块设备
        ...
        fh = mount_fuse(parsed_options);
        {
        ctx->fc = try_fuse_mount(parsed_options);
            ==> fc = fuse_mount(opts.mnt_point, &margs);
                {
                fd = fuse_kern_mount(mountpoint, args);
                ==> res = fusermount(0, 0, 0, mnt_opts ? mnt_opts : "", mountpoint);
                    ==> res = mount_fuse(mnt, opts);
                        ==> fd = open_fuse_device(&dev);
                            ==> fd = try_open(FUSE_DEV_NEW, devp);
                                //注意了!注意了!open fuse设备了啊!
                                //例如,dev = "/dev/fuse"
                                ==> fd = open(dev, O_RDWR);
                ...
                ==> ch = fuse_kern_chan_new(fd);
                    {
                    struct fuse_chan_ops op = {
                        //埋下伏笔(2.0)!!!
                        //注册了设备文件操作函数
                        //op.receive = fuse_kern_chan_receive
                        //op.send = fuse_kern_chan_send
                        .receive = fuse_kern_chan_receive,
                        .send = fuse_kern_chan_send,
                        ...
                        };
                    ...
                    return fuse_chan_new(&op, fd, bufsize, NULL);
                    ==> return fuse_chan_new_common(op, fd, bufsize, data);
                        {
                        //埋下伏笔(2.1)!!!
                        //伏笔(2.0)的op给了ch
                        //ch->op->receive = fuse_kern_chan_receive
                        //ch->op->send = fuse_kern_chan_send
                        ch->op = *op;
                        //埋下伏笔(3)!!!
                        //打开fuse设备的fd给了ch
                        ch->fd = fd;
                        }
                    }
                }
        //埋下伏笔(4.0)!!!
        //ntfs_3g_ops.write = ntfs_fuse_write
        fh = fuse_new(ctx->fc, &args , &ntfs_3g_ops, sizeof(ntfs_3g_ops), NULL);
            //埋下伏笔(5.0)!!!
            //llop = fuse_path_ops
            //fuse_path_ops.write = fuse_lib_write
        ==> f->se = fuse_lowlevel_new(args, &llop, sizeof(llop), f);
            {
            struct fuse_session_ops sop = {
                //埋下伏笔(6.0)!!!
                //sop.process = fuse_ll_process
                .process = fuse_ll_process,
                ...
                 };
            ...
                //埋下伏笔(4.1)!!!
                //f->fs->op = ntfs_3g_ops
                //f->fs->op.write = ntfs_fuse_write
            fs = fuse_fs_new(op, op_size, user_data);
                ==> memcpy(&fs->op, op, op_size);
            f->fs = fs;
            ...
            //埋下伏笔(5.1)!!!
            //op = llop = fuse_path_ops
            //f->op->write = fuse_lib_write
            memcpy(&f->op, op, op_size);
            ...
            se = fuse_session_new(&sop, f);
                {
                //埋下伏笔(6.1)!!!
                //sop给了se
                se->op = *op;
                se->data = data;
                }
            }
        }
        ...
    }
    

    从上述代码中可以看到,fuse混杂设备确实被打开了。

    ntfs-3g.c
    main——处理kernel FUSE请求
    {
        //前面已经open了块设备和fuse设备
        ...
        fuse_loop(fh);
        ==> return fuse_session_loop(f->se);
            {
            //这个循环中不停地响应着kernel FUSE的请求
            while (!fuse_session_exited(se)) {
                struct fuse_chan *tmpch = ch;
                res = fuse_chan_recv(&tmpch, buf, bufsize);
                ==> return ch->op.receive(chp, buf, size);
                    //为啥call到这?请看伏笔(2.x)
                    ==> fuse_kern_chan_receive
                        {
                        //fuse_chan_fd(ch)是什么?请看伏笔(3)
                        res = read(fuse_chan_fd(ch), buf, size);
                        }
                    ...
                fuse_session_process(se, buf, res, tmpch);
                ==> se->op.process(se->data, buf, len, ch);
                    //为啥call到这?请看伏笔(6.x)
                    ==> fuse_ll_process
                        /**********
                            static struct {
                                void (*func)(fuse_req_t, fuse_ino_t, const void *);
                                const char *name;
                                } fuse_ll_ops[] = {
                                    ...
                                    [FUSE_WRITE]       = { do_write,       "WRITE"       },
                                    ...
                            };
                        ***********/
                        //假设我们在进行写(FUSE_WRITE)操作
                        ==> fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg);
                            ==> do_write
                                ==> req->f->op.write(req, nodeid, PARAM(arg), arg->size, arg->offset, &fi);
                                    //为啥call到这?请看伏笔(5.x)
                                    ==> fuse_lib_write
                                        {
                                        ...
                                        res = fuse_fs_write(f->fs, path, buf, size, off, fi);
                                        ==> return fs->op.write(path, buf, size, off, fi);
                                            //为啥call到这?请看伏笔(4.x)
                                            ==> ntfs_fuse_write
                                                ==> s64 ret = ntfs_attr_pwrite(na, offset, size, buf + total);
                                                    //vol->dev是什么?请看伏笔(7)
                                                    ==> written = ntfs_pwrite(vol->dev, ...);
                                                        ==> written = dops->pwrite(dev, ...);
                                                            //为啥call到这?请看伏笔(1)
                                                            ==> ntfs_device_unix_io_pwrite
                                                                //注意了!注意了!对块设备文件pwrite了啊!
                                                                //DEV_FD(dev)是什么?请看前面打开块设备的地方
                                                                ==> return pwrite(DEV_FD(dev), buf, count, offset);
                                        ...
                                        fuse_reply_write(req, res);
                                            ==> return send_reply_ok(req, &arg, sizeof(arg));
                                                ==> return send_reply(req, 0, arg, argsize);
                                                    ==> return send_reply_iov(req, error, iov, count);
                                                        ==> res = fuse_chan_send(req->ch, iov, count);
                                                            ==> return ch->op.send(ch, iov, count);
                                                                ==> fuse_kern_chan_send
                                                                    //注意了!注意了!对fuse设备文件writev了啊!
                                                                    //虽然和write不同,但也是向fuse设备文件的fd写东西
                                                                    //fuse_chan_fd(ch)是什么?请看伏笔(3)
                                                                    ==> ssize_t res = writev(fuse_chan_fd(ch), iov, count);
                                        ...
                                        }
                }
            }
        //收尾工作
        ...
    }
    

    光练不说傻把式,还得说一下。
    从上述代码中可以看到,“写”的用户请求是用ntfs_fuse_write函数处理的,struct fuse_operations ntfs_3g_ops就是开发者要实现的文件系统核心逻辑,这些文件操作在打开fuse设备过程(mount_fuse函数)中被绑定到那些核心数据结构中。在最后处理文件系统请求时调用,最终以直接访问块设备的方式实现了“处理”。然后,以写入fuse设备文件的方式将“处理”结果发给kernel FUSE。

    Android与FUSE

    Android代码到哪看

    谈到Android,由于众所周知的原因,首先要说怎么在中国大陆访问它的代码,这事靠百度可以解决,如果只是看看,用这些网站在线看就好了。
    Android代码浏览网站1
    Android代码浏览网站2

    Android 8.0的FUSE

    Android里面用的并不是NTFS-3G所使用的libfuse,因为我接触到的是AN8(Android 8.0)的代码,所以就基于它来再次领略一下FUSE文件系统的实现。代码在AN8/system/core/sdcard,下面有3个代码文件

    AN8/system/core/sdcard
    ├── Android.mk
    ├── fuse.cpp
    ├── fuse.h
    └── sdcard.cpp // main函数在这里!!!

    sdcard.cpp是对SD卡文件系统处理的代码。谷歌搞了个sdcardfs文件系统,当系统支持sdcardfs,并且用户要求使用时,就会优先用这个文件系统挂载SD卡,否则就用FUSE挂载。也就是说,对于AN8来说,FUSE是sdcardfs的备胎,下面代码反映了这绿油油的事实。

    int main(int argc, char **argv) {
        //各种准备工作
        ...
        if (should_use_sdcardfs()) {
            //如果应该用sdcardfs,就运行sdcardfs
            run_sdcardfs(...);
        } else {
            //否则,就运行FUSE
            run(...);
        }
        return 1;
    }
    

    下面创建了3个start_handler的线程,看得出来它们之间有些区别。为什么是这3个?我也不知道,那就是AN8的实现问题了,不是本文重点。

    static void run(...) {
        //准备工作
        ...
        //埋下伏笔(1)
        //这些dest_path后面会用到
        snprintf(fuse_default.dest_path, PATH_MAX, "/mnt/runtime/default/%s", label);
        snprintf(fuse_read.dest_path, PATH_MAX, "/mnt/runtime/read/%s", label);
        snprintf(fuse_write.dest_path, PATH_MAX, "/mnt/runtime/write/%s", label);
    
        handler_default.fuse = &fuse_default;
        handler_read.fuse = &fuse_read;
        handler_write.fuse = &fuse_write;
    
        ...
        if (fuse_setup(&fuse_default, AID_SDCARD_RW, 0006)
                    || fuse_setup(&fuse_read, AID_EVERYBODY, ...)
                    || fuse_setup(&fuse_write, AID_EVERYBODY, full_write ? 0007 : 0027))
            ==> fuse_setup
                {
                //注意了!注意了!打开fuse设备文件了啊!
                //埋下伏笔(2)
                //注意这个fd,后面会用到
                fuse->fd = TEMP_FAILURE_RETRY(open("/dev/fuse", O_RDWR | O_CLOEXEC));
                //欲知fuse->dest_path是什么,请看伏笔(1)
                mount("/dev/fuse", fuse->dest_path,...)
                }
        ...
        if (pthread_create(&thread_default, NULL, start_handler, &handler_default)
                || pthread_create(&thread_read, NULL, start_handler, &handler_read)
                || pthread_create(&thread_write, NULL, start_handler, &handler_write)) {
            LOG(FATAL) << "failed to pthread_create";
        }
        // 一些不会退出的loop
        ...
    }
    

    在上面代码中,打开了fuse设备文件,同时创建了3个FUSE用户线程来处理kernel FUSE的请求。

    start_handler ==> handle_fuse_requests
    {
        for (;;) {
            //欲知fuse->fd是什么,请看伏笔(2)
            read(fuse->fd,...);
            ...
            //埋下伏笔(3)
            //data是kernel FUSE发来的请求
            int res = handle_fuse_request(fuse, handler, hdr, data, data_len);
                    //以一个顺利的写请求为例
                ==> return handle_write(fuse, handler, hdr, req, buffer);
                    {
                    struct handle *h = static_cast<struct handle*>(id_to_ptr(req->fh));
                    ...
                    //注意了!注意了!写块设备文件了啊!
                    //欲知h->fd是什么,它源自伏笔(3)提到的data,所以它来自kernel FUSE
                    //它是怎么来的呢?此处设下一个悬念(1)
                    res = TEMP_FAILURE_RETRY(pwrite64(h->fd, buffer, req->size, req->offset));
                    ...
                    fuse_reply(fuse, hdr->unique, &out, sizeof(out));
                        //注意了!注意了!写fuse设备文件了啊!
                        //欲知fuse->fd是什么,请看伏笔(2)
                    ==> ssize_t ret = TEMP_FAILURE_RETRY(writev(fuse->fd, vec, 2));
                    ...
                    }
            ...
        }
    }
    

    在上面代码中,读取了kernel FUSE的请求,然后处理,即写入了块设备文件,最后发回结果给kernel FUSE。
    这段代码中有一个悬念,后文会揭露。

    Kernel FUSE

    代码在哪

    代码导读

    我对这里没有多少研究,怕误人子弟,所以不展开了,仅仅围绕前面代码中的悬念(1)进行说明。前面的悬念(1)在于那个来自kernel FUSE的fd是在哪里赋值的。下面先从读fuse设备文件说起,因为这里就是获取kernel FUSE请求的现场。

    读写fuse设备文件

    前面的FUSE文件系统实现中,它们与kernel FUSE沟通都是通过读写fuse设备文件实现的,而这个设备文件的读写操作就定义在struct file_operations fuse_dev_operations中。

    //dev.c
    const struct file_operations fuse_dev_operations = {
        ...
        .read_iter  = fuse_dev_read,
        .splice_read    = fuse_dev_splice_read,
        .write_iter = fuse_dev_write,
        .splice_write   = fuse_dev_splice_write,
        ...
    };
    

    我看了半天才想到,上面这部分代码对我们揭开悬念没有帮助,因为这里只是把请求从某处读出来给用户层而已,所以它并不生产请求,只是请求的搬运工。回顾一下原理,直接给kernel FUSE创建请求的是VFS,所以应该从对接VFS的那部分kernel FUSE的代码寻找线索。另外一个重要线索就是在AN8的代码中,处理写请求时用到了struct fuse_write_in这个结构体,悬念处的fd值就是源于fuse_write_in.fh,关键是它定义在kernel的头文件里哟,你懂的。

    神秘的fh

    在kernel里搜struct fuse_write_in就很容易发现,fuse_write_in.fh的赋值在fuse_write_fill里面。下面的代码描述的是每个FUSE文件系统中的文件的“写”过程,从这个过程中可以观察到,这个fh就在file->private_data中,file->private_data的实际类型是struct fuse_file*

    static const struct file_operations fuse_file_operations = {
        ...
        .write_iter = fuse_file_write_iter,
                ==> written_buffered = fuse_perform_write(file, mapping, from, pos);
                    ==> num_written = fuse_send_write_pages(...);
                        ==> res = fuse_send_write(req, &io, pos, count, NULL);
                            {
                                struct fuse_file *ff = file->private_data;
                                ...
                                fuse_write_fill(req, ff, pos, count);
                                {
                                struct fuse_write_in *inarg = &req->misc.write.in;
                                ...
                                //inarg->fh = file->private_data->fh
                                inarg->fh = ff->fh;
                                }
                            }
        ...
    };
    void fuse_init_file_inode(struct inode *inode)
    {
        inode->i_fop = &fuse_file_operations;
        inode->i_data.a_ops = &fuse_file_aops;
    }
    

    神秘的private_data——一切还在用户层

    暮然回首,那fd还在用户层,请看代码(AN8中)。

    static int handle_open(struct fuse* fuse, struct fuse_handler* handler,
            const struct fuse_in_header* hdr, const struct fuse_open_in* req)
    {
        ...
        node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
        ...
        //注意了!注意了!打开块设备文件了啊!
        //悬念(1)被揭露了
        h->fd = TEMP_FAILURE_RETRY(open(path, req->flags));
        out.fh = ptr_to_id(h);
        fuse_reply(fuse, hdr->unique, &out, sizeof(out));
        ...
    }
    
    

    上面这段代码是AN8的FUSE实现打开文件的函数,这就是AN8 FUSE打开块设备文件的现场了。为什么是open呢?此处与kernel中的file->private_data有什么关系呢?请看下面代码。

    int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file,
             bool isdir)
    {
        ...
        //这里就通向了用户层的open,用户层那个fh就通过outarg传了回来
        err = fuse_send_open(fc, nodeid, file, opcode, &outarg);
        ff->fh = outarg.fh;
        ff->open_flags = outarg.open_flags;
        ...
        //file->private_data->fh = outarg.fh
        //outarg就是悬念(1)被揭露现场的那个out
        file->private_data = fuse_file_get(ff);
            ==> return ff;
        ...
    }
    

    与NTFS-3G相比,AN8利用每个文件的struct file.private_data来传递块设备文件的fd,并在open文件的时候打开块设备

    转载于:https://my.oschina.net/fileoptions/blog/2996339

    展开全文
  • FUSE 小型文件系统 SmallFS在 FUSE 驱动程序的实现中,用于小而简单的文件系统。 该驱动程序已被实施以用作 UNITEC (Universidad Tecnologica Centroamericana ) 的操作系统类的一部分。 该文件系统由美国大学的 ...
  • concat-fuse是用于Linux的基于的虚拟文件系统,它可以像处理单个文件一样处理一组文件。 它实际上是在做: cat *.txt > large_file 但是,它不是创建large_file而是创建一个虚拟文件并访问原始的*.txt文件。 可以...
  • 从这个意义上讲,它类似于FUSE(用户空间中的文件系统),后者在类似UNIX的计算机上提供相同的功能。 好处 稳定性 WinFsp非常稳定。 没有已知的内核模式崩溃,它也不会遭受资源泄漏或类似问题的困扰。 WinFsp的稳定...
  • hadoop-fuse-dfs安装.docx

    2019-07-30 10:53:48
    CDH hadoop-fuse-dfs的安装指导,是我在工作过程中安装步鄹的总结。
  • 流行的用户空间文件系统框架FUSE已被广泛用于在基础内核文件系统(kFS)之上构建各种自定义文件系统(cFS)。 基于FUSE的cFS通过在用户空间中开发其特定功能而获得了足够的灵活性,但是由于将所有请求从FUSE内核驱动...
  • 用户空间中的小文件系统 一个FUSE包装器,将littlefs放在用户空间中。...littlefs-fuse需要FUSE 2.6或更高版本,您可以通过以下方式找到FUSE版本: fusermount -V 为了针对FUSE进行构建,您将需要软
  • 软件包 ,尤其是FileSystem接口,提供了一种方便的方法来创建文件系统类型,并通过fuse.Mount将其导出到内核。 确保还查看程序包的子程序包以获取示例和测试。 该软件包的灵感和与内核相关的大部分代码都 。
  • fuse和ntfs-3g.rar

    2019-06-15 20:44:22
    在ubuntu-linux系统上挂载ntfs的硬盘需要这两个安装包,我的系统是ubuntu18.04
  • Rust的FUSE(用户空间中的文件系统)库。 polyfuse是一个库,用于基于Rust中的来实现文件。 该项目的目标是提供一个Rust FUSE库,该库与Rust 1.39中稳定的async / .await语法具有高度的相似性。 平台要求 当前, ...
  • dfmerge-fuse dfmerge-fuse 是一个 FUSE 文件系统,用于合并来自多个分支(原版游戏、模组、用户文件等)的矮人要塞文件。 它根据文件路径使用不同的方案: 合并特定的 DF 文件格式,目前: 初始化文件(init.txt...
  • MOUNT_OPTS :其他安装选项(在/etc/fuse.conf中配置了user_allow_other) CLIENT_ID :不带.apps.googleusercontent.com Google oAuth客户端ID CLIENT_SECRET :Google oAuth客户端机密 VERIFICATION_CODE :您...
  • composer require sj-i/php-fuse 要求 PHP 7.4+(NTS / ZTS) 64位Linux x86_64 FFI扩展 libfuse(当前基于2.9.9) 文献资料 当前,没有提供文档。 :-( 如果要使用此库在PHP中编写文件系统,请参阅此存储库中的和...
  • seafile-fuse-client 的自述文件 先决条件 安装 python-seafile。 由于 seafile-fuse-client 依赖于 seafile 提供的 ,因此需要 Python-seafile: $ git clone https://github.com/dongsupark/python-seafile.git...
  • fuse-libs-2.9.2-7.el7.x86_64.rpm rpm包 安装后执行rpm -ivh fuse-libs-2.9.2-7.el7.x86_64.rpm 可直接使用
  • 在 jboss-fuse-6.1.0.redhat-379 上测试 ##部署(普通保险丝) 可以通过多种方式部署到普通保险丝(无织物)中: ###通过部署文件夹 这假设您的容器上已经运行了骆驼功能 cp target/camel-helloworld-fuse-1.0-...
  • Rust的FUSE(用户空间中的文件系统) 关于 FUSE-Rust是一个库文件箱,用于在用户空间中轻松实现。 FUSE-Rust不仅仅提供绑定,它是对原始FUSE C库的重写,以充分利用Rust的体系结构。 该库最初是从叉出来的,目的是...
  • cenos fuse-exfat

    2017-11-02 15:04:17
    linux系统识别,u盘/移动硬盘 exfat格式 centos/redhat 6/7 源码包自建rpm,内附安装说明

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 26,580
精华内容 10,632
关键字:

fuse