用户空间的文件系统(FUSE),无需理解文件系统的内幕,也不用学习内核模块编程的知识,就可以开发用户空间的文件系统框架。在用户空间的文件系统出现之前,文件系统的开发曾是内核开发人员的工作。创建文件系统需要了解内核编程和内核技术(例如 vfs)方面的知识。调试则需要 C 和 C++ 方面的专业技能。使用 FUSE 您可以开发功能完备的文件系统:其具有简单的 API 库,可以被非特权用户访问,并可以安全的实施。更重要的是,FUSE 以往的表现充分证明了其稳定性。
使用 FUSE,您可以像可执行二进制文件一样来开发文件系统,它们需要链接到 FUSE 库上 —— 换言之,这个文件系统框架并不需要您了解文件系统的内幕和内核模块编程的知识。要在 FUSE 中创建一个文件系统,您需要安装一个 FUSE 内核模块,然后使用 FUSE 库和 API 来创建自己的文件系统。
要开发一个文件系统,首先请下载 FUSE 的源代码(请参阅 参考资料)并展开这个包:tar -zxvf fuse-2.2.tar.gz。这会创建一个 FUSE 目录,其中保存的是源代码。fuse-2.2 目录的内容如下:
./doc 包含了与 FUSE 有关的文档。现在,这只有一个文件 how-fuse-works。
./kernel 包含了 FUSE 内核模块的源代码(对于使用 FUSE 开发文件系统来说,您当然不用懂得这些代码的机制)。
./include 包含了 FUSE API 头,您需要这些文件来创建文件系统。您现在唯一需要的就是 fuse.h。
./lib 中存放的是创建 FUSE 库的源代码,您需要将它们与您的二进制文件链接在一起来创建文件系统。
./util 中存放的是 FUSE 工具库的源代码。
./example 当然包含的是一些供您参考的例子,例如 fusexmp.null 和 hello 文件系统。
Fuse开发文件系统的GO语言库bazil.org/fuse:https://godoc.org/bazil.org/fuse
https://bazil.org/fuse/fs/ 这个是fuse文件系统的高层级接口:https://bazil.org/fuse/fs/
bazil.org/fuse/fs
contains a higher-level API for creating FUSE filesystems, that keeps track of directory entries and open files the kernel knows about.
Servers of synthesized file systems tend to share common bookkeeping abstracted away by the second approach, which is to call fs.Serve to serve the FUSE protocol using an implementation of the service methods in the interfaces FS* (file system), Node* (file or directory), and Handle* (opened file or directory).
vim的 godef安装
[root@localhost cgroupfs-master]# go get code.google.com/p/rog-go/exp/cmd/godef
package code.google.com/p/rog-go/exp/cmd/godef: unable to detect version control system for code.google.com/ path
[root@localhost cgroupfs-master]# go get github.com/rogpeppe/godef
Go语言下的hello.go
// Hellofs implements a simple "hello world" file system.
package main
import (
"flag"
"fmt"
"log"
"os"
"bazil.org/fuse"
"bazil.org/fuse/fs"
_ "bazil.org/fuse/fs/fstestutil"
"golang.org/x/net/context"
)
func usage() {
fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
fmt.Fprintf(os.Stderr, " %s MOUNTPOINT\n", os.Args[0])
flag.PrintDefaults()
}
func main() {
flag.Usage = usage
flag.Parse()
if flag.NArg() != 1 {
usage()
os.Exit(2)
}
mountpoint := flag.Arg(0)
c, err := fuse.Mount( //建立一个新的fuse连接,返回一个连接c 用于读写
mountpoint,
fuse.FSName("helloworld"),
fuse.Subtype("hellofs"),
fuse.LocalVolume(),
fuse.VolumeName("Hello world!"),
)
if err != nil {
log.Fatal(err)
}
defer c.Close()
err = fs.Serve(c, FS{})//使用连接c提供服务。An FS is the interface required of a file system.
if err != nil {
log.Fatal(err)
}
// check if the mount process has an error to report
<-c.Ready
if err := c.MountError; err != nil {
log.Fatal(err)
}
}
// FS implements the hello world file system.
type FS struct{}
func (FS) Root() (fs.Node, error) { //FS实现root接口
return Dir{}, nil
}
// Dir implements both Node and Handle for the root directory.
type Dir struct{}
func (Dir) Attr(ctx context.Context, a *fuse.Attr) error {
a.Inode = 1
a.Mode = os.ModeDir | 0555
return nil
}
func (Dir) Lookup(ctx context.Context, name string) (fs.Node, error) {
if name == "hello" {
return File{}, nil
}
return nil, fuse.ENOENT
}
var dirDirs = []fuse.Dirent{
{Inode: 2, Name: "hello", Type: fuse.DT_File},
}
func (Dir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
return dirDirs, nil
}
// File implements both Node and Handle for the hello file.
type File struct{}
const greeting = "hello, world\n"
func (File) Attr(ctx context.Context, a *fuse.Attr) error {
a.Inode = 2
a.Mode = 0444
a.Size = uint64(len(greeting))
return nil
}
func (File) ReadAll(ctx context.Context) ([]byte, error) {
return []byte(greeting), nil
}
fuse的原理说明:
FUSE内核模块实现VFS接口(实现fuse文件驱动模块的注册、fuse 的(虚拟)设备驱动、提供supper block、dentry、inode的维护),接收来至后者的请求,传递给LibFUSE,LibFUSE再传递给我们用户程序的接口进行实现操作。