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

Move file handle management into PathFileSystemConnector.

parent 07bf2acc
......@@ -25,8 +25,8 @@ func (me *DefaultRawFuseFileSystem) GetAttr(header *InHeader, input *GetAttrIn)
return nil, ENOSYS
}
func (me *DefaultRawFuseFileSystem) Open(header *InHeader, input *OpenIn) (flags uint32, fuseFile RawFuseFile, status Status) {
return 0, nil, OK
func (me *DefaultRawFuseFileSystem) Open(header *InHeader, input *OpenIn) (flags uint32, handle uint64, status Status) {
return 0, 0, OK
}
func (me *DefaultRawFuseFileSystem) SetAttr(header *InHeader, input *SetAttrIn) (out *AttrOut, code Status) {
......@@ -85,8 +85,8 @@ func (me *DefaultRawFuseFileSystem) Access(header *InHeader, input *AccessIn) (c
return ENOSYS
}
func (me *DefaultRawFuseFileSystem) Create(header *InHeader, input *CreateIn, name string) (flags uint32, fuseFile RawFuseFile, out *EntryOut, code Status) {
return 0, nil, nil, ENOSYS
func (me *DefaultRawFuseFileSystem) Create(header *InHeader, input *CreateIn, name string) (flags uint32, handle uint64, out *EntryOut, code Status) {
return 0, 0, nil, ENOSYS
}
func (me *DefaultRawFuseFileSystem) Bmap(header *InHeader, input *BmapIn) (out *BmapOut, code Status) {
......@@ -105,12 +105,27 @@ func (me *DefaultRawFuseFileSystem) OpenDir(header *InHeader, input *OpenIn) (fl
return 0, nil, ENOSYS
}
func (me *DefaultRawFuseFileSystem) Release(header *InHeader, f RawFuseFile) {
func (me *DefaultRawFuseFileSystem) ReleaseDir(header *InHeader, f RawFuseDir) {
}
func (me *DefaultRawFuseFileSystem) ReleaseDir(header *InHeader, f RawFuseDir) {
func (me *DefaultRawFuseFileSystem) Read(*ReadIn, *BufferPool) ([]byte, Status) {
return nil, ENOSYS
}
func (me *DefaultRawFuseFileSystem) Release(header *InHeader, input *ReleaseIn) {
}
func (me *DefaultRawFuseFileSystem) Write(input *WriteIn, data []byte) (written uint32, code Status) {
return 0, ENOSYS
}
func (me *DefaultRawFuseFileSystem) Flush(input *FlushIn) Status {
return OK
}
func (me *DefaultRawFuseFileSystem) Fsync(input *FsyncIn) (code Status) {
return ENOSYS
}
////////////////////////////////////////////////////////////////
// DefaultRawFuseFile
......
......@@ -453,15 +453,15 @@ func (me *MountState) dispatch(req *fuseRequest) {
case FUSE_OPEN:
req.data, status = doOpen(me, h, (*OpenIn)(inData))
case FUSE_READ:
req.flatData, status = doRead(me, h, (*ReadIn)(inData), me.buffers)
req.flatData, status = me.fileSystem.Read((*ReadIn)(inData), me.buffers)
case FUSE_WRITE:
req.data, status = doWrite(me, h, (*WriteIn)(inData), data)
case FUSE_FLUSH:
status = doFlush(me, h, (*FlushIn)(inData))
status = me.fileSystem.Flush((*FlushIn)(inData))
case FUSE_RELEASE:
status = doRelease(me, h, (*ReleaseIn)(inData))
me.fileSystem.Release(h, (*ReleaseIn)(inData))
case FUSE_FSYNC:
status = doFsync(me, h, (*FsyncIn)(inData))
status = me.fileSystem.Fsync((*FsyncIn)(inData))
case FUSE_OPENDIR:
req.data, status = doOpenDir(me, h, (*OpenIn)(inData))
case FUSE_READDIR:
......@@ -583,63 +583,38 @@ func initFuse(state *MountState, h *InHeader, input *InitIn) (unsafe.Pointer, St
// Handling files.
func doOpen(state *MountState, header *InHeader, input *OpenIn) (unsafe.Pointer, Status) {
flags, fuseFile, status := state.fileSystem.Open(header, input)
flags, handle, status := state.fileSystem.Open(header, input)
if status != OK {
return nil, status
}
if fuseFile == nil {
fmt.Println("fuseFile should not be nil.")
}
out := new(OpenOut)
out.Fh = state.RegisterFile(fuseFile)
out.Fh = handle
out.OpenFlags = flags
return unsafe.Pointer(out), status
}
func doCreate(state *MountState, header *InHeader, input *CreateIn, name string) (unsafe.Pointer, Status) {
flags, fuseFile, entry, status := state.fileSystem.Create(header, input, name)
flags, handle, entry, status := state.fileSystem.Create(header, input, name)
if status != OK {
return nil, status
}
if fuseFile == nil {
fmt.Println("fuseFile should not be nil.")
}
out := new(CreateOut)
out.Entry = *entry
out.Open.Fh = state.RegisterFile(fuseFile)
out.Open.Fh = handle
out.Open.OpenFlags = flags
return unsafe.Pointer(out), status
}
func doRelease(state *MountState, header *InHeader, input *ReleaseIn) (code Status) {
f := state.FindFile(input.Fh)
state.fileSystem.Release(header, f)
f.Release()
state.UnregisterFile(input.Fh)
return OK
}
func doRead(state *MountState, header *InHeader, input *ReadIn, buffers *BufferPool) (out []byte, code Status) {
output, code := state.FindFile(input.Fh).Read(input, buffers)
return output, code
}
func doWrite(state *MountState, header *InHeader, input *WriteIn, data []byte) (out unsafe.Pointer, code Status) {
n, status := state.FindFile(input.Fh).Write(input, data)
o := new(WriteOut)
o.Size = n
n, status := state.fileSystem.Write(input, data)
o := &WriteOut{
Size: n,
}
return unsafe.Pointer(o), status
}
func doFsync(state *MountState, header *InHeader, input *FsyncIn) (code Status) {
return state.FindFile(input.Fh).Fsync(input)
}
func doFlush(state *MountState, header *InHeader, input *FlushIn) (code Status) {
return state.FindFile(input.Fh).Flush()
}
func doSetattr(state *MountState, header *InHeader, input *SetAttrIn) (out unsafe.Pointer, code Status) {
// TODO - if Fh != 0, we should do a FSetAttr instead.
o, s := state.fileSystem.SetAttr(header, input)
......
......@@ -164,6 +164,12 @@ type LockingRawFilesystem struct {
lock sync.Mutex
}
func NewLockingRawFilesystem(rfs RawFileSystem) *LockingRawFilesystem {
l := &LockingRawFilesystem{}
l.Original = rfs
return l
}
func (me *LockingRawFilesystem) Init(h *InHeader, input *InitIn) (*InitOut, Status) {
me.lock.Lock()
defer me.lock.Unlock()
......@@ -194,7 +200,7 @@ func (me *LockingRawFilesystem) GetAttr(header *InHeader, input *GetAttrIn) (out
return me.Original.GetAttr(header, input)
}
func (me *LockingRawFilesystem) Open(header *InHeader, input *OpenIn) (flags uint32, fuseFile RawFuseFile, status Status) {
func (me *LockingRawFilesystem) Open(header *InHeader, input *OpenIn) (flags uint32, handle uint64, status Status) {
me.lock.Lock()
defer me.lock.Unlock()
return me.Original.Open(header, input)
......@@ -284,7 +290,7 @@ func (me *LockingRawFilesystem) Access(header *InHeader, input *AccessIn) (code
return me.Original.Access(header, input)
}
func (me *LockingRawFilesystem) Create(header *InHeader, input *CreateIn, name string) (flags uint32, fuseFile RawFuseFile, out *EntryOut, code Status) {
func (me *LockingRawFilesystem) Create(header *InHeader, input *CreateIn, name string) (flags uint32, handle uint64, out *EntryOut, code Status) {
me.lock.Lock()
defer me.lock.Unlock()
return me.Original.Create(header, input, name)
......@@ -314,10 +320,10 @@ func (me *LockingRawFilesystem) OpenDir(header *InHeader, input *OpenIn) (flags
return me.Original.OpenDir(header, input)
}
func (me *LockingRawFilesystem) Release(header *InHeader, f RawFuseFile) {
func (me *LockingRawFilesystem) Release(header *InHeader, input *ReleaseIn) {
me.lock.Lock()
defer me.lock.Unlock()
me.Original.Release(header, f)
me.Original.Release(header, input)
}
func (me *LockingRawFilesystem) ReleaseDir(header *InHeader, f RawFuseDir) {
......@@ -325,3 +331,19 @@ func (me *LockingRawFilesystem) ReleaseDir(header *InHeader, f RawFuseDir) {
defer me.lock.Unlock()
me.Original.ReleaseDir(header, f)
}
func (me *LockingRawFilesystem) Read(input *ReadIn, bp *BufferPool) ([]byte, Status) {
return me.Original.Read(input, bp)
}
func (me *LockingRawFilesystem) Write(input *WriteIn, data []byte) (written uint32, code Status) {
return me.Original.Write(input, data)
}
func (me *LockingRawFilesystem) Flush(input *FlushIn) Status {
return me.Original.Flush(input)
}
func (me *LockingRawFilesystem) Fsync(input *FsyncIn) (code Status) {
return me.Original.Fsync(input)
}
......@@ -54,8 +54,16 @@ func (me *testCase) Setup(t *testing.T) {
me.origSubdir = filepath.Join(me.origDir, subdir)
me.origSubfile = filepath.Join(me.origSubdir, "subfile")
pfs := NewLoopbackFileSystem(me.origDir)
var pfs PathFilesystem
pfs = NewLoopbackFileSystem(me.origDir)
pfs = NewTimingPathFilesystem(pfs)
pfs = NewLockingPathFilesystem(pfs)
var rfs RawFileSystem
me.connector = NewPathFileSystemConnector(pfs)
rfs = NewTimingRawFilesystem(me.connector)
rfs = NewLockingRawFilesystem(rfs)
me.connector.Debug = true
me.state = NewMountState(me.connector)
me.state.Mount(me.mountPoint)
......
......@@ -43,7 +43,8 @@ type inode struct {
NodeId uint64
Name string
LookupCount int
OpenCount int
// ?
Type uint32
mount *mountData
......@@ -137,15 +138,56 @@ type PathFileSystemConnectorOptions struct {
type PathFileSystemConnector struct {
DefaultRawFuseFileSystem
// Protects the hashmap, its contents and the nextFreeInode counter.
options PathFileSystemConnectorOptions
Debug bool
////////////////
// Protects the inode hashmap, its contents and the nextFreeInode counter.
lock sync.RWMutex
// Invariants: see the verify() method.
inodeMap map[uint64]*inode
nextFreeInode uint64
options PathFileSystemConnectorOptions
Debug bool
// Open files/directories.
fileLock sync.RWMutex
openFiles map[uint64]RawFuseFile
nextFreeHandle uint64
}
func (me *PathFileSystemConnector) unregisterFile(node *inode, handle uint64) RawFuseFile {
me.fileLock.Lock()
defer me.fileLock.Unlock()
f, ok := me.openFiles[handle]
if !ok {
panic("invalid handle")
}
me.openFiles[handle] = nil, false
node.OpenCount--
return f
}
func (me *PathFileSystemConnector) getFile(h uint64) RawFuseFile {
me.fileLock.RLock()
defer me.fileLock.RUnlock()
return me.openFiles[h]
}
func (me *PathFileSystemConnector) registerFile(node *inode, f RawFuseFile) uint64 {
me.fileLock.Lock()
defer me.fileLock.Unlock()
h := me.nextFreeHandle
me.nextFreeHandle++
_, ok := me.openFiles[h]
if ok {
panic("handle counter wrapped")
}
node.OpenCount++
me.openFiles[h] = f
return h
}
func (me *PathFileSystemConnector) verify() {
......@@ -166,7 +208,7 @@ func (me *PathFileSystemConnector) newInode() *inode {
me.nextFreeInode++
me.inodeMap[data.NodeId] = data
return data
}
......@@ -275,7 +317,8 @@ func (me *PathFileSystemConnector) findInode(fullPath string) *inode {
func NewPathFileSystemConnector(fs PathFilesystem) (out *PathFileSystemConnector) {
out = new(PathFileSystemConnector)
out.inodeMap = make(map[uint64]*inode)
out.openFiles = make(map[uint64]RawFuseFile)
out.nextFreeInode = FUSE_ROOT_ID
rootData := out.newInode()
rootData.NodeId = FUSE_ROOT_ID
......@@ -299,7 +342,6 @@ func (me *PathFileSystemConnector) SetOptions(opts PathFileSystemConnectorOption
me.options = opts
}
func (me *PathFileSystemConnector) Mount(mountPoint string, fs PathFilesystem) Status {
var node *inode
......@@ -399,23 +441,28 @@ func (me *PathFileSystemConnector) Lookup(header *InHeader, name string) (out *E
}
func (me *PathFileSystemConnector) internalLookup(parent *inode, name string, lookupCount int) (out *EntryOut, status Status) {
out, status, _ = me.internalLookupWithNode(parent, name, lookupCount)
return out, status
}
func (me *PathFileSystemConnector) internalLookupWithNode(parent *inode, name string, lookupCount int) (out *EntryOut, status Status, node *inode) {
// TODO - fuse.c has special case code for name == "." and
// "..", those lookups happen if FUSE_EXPORT_SUPPORT is set in
// Init.
fullPath, mount := parent.GetPath()
if mount == nil {
return NegativeEntry(me.options.NegativeTimeout), OK
return NegativeEntry(me.options.NegativeTimeout), OK, nil
}
fullPath = filepath.Join(fullPath, name)
attr, err := mount.fs.GetAttr(fullPath)
if err == ENOENT && me.options.NegativeTimeout > 0.0 {
return NegativeEntry(me.options.NegativeTimeout), OK
return NegativeEntry(me.options.NegativeTimeout), OK, nil
}
if err != OK {
return nil, err
return nil, err, nil
}
data := me.lookupUpdate(parent, name, attr.Mode&S_IFDIR != 0)
......@@ -430,7 +477,7 @@ func (me *PathFileSystemConnector) internalLookup(parent *inode, name string, lo
SplitNs(me.options.AttrTimeout, &out.AttrValid, &out.AttrValidNsec)
out.Attr = *attr
out.Attr.Ino = data.NodeId
return out, OK
return out, OK, data
}
func (me *PathFileSystemConnector) Forget(h *InHeader, input *ForgetIn) {
......@@ -476,19 +523,21 @@ func (me *PathFileSystemConnector) OpenDir(header *InHeader, input *OpenIn) (fla
return 0, de, OK
}
func (me *PathFileSystemConnector) Open(header *InHeader, input *OpenIn) (flags uint32, fuseFile RawFuseFile, status Status) {
fullPath, mount, _ := me.GetPath(header.NodeId)
func (me *PathFileSystemConnector) Open(header *InHeader, input *OpenIn) (flags uint32, handle uint64, status Status) {
fullPath, mount, node := me.GetPath(header.NodeId)
if mount == nil {
return 0, nil, ENOENT
return 0, 0, ENOENT
}
// TODO - how to handle return flags, the FUSE open flags?
f, err := mount.fs.Open(fullPath, input.Flags)
if err != OK {
return 0, nil, err
return 0, 0, err
}
h := me.registerFile(node, f)
mount.incOpenCount(1)
return 0, f, OK
return 0, h, OK
}
func (me *PathFileSystemConnector) SetAttr(header *InHeader, input *SetAttrIn) (out *AttrOut, code Status) {
......@@ -654,26 +703,27 @@ func (me *PathFileSystemConnector) Access(header *InHeader, input *AccessIn) (co
return mount.fs.Access(p, input.Mask)
}
func (me *PathFileSystemConnector) Create(header *InHeader, input *CreateIn, name string) (flags uint32, fuseFile RawFuseFile, out *EntryOut, code Status) {
func (me *PathFileSystemConnector) Create(header *InHeader, input *CreateIn, name string) (flags uint32, h uint64, out *EntryOut, code Status) {
directory, mount, parent := me.GetPath(header.NodeId)
if mount == nil {
return 0, nil, nil, ENOENT
return 0, 0, nil, ENOENT
}
fullPath := filepath.Join(directory, name)
f, err := mount.fs.Create(fullPath, uint32(input.Flags), input.Mode)
if err != OK {
return 0, nil, nil, err
return 0, 0, nil, err
}
out, code, inode := me.internalLookupWithNode(parent, name, 1)
mount.incOpenCount(1)
out, code = me.internalLookup(parent, name, 1)
return 0, f, out, code
return 0, me.registerFile(inode, f), out, code
}
func (me *PathFileSystemConnector) Release(header *InHeader, f RawFuseFile) {
_, mount, _ := me.GetPath(header.NodeId)
func (me *PathFileSystemConnector) Release(header *InHeader, input *ReleaseIn) {
_, mount, node := me.GetPath(header.NodeId)
f := me.unregisterFile(node, input.Fh)
f.Release()
if mount != nil {
mount.incOpenCount(-1)
}
......@@ -733,3 +783,13 @@ func (me *PathFileSystemConnector) ListXAttr(header *InHeader) (data []byte, cod
return b.Bytes(), code
}
func (me *PathFileSystemConnector) Write(input *WriteIn, data []byte) (written uint32, code Status) {
f := me.getFile(input.Fh)
return f.Write(input, data)
}
func (me *PathFileSystemConnector) Read(input *ReadIn, bp *BufferPool) ([]byte, Status) {
f := me.getFile(input.Fh)
return f.Read(input, bp)
}
......@@ -71,7 +71,7 @@ func (me *TimingRawFilesystem) GetAttr(header *InHeader, input *GetAttrIn) (out
return me.Original.GetAttr(header, input)
}
func (me *TimingRawFilesystem) Open(header *InHeader, input *OpenIn) (flags uint32, fuseFile RawFuseFile, status Status) {
func (me *TimingRawFilesystem) Open(header *InHeader, input *OpenIn) (flags uint32, handle uint64, status Status) {
defer me.startTimer("Open")()
return me.Original.Open(header, input)
}
......@@ -146,7 +146,7 @@ func (me *TimingRawFilesystem) Access(header *InHeader, input *AccessIn) (code S
return me.Original.Access(header, input)
}
func (me *TimingRawFilesystem) Create(header *InHeader, input *CreateIn, name string) (flags uint32, fuseFile RawFuseFile, out *EntryOut, code Status) {
func (me *TimingRawFilesystem) Create(header *InHeader, input *CreateIn, name string) (flags uint32, handle uint64, out *EntryOut, code Status) {
defer me.startTimer("Create")()
return me.Original.Create(header, input, name)
}
......@@ -171,12 +171,32 @@ func (me *TimingRawFilesystem) OpenDir(header *InHeader, input *OpenIn) (flags u
return me.Original.OpenDir(header, input)
}
func (me *TimingRawFilesystem) Release(header *InHeader, f RawFuseFile) {
func (me *TimingRawFilesystem) Release(header *InHeader, input *ReleaseIn) {
defer me.startTimer("Release")()
me.Original.Release(header, f)
me.Original.Release(header, input)
}
func (me *TimingRawFilesystem) ReleaseDir(header *InHeader, f RawFuseDir) {
defer me.startTimer("ReleaseDir")()
me.Original.ReleaseDir(header, f)
}
func (me *TimingRawFilesystem) Read(input *ReadIn, bp *BufferPool) ([]byte, Status) {
defer me.startTimer("Read")()
return me.Original.Read(input, bp)
}
func (me *TimingRawFilesystem) Write(input *WriteIn, data []byte) (written uint32, code Status) {
defer me.startTimer("Write")()
return me.Original.Write(input, data)
}
func (me *TimingRawFilesystem) Flush(input *FlushIn) Status {
defer me.startTimer("Flush")()
return me.Original.Flush(input)
}
func (me *TimingRawFilesystem) Fsync(input *FsyncIn) (code Status) {
defer me.startTimer("Fsync")()
return me.Original.Fsync(input)
}
......@@ -524,17 +524,23 @@ type RawFileSystem interface {
SetXAttr(header *InHeader, input *SetXAttrIn, attr string, data []byte) Status
RemoveXAttr(header *InHeader, attr string) (code Status)
Access(header *InHeader, input *AccessIn) (code Status)
Create(header *InHeader, input *CreateIn, name string) (flags uint32, fuseFile RawFuseFile, out *EntryOut, code Status)
Create(header *InHeader, input *CreateIn, name string) (flags uint32, handle uint64, out *EntryOut, code Status)
Bmap(header *InHeader, input *BmapIn) (out *BmapOut, code Status)
Ioctl(header *InHeader, input *IoctlIn) (out *IoctlOut, code Status)
Poll(header *InHeader, input *PollIn) (out *PollOut, code Status)
// The return flags are FOPEN_xx.
Open(header *InHeader, input *OpenIn) (flags uint32, fuseFile RawFuseFile, status Status)
Open(header *InHeader, input *OpenIn) (flags uint32, handle uint64, status Status)
OpenDir(header *InHeader, input *OpenIn) (flags uint32, fuseFile RawFuseDir, status Status)
Release(header *InHeader, f RawFuseFile)
ReleaseDir(header *InHeader, f RawFuseDir)
// File handling.
Read(*ReadIn, *BufferPool) ([]byte, Status)
Release(header *InHeader, input *ReleaseIn)
Write(*WriteIn, []byte) (written uint32, code Status)
Flush(*FlushIn) Status
Fsync(*FsyncIn) (code Status)
}
type RawFuseFile interface {
......
......@@ -105,7 +105,6 @@ type WrappingRawFilesystem struct {
Original RawFileSystem
}
func (me *WrappingRawFilesystem) Init(h *InHeader, input *InitIn) (*InitOut, Status) {
return me.Original.Init(h, input)
}
......@@ -126,7 +125,7 @@ func (me *WrappingRawFilesystem) GetAttr(header *InHeader, input *GetAttrIn) (ou
return me.Original.GetAttr(header, input)
}
func (me *WrappingRawFilesystem) Open(header *InHeader, input *OpenIn) (flags uint32, fuseFile RawFuseFile, status Status) {
func (me *WrappingRawFilesystem) Open(header *InHeader, input *OpenIn) (flags uint32, handle uint64, status Status) {
return me.Original.Open(header, input)
}
......@@ -186,7 +185,7 @@ func (me *WrappingRawFilesystem) Access(header *InHeader, input *AccessIn) (code
return me.Original.Access(header, input)
}
func (me *WrappingRawFilesystem) Create(header *InHeader, input *CreateIn, name string) (flags uint32, fuseFile RawFuseFile, out *EntryOut, code Status) {
func (me *WrappingRawFilesystem) Create(header *InHeader, input *CreateIn, name string) (flags uint32, handle uint64, out *EntryOut, code Status) {
return me.Original.Create(header, input, name)
}
......@@ -206,10 +205,26 @@ func (me *WrappingRawFilesystem) OpenDir(header *InHeader, input *OpenIn) (flags
return me.Original.OpenDir(header, input)
}
func (me *WrappingRawFilesystem) Release(header *InHeader, f RawFuseFile) {
me.Original.Release(header, f)
func (me *WrappingRawFilesystem) Release(header *InHeader, input *ReleaseIn) {
me.Original.Release(header, input)
}
func (me *WrappingRawFilesystem) ReleaseDir(header *InHeader, f RawFuseDir) {
me.Original.ReleaseDir(header, f)
}
func (me *WrappingRawFilesystem) Read(input *ReadIn, bp *BufferPool) ([]byte, Status) {
return me.Original.Read(input, bp)
}
func (me *WrappingRawFilesystem) Write(input *WriteIn, data []byte) (written uint32, code Status) {
return me.Original.Write(input, data)
}
func (me *WrappingRawFilesystem) Flush(input *FlushIn) Status {
return me.Original.Flush(input)
}
func (me *WrappingRawFilesystem) Fsync(input *FsyncIn) (code Status) {
return me.Original.Fsync(input)
}
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