Commit ef5d1063 authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

Add file/directory/mount tracking for proper EBUSY errors on mounts.

Extends raw API with Release() and ReleaseDir() methods.
parent 0f4e53e7
...@@ -97,6 +97,13 @@ func (self *DummyFuse) OpenDir(header *fuse.InHeader, input *fuse.OpenIn) (flags ...@@ -97,6 +97,13 @@ func (self *DummyFuse) OpenDir(header *fuse.InHeader, input *fuse.OpenIn) (flags
return 0, nil, fuse.ENOSYS return 0, nil, fuse.ENOSYS
} }
func (self *DummyFuse) Release(header *fuse.InHeader, f fuse.RawFuseFile) {
}
func (self *DummyFuse) ReleaseDir(header *fuse.InHeader, f fuse.RawFuseDir) {
}
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
// DummyFuseFile // DummyFuseFile
......
...@@ -11,6 +11,7 @@ import ( ...@@ -11,6 +11,7 @@ import (
"testing" "testing"
"syscall" "syscall"
"rand" "rand"
"time"
) )
var _ = strings.Join var _ = strings.Join
...@@ -634,5 +635,25 @@ func TestRecursiveMount(t *testing.T) { ...@@ -634,5 +635,25 @@ func TestRecursiveMount(t *testing.T) {
if err != nil { if err != nil {
t.Error("lstat submount/file", err) t.Error("lstat submount/file", err)
} }
f, err = os.Open(path.Join(submnt, "hello.txt"), os.O_RDONLY, 0)
if err != nil {
t.Error("open submount/file", err)
}
code = ts.connector.Unmount("/mnt")
if code != fuse.EBUSY {
t.Error("expect EBUSY")
}
f.Close()
// The close takes some time to propagate through FUSE.
time.Sleep(1e9)
code = ts.connector.Unmount("/mnt")
if code != fuse.OK {
t.Error("umount failed.", code)
}
ts.Cleanup() ts.Cleanup()
} }
...@@ -592,6 +592,16 @@ func (self *SubmountFileSystem) OpenDir(header *fuse.InHeader, input *fuse.OpenI ...@@ -592,6 +592,16 @@ func (self *SubmountFileSystem) OpenDir(header *fuse.InHeader, input *fuse.OpenI
return subfs.Fs.OpenDir(header, input) return subfs.Fs.OpenDir(header, input)
} }
func (self *SubmountFileSystem) Release(header *fuse.InHeader, f fuse.RawFuseFile) {
// TODO - should run release on subfs too.
}
func (self *SubmountFileSystem) ReleaseDir(header *fuse.InHeader, f fuse.RawFuseDir) {
// TODO - should run releasedir on subfs too.
}
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
type SubmountFileSystemTopDir struct { type SubmountFileSystemTopDir struct {
...@@ -628,3 +638,4 @@ func (self *SubmountFileSystemTopDir) ReleaseDir() { ...@@ -628,3 +638,4 @@ func (self *SubmountFileSystemTopDir) ReleaseDir() {
func (self *SubmountFileSystemTopDir) FsyncDir(input *fuse.FsyncIn) (code fuse.Status) { func (self *SubmountFileSystemTopDir) FsyncDir(input *fuse.FsyncIn) (code fuse.Status) {
return fuse.ENOENT return fuse.ENOENT
} }
...@@ -501,7 +501,9 @@ func doCreate(state *MountState, header *InHeader, input *CreateIn, name string) ...@@ -501,7 +501,9 @@ func doCreate(state *MountState, header *InHeader, input *CreateIn, name string)
} }
func doRelease(state *MountState, header *InHeader, input *ReleaseIn) (out Empty, code Status) { func doRelease(state *MountState, header *InHeader, input *ReleaseIn) (out Empty, code Status) {
state.FindFile(input.Fh).Release() f := state.FindFile(input.Fh)
state.fileSystem.Release(header, f)
f.Release()
state.UnregisterFile(input.Fh) state.UnregisterFile(input.Fh)
return nil, OK return nil, OK
} }
...@@ -534,7 +536,9 @@ func doSetattr(state *MountState, header *InHeader, input *SetAttrIn) (out *Attr ...@@ -534,7 +536,9 @@ func doSetattr(state *MountState, header *InHeader, input *SetAttrIn) (out *Attr
// Handling directories // Handling directories
func doReleaseDir(state *MountState, header *InHeader, input *ReleaseIn) (out Empty, code Status) { func doReleaseDir(state *MountState, header *InHeader, input *ReleaseIn) (out Empty, code Status) {
state.FindDir(input.Fh).ReleaseDir() d := state.FindDir(input.Fh)
state.fileSystem.ReleaseDir(header, d)
d.ReleaseDir()
state.UnregisterDir(input.Fh) state.UnregisterDir(input.Fh)
return nil, OK return nil, OK
} }
......
...@@ -9,6 +9,22 @@ import ( ...@@ -9,6 +9,22 @@ import (
"strings" "strings"
) )
type mountData struct {
// If non-nil the file system mounted here.
fs PathFilesystem
// If yes, we are looking to unmount the mounted fs.
unmountPending bool
openFiles int
openDirs int
subMounts int
}
func newMount(fs PathFilesystem) *mountData {
return &mountData{fs: fs}
}
// TODO should rename to dentry? // TODO should rename to dentry?
type inodeData struct { type inodeData struct {
Parent *inodeData Parent *inodeData
...@@ -20,11 +36,7 @@ type inodeData struct { ...@@ -20,11 +36,7 @@ type inodeData struct {
// Number of inodeData that have this as parent. // Number of inodeData that have this as parent.
RefCount int RefCount int
// If non-nil the file system mounted here. mount *mountData
Mounted PathFilesystem
// If yes, we are looking to unmount the mounted fs.
unmountPending bool
} }
// Should implement some hash table method instead? // Should implement some hash table method instead?
...@@ -41,22 +53,26 @@ func (self *inodeData) Key() string { ...@@ -41,22 +53,26 @@ func (self *inodeData) Key() string {
return inodeDataKey(p, self.Name) return inodeDataKey(p, self.Name)
} }
func (self *inodeData) GetPath() (path string, fs PathFilesystem) { func (self *inodeData) GetPath() (path string, mount *mountData) {
// TODO - softcode this. // TODO - softcode this.
var components [100]string var components [100]string
j := len(components) j := len(components)
inode := self inode := self
for ; inode != nil && inode.Mounted == nil; inode = inode.Parent { for ; inode != nil && inode.mount == nil; inode = inode.Parent {
j-- j--
components[j] = inode.Name components[j] = inode.Name
} }
if inode == nil {
panic("did not find parent with mount")
}
fullPath := strings.Join(components[j:], "/") fullPath := strings.Join(components[j:], "/")
if !inode.unmountPending { mount = inode.mount
fs = inode.Mounted if mount.unmountPending {
mount = nil
} }
return fullPath, fs return fullPath, mount
} }
type TimeoutOptions struct { type TimeoutOptions struct {
...@@ -167,7 +183,7 @@ func (self *PathFileSystemConnector) forgetUpdate(nodeId uint64, forgetCount int ...@@ -167,7 +183,7 @@ func (self *PathFileSystemConnector) forgetUpdate(nodeId uint64, forgetCount int
data, ok := self.inodePathMapByInode[nodeId] data, ok := self.inodePathMapByInode[nodeId]
if ok { if ok {
data.LookupCount -= forgetCount data.LookupCount -= forgetCount
if data.LookupCount <= 0 && data.RefCount <= 0 && (data.Mounted == nil || data.unmountPending) { if data.LookupCount <= 0 && data.RefCount <= 0 && (data.mount == nil || data.mount.unmountPending) {
self.inodePathMap[data.Key()] = nil, false self.inodePathMap[data.Key()] = nil, false
} }
} }
...@@ -309,34 +325,51 @@ func (self *PathFileSystemConnector) Mount(path string, fs PathFilesystem) Statu ...@@ -309,34 +325,51 @@ func (self *PathFileSystemConnector) Mount(path string, fs PathFilesystem) Statu
log.Println("Mount: ", fs, "on", path, node) log.Println("Mount: ", fs, "on", path, node)
} }
// TODO - this is technically a race-condition. // TODO - this is technically a race-condition?
node.Mounted = fs node.mount = newMount(fs)
node.unmountPending = false if node.Parent != nil {
_, parentMount := node.Parent.GetPath()
parentMount.subMounts++
}
return OK return OK
} }
func (self *PathFileSystemConnector) Unmount(path string) Status { func (self *PathFileSystemConnector) Unmount(path string) Status {
node := self.findInode(path) node := self.findInode(path)
if node == nil || node.Mounted == nil { if node == nil {
panic(path)
}
mount := node.mount
if mount == nil {
panic(path) panic(path)
} }
// TODO - check if we have open files.
if mount.openFiles + mount.openDirs + mount.subMounts > 0 {
log.Println("busy: ", mount)
return EBUSY
}
if self.Debug { if self.Debug {
log.Println("Unmount: ", node) log.Println("Unmount: ", mount)
} }
// node manipulations are racy? // node manipulations are racy?
if node.RefCount > 0 { if node.RefCount > 0 {
node.Mounted.Unmount() mount.fs.Unmount()
node.unmountPending = true mount.unmountPending = true
} else { } else {
node.Mounted = nil node.mount = nil
}
if node.Parent != nil {
_, parentMount := node.Parent.GetPath()
parentMount.subMounts--
} }
return OK return OK
} }
func (self *PathFileSystemConnector) GetPath(nodeid uint64) (path string, fs PathFilesystem) { func (self *PathFileSystemConnector) GetPath(nodeid uint64) (path string, mount *mountData) {
return self.getInodeData(nodeid).GetPath() return self.getInodeData(nodeid).GetPath()
} }
...@@ -355,13 +388,13 @@ func (self *PathFileSystemConnector) Lookup(header *InHeader, name string) (out ...@@ -355,13 +388,13 @@ func (self *PathFileSystemConnector) Lookup(header *InHeader, name string) (out
// TODO - fuse.c has special case code for name == "." and // TODO - fuse.c has special case code for name == "." and
// "..", those lookups happen if FUSE_EXPORT_SUPPORT is set in // "..", those lookups happen if FUSE_EXPORT_SUPPORT is set in
// Init. // Init.
fullPath, fs := parent.GetPath() fullPath, mount := parent.GetPath()
if fs == nil { if mount == nil {
return NegativeEntry(self.options.NegativeTimeout), OK return NegativeEntry(self.options.NegativeTimeout), OK
} }
fullPath = path.Join(fullPath, name) fullPath = path.Join(fullPath, name)
attr, err := fs.GetAttr(fullPath) attr, err := mount.fs.GetAttr(fullPath)
if err == ENOENT && self.options.NegativeTimeout > 0.0 { if err == ENOENT && self.options.NegativeTimeout > 0.0 {
return NegativeEntry(self.options.NegativeTimeout), OK return NegativeEntry(self.options.NegativeTimeout), OK
...@@ -390,11 +423,11 @@ func (self *PathFileSystemConnector) Forget(h *InHeader, input *ForgetIn) { ...@@ -390,11 +423,11 @@ func (self *PathFileSystemConnector) Forget(h *InHeader, input *ForgetIn) {
func (self *PathFileSystemConnector) GetAttr(header *InHeader, input *GetAttrIn) (out *AttrOut, code Status) { func (self *PathFileSystemConnector) GetAttr(header *InHeader, input *GetAttrIn) (out *AttrOut, code Status) {
// TODO - should we update inodeData.Type? // TODO - should we update inodeData.Type?
fullPath, fs := self.GetPath(header.NodeId) fullPath, mount := self.GetPath(header.NodeId)
if fs == nil { if mount == nil {
return nil, ENOENT return nil, ENOENT
} }
attr, err := fs.GetAttr(fullPath) attr, err := mount.fs.GetAttr(fullPath)
if err != OK { if err != OK {
return nil, err return nil, err
} }
...@@ -408,29 +441,34 @@ func (self *PathFileSystemConnector) GetAttr(header *InHeader, input *GetAttrIn) ...@@ -408,29 +441,34 @@ func (self *PathFileSystemConnector) GetAttr(header *InHeader, input *GetAttrIn)
} }
func (self *PathFileSystemConnector) OpenDir(header *InHeader, input *OpenIn) (flags uint32, fuseFile RawFuseDir, status Status) { func (self *PathFileSystemConnector) OpenDir(header *InHeader, input *OpenIn) (flags uint32, fuseFile RawFuseDir, status Status) {
fullPath, fs := self.GetPath(header.NodeId) fullPath, mount := self.GetPath(header.NodeId)
if fs == nil { if mount == nil {
return 0, nil, ENOENT return 0, nil, ENOENT
} }
// TODO - how to handle return flags, the FUSE open flags? // TODO - how to handle return flags, the FUSE open flags?
f, err := fs.OpenDir(fullPath) f, err := mount.fs.OpenDir(fullPath)
if err != OK { if err != OK {
return 0, nil, err return 0, nil, err
} }
// TODO - racy?
mount.openDirs++
return 0, f, OK return 0, f, OK
} }
func (self *PathFileSystemConnector) Open(header *InHeader, input *OpenIn) (flags uint32, fuseFile RawFuseFile, status Status) { func (self *PathFileSystemConnector) Open(header *InHeader, input *OpenIn) (flags uint32, fuseFile RawFuseFile, status Status) {
fullPath, fs := self.GetPath(header.NodeId) fullPath, mount := self.GetPath(header.NodeId)
if fs == nil { if mount == nil {
return 0, nil, ENOENT return 0, nil, ENOENT
} }
// TODO - how to handle return flags, the FUSE open flags? // TODO - how to handle return flags, the FUSE open flags?
f, err := fs.Open(fullPath, input.Flags) f, err := mount.fs.Open(fullPath, input.Flags)
if err != OK { if err != OK {
return 0, nil, err return 0, nil, err
} }
// TODO - racy?
mount.openFiles++
return 0, f, OK return 0, f, OK
} }
...@@ -438,23 +476,23 @@ func (self *PathFileSystemConnector) SetAttr(header *InHeader, input *SetAttrIn) ...@@ -438,23 +476,23 @@ func (self *PathFileSystemConnector) SetAttr(header *InHeader, input *SetAttrIn)
var err Status = OK var err Status = OK
// TODO - support Fh. (FSetAttr/FGetAttr/FTruncate.) // TODO - support Fh. (FSetAttr/FGetAttr/FTruncate.)
fullPath, fs := self.GetPath(header.NodeId) fullPath, mount := self.GetPath(header.NodeId)
if fs == nil { if mount == nil {
return nil, ENOENT return nil, ENOENT
} }
if input.Valid&FATTR_MODE != 0 { if input.Valid&FATTR_MODE != 0 {
err = fs.Chmod(fullPath, input.Mode) err = mount.fs.Chmod(fullPath, input.Mode)
} }
if err != OK && (input.Valid&FATTR_UID != 0 || input.Valid&FATTR_GID != 0) { if err != OK && (input.Valid&FATTR_UID != 0 || input.Valid&FATTR_GID != 0) {
// TODO - can we get just FATTR_GID but not FATTR_UID ? // TODO - can we get just FATTR_GID but not FATTR_UID ?
err = fs.Chown(fullPath, uint32(input.Uid), uint32(input.Gid)) err = mount.fs.Chown(fullPath, uint32(input.Uid), uint32(input.Gid))
} }
if input.Valid&FATTR_SIZE != 0 { if input.Valid&FATTR_SIZE != 0 {
fs.Truncate(fullPath, input.Size) mount.fs.Truncate(fullPath, input.Size)
} }
if err != OK && (input.Valid&FATTR_ATIME != 0 || input.Valid&FATTR_MTIME != 0) { if err != OK && (input.Valid&FATTR_ATIME != 0 || input.Valid&FATTR_MTIME != 0) {
err = fs.Utimens(fullPath, err = mount.fs.Utimens(fullPath,
uint64(input.Atime*1e9)+uint64(input.Atimensec), uint64(input.Atime*1e9)+uint64(input.Atimensec),
uint64(input.Mtime*1e9)+uint64(input.Mtimensec)) uint64(input.Mtime*1e9)+uint64(input.Mtimensec))
} }
...@@ -471,21 +509,21 @@ func (self *PathFileSystemConnector) SetAttr(header *InHeader, input *SetAttrIn) ...@@ -471,21 +509,21 @@ func (self *PathFileSystemConnector) SetAttr(header *InHeader, input *SetAttrIn)
} }
func (self *PathFileSystemConnector) Readlink(header *InHeader) (out []byte, code Status) { func (self *PathFileSystemConnector) Readlink(header *InHeader) (out []byte, code Status) {
fullPath, fs := self.GetPath(header.NodeId) fullPath, mount := self.GetPath(header.NodeId)
if fs == nil { if mount == nil {
return nil, ENOENT return nil, ENOENT
} }
val, err := fs.Readlink(fullPath) val, err := mount.fs.Readlink(fullPath)
return bytes.NewBufferString(val).Bytes(), err return bytes.NewBufferString(val).Bytes(), err
} }
func (self *PathFileSystemConnector) Mknod(header *InHeader, input *MknodIn, name string) (out *EntryOut, code Status) { func (self *PathFileSystemConnector) Mknod(header *InHeader, input *MknodIn, name string) (out *EntryOut, code Status) {
fullPath, fs := self.GetPath(header.NodeId) fullPath, mount := self.GetPath(header.NodeId)
if fs == nil { if mount == nil {
return nil, ENOENT return nil, ENOENT
} }
fullPath = path.Join(fullPath, name) fullPath = path.Join(fullPath, name)
err := fs.Mknod(fullPath, input.Mode, uint32(input.Rdev)) err := mount.fs.Mknod(fullPath, input.Mode, uint32(input.Rdev))
if err != OK { if err != OK {
return nil, err return nil, err
} }
...@@ -493,11 +531,11 @@ func (self *PathFileSystemConnector) Mknod(header *InHeader, input *MknodIn, nam ...@@ -493,11 +531,11 @@ func (self *PathFileSystemConnector) Mknod(header *InHeader, input *MknodIn, nam
} }
func (self *PathFileSystemConnector) Mkdir(header *InHeader, input *MkdirIn, name string) (out *EntryOut, code Status) { func (self *PathFileSystemConnector) Mkdir(header *InHeader, input *MkdirIn, name string) (out *EntryOut, code Status) {
fullPath, fs := self.GetPath(header.NodeId) fullPath, mount := self.GetPath(header.NodeId)
if fs == nil { if mount == nil {
return nil, ENOENT return nil, ENOENT
} }
err := fs.Mkdir(path.Join(fullPath, name), input.Mode) err := mount.fs.Mkdir(path.Join(fullPath, name), input.Mode)
if err != OK { if err != OK {
return nil, err return nil, err
} }
...@@ -506,11 +544,11 @@ func (self *PathFileSystemConnector) Mkdir(header *InHeader, input *MkdirIn, nam ...@@ -506,11 +544,11 @@ func (self *PathFileSystemConnector) Mkdir(header *InHeader, input *MkdirIn, nam
} }
func (self *PathFileSystemConnector) Unlink(header *InHeader, name string) (code Status) { func (self *PathFileSystemConnector) Unlink(header *InHeader, name string) (code Status) {
fullPath, fs := self.GetPath(header.NodeId) fullPath, mount := self.GetPath(header.NodeId)
if fs == nil { if mount == nil {
return ENOENT return ENOENT
} }
code = fs.Unlink(path.Join(fullPath, name)) code = mount.fs.Unlink(path.Join(fullPath, name))
// Like fuse.c, we update our internal tables. // Like fuse.c, we update our internal tables.
self.unlinkUpdate(header.NodeId, name) self.unlinkUpdate(header.NodeId, name)
...@@ -519,21 +557,21 @@ func (self *PathFileSystemConnector) Unlink(header *InHeader, name string) (code ...@@ -519,21 +557,21 @@ func (self *PathFileSystemConnector) Unlink(header *InHeader, name string) (code
} }
func (self *PathFileSystemConnector) Rmdir(header *InHeader, name string) (code Status) { func (self *PathFileSystemConnector) Rmdir(header *InHeader, name string) (code Status) {
fullPath, fs := self.GetPath(header.NodeId) fullPath, mount := self.GetPath(header.NodeId)
if fs == nil { if mount == nil {
return ENOENT return ENOENT
} }
code = fs.Rmdir(path.Join(fullPath, name)) code = mount.fs.Rmdir(path.Join(fullPath, name))
self.unlinkUpdate(header.NodeId, name) self.unlinkUpdate(header.NodeId, name)
return code return code
} }
func (self *PathFileSystemConnector) Symlink(header *InHeader, pointedTo string, linkName string) (out *EntryOut, code Status) { func (self *PathFileSystemConnector) Symlink(header *InHeader, pointedTo string, linkName string) (out *EntryOut, code Status) {
fullPath, fs := self.GetPath(header.NodeId) fullPath, mount := self.GetPath(header.NodeId)
if fs == nil { if mount == nil {
return nil, ENOENT return nil, ENOENT
} }
err := fs.Symlink(pointedTo, path.Join(fullPath, linkName)) err := mount.fs.Symlink(pointedTo, path.Join(fullPath, linkName))
if err != OK { if err != OK {
return nil, err return nil, err
} }
...@@ -543,18 +581,18 @@ func (self *PathFileSystemConnector) Symlink(header *InHeader, pointedTo string, ...@@ -543,18 +581,18 @@ func (self *PathFileSystemConnector) Symlink(header *InHeader, pointedTo string,
} }
func (self *PathFileSystemConnector) Rename(header *InHeader, input *RenameIn, oldName string, newName string) (code Status) { func (self *PathFileSystemConnector) Rename(header *InHeader, input *RenameIn, oldName string, newName string) (code Status) {
oldPath, oldFs := self.GetPath(header.NodeId) oldPath, oldMount := self.GetPath(header.NodeId)
newPath, fs := self.GetPath(input.Newdir) newPath, mount := self.GetPath(input.Newdir)
if fs == nil || oldFs == nil { if mount == nil || oldMount == nil {
return ENOENT return ENOENT
} }
if fs != oldFs { if mount != oldMount {
return EXDEV return EXDEV
} }
oldPath = path.Join(oldPath, oldName) oldPath = path.Join(oldPath, oldName)
newPath = path.Join(newPath, newName) newPath = path.Join(newPath, newName)
code = fs.Rename(oldPath, newPath) code = mount.fs.Rename(oldPath, newPath)
if code != OK { if code != OK {
return return
} }
...@@ -571,18 +609,17 @@ func (self *PathFileSystemConnector) Rename(header *InHeader, input *RenameIn, o ...@@ -571,18 +609,17 @@ func (self *PathFileSystemConnector) Rename(header *InHeader, input *RenameIn, o
} }
func (self *PathFileSystemConnector) Link(header *InHeader, input *LinkIn, filename string) (out *EntryOut, code Status) { func (self *PathFileSystemConnector) Link(header *InHeader, input *LinkIn, filename string) (out *EntryOut, code Status) {
orig, fs := self.GetPath(input.Oldnodeid) orig, mount := self.GetPath(input.Oldnodeid)
newName, newFs := self.GetPath(header.NodeId) newName, newMount := self.GetPath(header.NodeId)
if fs == nil || newFs == nil { if mount == nil || newMount == nil {
return nil, ENOENT return nil, ENOENT
} }
if mount != newMount {
if newFs != fs {
return nil, EXDEV return nil, EXDEV
} }
newName = path.Join(newName, filename) newName = path.Join(newName, filename)
err := fs.Link(orig, newName) err := mount.fs.Link(orig, newName)
if err != OK { if err != OK {
return nil, err return nil, err
...@@ -592,29 +629,40 @@ func (self *PathFileSystemConnector) Link(header *InHeader, input *LinkIn, filen ...@@ -592,29 +629,40 @@ func (self *PathFileSystemConnector) Link(header *InHeader, input *LinkIn, filen
} }
func (self *PathFileSystemConnector) Access(header *InHeader, input *AccessIn) (code Status) { func (self *PathFileSystemConnector) Access(header *InHeader, input *AccessIn) (code Status) {
p, fs := self.GetPath(header.NodeId) p, mount := self.GetPath(header.NodeId)
if fs == nil { if mount == nil {
return ENOENT return ENOENT
} }
return fs.Access(p, input.Mask) return mount.fs.Access(p, input.Mask)
} }
func (self *PathFileSystemConnector) Create(header *InHeader, input *CreateIn, name string) (flags uint32, fuseFile RawFuseFile, out *EntryOut, code Status) { func (self *PathFileSystemConnector) Create(header *InHeader, input *CreateIn, name string) (flags uint32, fuseFile RawFuseFile, out *EntryOut, code Status) {
directory, fs := self.GetPath(header.NodeId) directory, mount := self.GetPath(header.NodeId)
if fs == nil { if mount == nil {
return 0, nil, nil, ENOENT return 0, nil, nil, ENOENT
} }
fullPath := path.Join(directory, name) fullPath := path.Join(directory, name)
f, err := fs.Create(fullPath, uint32(input.Flags), input.Mode) f, err := mount.fs.Create(fullPath, uint32(input.Flags), input.Mode)
if err != OK { if err != OK {
return 0, nil, nil, err return 0, nil, nil, err
} }
mount.openFiles++
out, code = self.Lookup(header, name) out, code = self.Lookup(header, name)
return 0, f, out, code return 0, f, out, code
} }
func (self *PathFileSystemConnector) Release(header *InHeader, f RawFuseFile) {
_, mount := self.GetPath(header.NodeId)
mount.openFiles--
}
func (self *PathFileSystemConnector) ReleaseDir(header *InHeader, f RawFuseDir) {
_, mount := self.GetPath(header.NodeId)
mount.openDirs--
}
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
// unimplemented. // unimplemented.
......
...@@ -531,6 +531,9 @@ type RawFileSystem interface { ...@@ -531,6 +531,9 @@ type RawFileSystem interface {
// The return flags are FOPEN_xx. // The return flags are FOPEN_xx.
Open(header *InHeader, input *OpenIn) (flags uint32, fuseFile RawFuseFile, status Status) Open(header *InHeader, input *OpenIn) (flags uint32, fuseFile RawFuseFile, status Status)
OpenDir(header *InHeader, input *OpenIn) (flags uint32, fuseFile RawFuseDir, status Status) OpenDir(header *InHeader, input *OpenIn) (flags uint32, fuseFile RawFuseDir, status Status)
Release(header *InHeader, f RawFuseFile)
ReleaseDir(header *InHeader, f RawFuseDir)
} }
type RawFuseFile interface { type RawFuseFile interface {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment