From a1d9d0c1292f2370ce6d9bb6abbd070844b4555f Mon Sep 17 00:00:00 2001 From: Xuanwo Date: Fri, 16 Jul 2021 14:37:12 +0800 Subject: [PATCH] vfs: Implement Create support (#13) * vfs: Implement Create support Signed-off-by: Xuanwo * Format code Signed-off-by: Xuanwo --- fuse/hanwen/fs.go | 32 ++++++++++++++++++++++---- vfs/dir.go | 6 +++-- vfs/file.go | 47 ++++++++++++++++++++++++++++++++++++++ vfs/fs.go | 57 +++++++++++++++++++++++++++++++++++++++++++++++ vfs/inode.go | 11 ++++++++- 5 files changed, 146 insertions(+), 7 deletions(-) create mode 100644 vfs/file.go diff --git a/fuse/hanwen/fs.go b/fuse/hanwen/fs.go index ef0a26a..038935d 100644 --- a/fuse/hanwen/fs.go +++ b/fuse/hanwen/fs.go @@ -95,6 +95,11 @@ func fillAttrOut(i *vfs.Inode, out *fuse.AttrOut) fuse.Status { return fuse.OK } +func fillOpenOut(fh *vfs.FileHandle, out *fuse.OpenOut) fuse.Status { + out.Fh = fh.ID + return fuse.OK +} + func parseError(err error) fuse.Status { switch { case errors.Is(err, services.ErrObjectNotExist): @@ -303,7 +308,15 @@ func (fs *FS) Create(cancel <-chan struct{}, input *fuse.CreateIn, name string, return fuse.EINVAL } - // Implement me + i, fh, err := fs.fs.Create(ino.ID, name) + if err != nil { + fs.logger.Error("create", zap.Error(err)) + return fuse.EAGAIN + } + fs.logger.Info("start fill open out") + fillOpenOut(fh, &out.OpenOut) + fs.logger.Info("start fill entry out") + fillEntryOut(i, &out.EntryOut) return fuse.OK } @@ -320,7 +333,12 @@ func (fs *FS) Open(cancel <-chan struct{}, input *fuse.OpenIn, out *fuse.OpenOut return fuse.ENOENT } - panic("implement me") + fh, err := fs.fs.CreateFileHandle(ino) + if err != nil { + fs.logger.Error("create file handle", zap.Error(err)) + return + } + return fillOpenOut(fh, out) } func (fs *FS) Read(cancel <-chan struct{}, input *fuse.ReadIn, buf []byte) (fuse.ReadResult, fuse.Status) { @@ -344,7 +362,12 @@ func (fs *FS) SetLkw(cancel <-chan struct{}, input *fuse.LkIn) (code fuse.Status } func (fs *FS) Release(cancel <-chan struct{}, input *fuse.ReleaseIn) { - panic("implement me") + err := fs.fs.DeleteFileHandle(input.Fh) + if err != nil { + fs.logger.Error("release", + zap.Uint64("file_handle", input.Fh), + zap.Error(err)) + } } func (fs *FS) Write(cancel <-chan struct{}, input *fuse.WriteIn, data []byte) (written uint32, code fuse.Status) { @@ -356,7 +379,8 @@ func (fs *FS) CopyFileRange(cancel <-chan struct{}, input *fuse.CopyFileRangeIn) } func (fs *FS) Flush(cancel <-chan struct{}, input *fuse.FlushIn) fuse.Status { - panic("implement me") + // FIXME: maybe we need to write data here. + return fuse.OK } func (fs *FS) Fsync(cancel <-chan struct{}, input *fuse.FsyncIn) (code fuse.Status) { diff --git a/vfs/dir.go b/vfs/dir.go index b5bb0a9..61f8bbc 100644 --- a/vfs/dir.go +++ b/vfs/dir.go @@ -2,9 +2,11 @@ package vfs import ( "errors" - "github.com/beyondstorage/beyond-fs/meta" - "github.com/beyondstorage/go-storage/v4/types" "sync" + + "github.com/beyondstorage/go-storage/v4/types" + + "github.com/beyondstorage/beyond-fs/meta" ) type dirHandleMap struct { diff --git a/vfs/file.go b/vfs/file.go new file mode 100644 index 0000000..288a785 --- /dev/null +++ b/vfs/file.go @@ -0,0 +1,47 @@ +package vfs + +import ( + "sync" + + "github.com/beyondstorage/beyond-fs/meta" +) + +type fileHandleMap struct { + lock sync.Mutex + m map[uint64]*FileHandle +} + +func newFileHandleMap() *fileHandleMap { + return &fileHandleMap{ + m: make(map[uint64]*FileHandle), + } +} + +func (fhm *fileHandleMap) Get(id uint64) *FileHandle { + fhm.lock.Lock() + defer fhm.lock.Unlock() + + return fhm.m[id] +} + +func (fhm *fileHandleMap) Set(id uint64, dh *FileHandle) { + fhm.lock.Lock() + defer fhm.lock.Unlock() + + fhm.m[id] = dh +} + +func (fhm *fileHandleMap) Delete(id uint64) { + fhm.lock.Lock() + defer fhm.lock.Unlock() + + delete(fhm.m, id) +} + +type FileHandle struct { + ID uint64 + + ino *Inode + fs *FS + meta meta.Service +} diff --git a/vfs/fs.go b/vfs/fs.go index 217b13b..812386b 100644 --- a/vfs/fs.go +++ b/vfs/fs.go @@ -1,7 +1,9 @@ package vfs import ( + "bytes" "fmt" + "time" _ "github.com/beyondstorage/go-service-fs/v3" _ "github.com/beyondstorage/go-service-s3/v2" @@ -32,6 +34,7 @@ type FS struct { meta meta.Service dhm *dirHandleMap + fhm *fileHandleMap logger *zap.Logger } @@ -57,6 +60,7 @@ func NewFS(cfg *Config) (fs *FS, err error) { meta: metaSrv, dhm: newDirHandleMap(), + fhm: newFileHandleMap(), logger: cfg.Logger, } @@ -71,6 +75,39 @@ func NewFS(cfg *Config) (fs *FS, err error) { return fs, err } +func (fs *FS) Create(parent uint64, name string) (ino *Inode, fh *FileHandle, err error) { + // FIXME: we need to handle file exists. + p, err := fs.GetInode(parent) + if err != nil { + return nil, nil, err + } + + path := p.GetEntryPath(name) + _, err = fs.s.Write(path, bytes.NewReader([]byte{}), 0) + if err != nil { + fs.logger.Error("write", zap.String("path", path), zap.Error(err)) + return nil, nil, err + } + + o := fs.s.Create(path) + o.Path = path + o.Mode = types.ModeRead + o.SetContentLength(0) + o.SetLastModified(time.Now()) + + ino = newInode(parent, o) + err = fs.SetInode(ino) + if err != nil { + return + } + + fh, err = fs.CreateFileHandle(ino) + if err != nil { + return + } + return +} + func (fs *FS) Delete(parent uint64, name string) (err error) { ino, err := fs.GetEntry(parent, name) if err != nil { @@ -95,6 +132,26 @@ func (fs *FS) DeleteDir(path string) (err error) { panic("implement me") } +func (fs *FS) CreateFileHandle(ino *Inode) (fh *FileHandle, err error) { + fh = &FileHandle{ + ID: NextHandle(), + ino: ino, + fs: fs, + meta: fs.meta, + } + fs.fhm.Set(fh.ID, fh) + return fh, nil +} + +func (fs *FS) GetFileHandle(fhid uint64) (fh *FileHandle, err error) { + return fs.fhm.Get(fhid), nil +} + +func (fs *FS) DeleteFileHandle(fhid uint64) (err error) { + fs.fhm.Delete(fhid) + return nil +} + func (fs *FS) CreateDirHandle(ino *Inode) (dh *DirHandle, err error) { it, err := fs.s.List(ino.Path, pairs.WithListMode(types.ListModeDir)) if err != nil { diff --git a/vfs/inode.go b/vfs/inode.go index 18c169f..9ef4097 100644 --- a/vfs/inode.go +++ b/vfs/inode.go @@ -1,10 +1,12 @@ package vfs import ( - "github.com/beyondstorage/go-storage/v4/types" + "fmt" "os" "path" "time" + + "github.com/beyondstorage/go-storage/v4/types" ) //go:generate go run github.com/tinylib/msgp @@ -27,6 +29,13 @@ func (ino *Inode) IsDir() bool { return ino.Mode&uint32(os.ModeDir) != 0 } +func (ino *Inode) GetEntryPath(name string) string { + if ino.Path == "" { + return name + } + return fmt.Sprintf("%s/%s", ino.Path, name) +} + func newInode(parent uint64, o *types.Object) *Inode { ino := &Inode{ ID: NextInodeID(),