commit
6292872c4e
|
@ -237,7 +237,7 @@ func (o *SetInodeAttributesOp) toBazilfuseResponse() (bfResp interface{}) {
|
||||||
// revalidating.
|
// revalidating.
|
||||||
//
|
//
|
||||||
// In contrast to all other inodes, RootInodeID begins with an implicit
|
// In contrast to all other inodes, RootInodeID begins with an implicit
|
||||||
// reference count of one, without a corresponding op to increase it. (There
|
// lookup count of one, without a corresponding op to increase it. (There
|
||||||
// could be no such op, because the root cannot be referred to by name.) Code
|
// could be no such op, because the root cannot be referred to by name.) Code
|
||||||
// walk:
|
// walk:
|
||||||
//
|
//
|
||||||
|
@ -248,10 +248,10 @@ func (o *SetInodeAttributesOp) toBazilfuseResponse() (bfResp interface{}) {
|
||||||
//
|
//
|
||||||
// * (http://goo.gl/vPD9Oh) fuse_iget increments nlookup.
|
// * (http://goo.gl/vPD9Oh) fuse_iget increments nlookup.
|
||||||
//
|
//
|
||||||
// File systems should not make assumptions about whether they will or will not
|
// File systems should tolerate but not rely on receiving forget ops for
|
||||||
// receive a ForgetInodeOp for the root inode. Experimentally, OS X seems to
|
// remaining inodes when the file system unmounts, including the root inode.
|
||||||
// never send one, while Linux appears to send one only sometimes. (Cf.
|
// Rather they should take fuse.Connection.ReadOp returning io.EOF as
|
||||||
// http://goo.gl/EUbxEg, fuse-devel thread "Root inode lookup count").
|
// implicitly decrementing all lookup counts to zero.
|
||||||
type ForgetInodeOp struct {
|
type ForgetInodeOp struct {
|
||||||
commonOp
|
commonOp
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,11 @@ type FileSystem interface {
|
||||||
FlushFile(*fuseops.FlushFileOp) error
|
FlushFile(*fuseops.FlushFileOp) error
|
||||||
ReleaseFileHandle(*fuseops.ReleaseFileHandleOp) error
|
ReleaseFileHandle(*fuseops.ReleaseFileHandleOp) error
|
||||||
ReadSymlink(*fuseops.ReadSymlinkOp) error
|
ReadSymlink(*fuseops.ReadSymlinkOp) error
|
||||||
|
|
||||||
|
// Regard all inodes (including the root inode) as having their lookup counts
|
||||||
|
// decremented to zero, and clean up any resources associated with the file
|
||||||
|
// system. No further calls to the file system will be made.
|
||||||
|
Destroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a fuse.Server that handles ops by calling the associated FileSystem
|
// Create a fuse.Server that handles ops by calling the associated FileSystem
|
||||||
|
@ -85,7 +90,12 @@ type fileSystemServer struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *fileSystemServer) ServeOps(c *fuse.Connection) {
|
func (s *fileSystemServer) ServeOps(c *fuse.Connection) {
|
||||||
defer s.opsInFlight.Wait()
|
// When we are done, we clean up by waiting for all in-flight ops then
|
||||||
|
// destroying the file system.
|
||||||
|
defer func() {
|
||||||
|
s.opsInFlight.Wait()
|
||||||
|
s.fs.Destroy()
|
||||||
|
}()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
op, err := c.ReadOp()
|
op, err := c.ReadOp()
|
||||||
|
|
|
@ -147,3 +147,6 @@ func (fs *NotImplementedFileSystem) ReadSymlink(
|
||||||
err = fuse.ENOSYS
|
err = fuse.ENOSYS
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fs *NotImplementedFileSystem) Destroy() {
|
||||||
|
}
|
||||||
|
|
|
@ -27,7 +27,8 @@ import (
|
||||||
// A type that knows how to serve ops read from a connection.
|
// A type that knows how to serve ops read from a connection.
|
||||||
type Server interface {
|
type Server interface {
|
||||||
// Read and serve ops from the supplied connection until EOF. Do not return
|
// Read and serve ops from the supplied connection until EOF. Do not return
|
||||||
// until all operations have been responded to.
|
// until all operations have been responded to. Must not be called more than
|
||||||
|
// once.
|
||||||
ServeOps(*Connection)
|
ServeOps(*Connection)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,6 @@ package forgetfs
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
|
||||||
|
|
||||||
"github.com/jacobsa/fuse"
|
"github.com/jacobsa/fuse"
|
||||||
"github.com/jacobsa/fuse/fuseops"
|
"github.com/jacobsa/fuse/fuseops"
|
||||||
|
@ -67,6 +66,13 @@ func NewFileSystem() (fs *ForgetFS) {
|
||||||
// The root inode starts with a lookup count of one.
|
// The root inode starts with a lookup count of one.
|
||||||
impl.inodes[cannedID_Root].IncrementLookupCount()
|
impl.inodes[cannedID_Root].IncrementLookupCount()
|
||||||
|
|
||||||
|
// The canned inodes are supposed to be stable from the user's point of view,
|
||||||
|
// so we should allow them to be looked up at any point even if the kernel
|
||||||
|
// has balanced its lookups with its forgets. Ensure that they never go to
|
||||||
|
// zero until the file system is destroyed.
|
||||||
|
impl.inodes[cannedID_Foo].IncrementLookupCount()
|
||||||
|
impl.inodes[cannedID_Bar].IncrementLookupCount()
|
||||||
|
|
||||||
// Set up the mutex.
|
// Set up the mutex.
|
||||||
impl.mu = syncutil.NewInvariantMutex(impl.checkInvariants)
|
impl.mu = syncutil.NewInvariantMutex(impl.checkInvariants)
|
||||||
|
|
||||||
|
@ -165,6 +171,11 @@ func (in *inode) DecrementLookupCount(n uint64) {
|
||||||
in.lookupCount -= n
|
in.lookupCount -= n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Decrement the lookup count to zero.
|
||||||
|
func (in *inode) Destroy() {
|
||||||
|
in.DecrementLookupCount(in.lookupCount)
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
// Helpers
|
// Helpers
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -184,30 +195,7 @@ func (fs *fsImpl) Check() {
|
||||||
fs.mu.Lock()
|
fs.mu.Lock()
|
||||||
defer fs.mu.Unlock()
|
defer fs.mu.Unlock()
|
||||||
|
|
||||||
// On Linux we often don't receive forget ops, and never receive destroy ops
|
|
||||||
// (cf. http://goo.gl/EUbxEg, fuse-devel thread "Root inode lookup count").
|
|
||||||
// So there's not really much we can check here.
|
|
||||||
//
|
|
||||||
// TODO(jacobsa): Figure out why we don't receive destroy. If we can reliably
|
|
||||||
// receive it, we can treat it as "forget all".
|
|
||||||
if runtime.GOOS == "linux" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, v := range fs.inodes {
|
for k, v := range fs.inodes {
|
||||||
// Special case: we don't require the root inode to have reached zero.
|
|
||||||
// OS X doesn't seem to send forgets for the root, and Linux only does
|
|
||||||
// sometimes. But we want to make sure it's not greater than one, which
|
|
||||||
// would be weird.
|
|
||||||
if k == fuseops.RootInodeID {
|
|
||||||
if v.lookupCount > 1 {
|
|
||||||
panic(fmt.Sprintf("Root has lookup count %v", v.lookupCount))
|
|
||||||
}
|
|
||||||
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check other inodes.
|
|
||||||
if v.lookupCount != 0 {
|
if v.lookupCount != 0 {
|
||||||
panic(fmt.Sprintf("Inode %v has lookup count %v", k, v.lookupCount))
|
panic(fmt.Sprintf("Inode %v has lookup count %v", k, v.lookupCount))
|
||||||
}
|
}
|
||||||
|
@ -383,3 +371,9 @@ func (fs *fsImpl) OpenDir(
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fs *fsImpl) Destroy() {
|
||||||
|
for _, in := range fs.inodes {
|
||||||
|
in.Destroy()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue