Commit 10b71ca5 authored by Aaron Jacobs's avatar Aaron Jacobs

Simplified memfs locking.

parents bb3046cd c7c0b23b
...@@ -22,11 +22,12 @@ import ( ...@@ -22,11 +22,12 @@ import (
"github.com/jacobsa/fuse/fuseops" "github.com/jacobsa/fuse/fuseops"
"github.com/jacobsa/fuse/fuseutil" "github.com/jacobsa/fuse/fuseutil"
"github.com/jacobsa/syncutil"
"github.com/jacobsa/timeutil" "github.com/jacobsa/timeutil"
) )
// Common attributes for files and directories. // Common attributes for files and directories.
//
// External synchronization is required.
type inode struct { type inode struct {
///////////////////////// /////////////////////////
// Dependencies // Dependencies
...@@ -38,8 +39,6 @@ type inode struct { ...@@ -38,8 +39,6 @@ type inode struct {
// Mutable state // Mutable state
///////////////////////// /////////////////////////
mu syncutil.InvariantMutex
// The current attributes of this inode. // The current attributes of this inode.
// //
// INVARIANT: attrs.Mode &^ (os.ModePerm|os.ModeDir|os.ModeSymlink) == 0 // INVARIANT: attrs.Mode &^ (os.ModePerm|os.ModeDir|os.ModeSymlink) == 0
...@@ -93,11 +92,10 @@ func newInode( ...@@ -93,11 +92,10 @@ func newInode(
attrs: attrs, attrs: attrs,
} }
in.mu = syncutil.NewInvariantMutex(in.checkInvariants)
return return
} }
func (in *inode) checkInvariants() { func (in *inode) CheckInvariants() {
// INVARIANT: attrs.Mode &^ (os.ModePerm|os.ModeDir|os.ModeSymlink) == 0 // INVARIANT: attrs.Mode &^ (os.ModePerm|os.ModeDir|os.ModeSymlink) == 0
if !(in.attrs.Mode&^(os.ModePerm|os.ModeDir|os.ModeSymlink) == 0) { if !(in.attrs.Mode&^(os.ModePerm|os.ModeDir|os.ModeSymlink) == 0) {
panic(fmt.Sprintf("Unexpected mode: %v", in.attrs.Mode)) panic(fmt.Sprintf("Unexpected mode: %v", in.attrs.Mode))
...@@ -153,25 +151,21 @@ func (in *inode) checkInvariants() { ...@@ -153,25 +151,21 @@ func (in *inode) checkInvariants() {
return return
} }
// LOCKS_REQUIRED(in.mu)
func (in *inode) isDir() bool { func (in *inode) isDir() bool {
return in.attrs.Mode&os.ModeDir != 0 return in.attrs.Mode&os.ModeDir != 0
} }
// LOCKS_REQUIRED(in.mu)
func (in *inode) isSymlink() bool { func (in *inode) isSymlink() bool {
return in.attrs.Mode&os.ModeSymlink != 0 return in.attrs.Mode&os.ModeSymlink != 0
} }
// LOCKS_REQUIRED(in.mu)
func (in *inode) isFile() bool { func (in *inode) isFile() bool {
return !(in.isDir() || in.isSymlink()) return !(in.isDir() || in.isSymlink())
} }
// Return the index of the child within in.entries, if it exists. // Return the index of the child within in.entries, if it exists.
// //
// REQUIRES: in.dir // REQUIRES: in.isDir()
// LOCKS_REQUIRED(in.mu)
func (in *inode) findChild(name string) (i int, ok bool) { func (in *inode) findChild(name string) (i int, ok bool) {
if !in.isDir() { if !in.isDir() {
panic("findChild called on non-directory.") panic("findChild called on non-directory.")
...@@ -195,7 +189,6 @@ func (in *inode) findChild(name string) (i int, ok bool) { ...@@ -195,7 +189,6 @@ func (in *inode) findChild(name string) (i int, ok bool) {
// Return the number of children of the directory. // Return the number of children of the directory.
// //
// REQUIRES: in.isDir() // REQUIRES: in.isDir()
// LOCKS_REQUIRED(in.mu)
func (in *inode) Len() (n int) { func (in *inode) Len() (n int) {
for _, e := range in.entries { for _, e := range in.entries {
if e.Type != fuseutil.DT_Unknown { if e.Type != fuseutil.DT_Unknown {
...@@ -209,7 +202,6 @@ func (in *inode) Len() (n int) { ...@@ -209,7 +202,6 @@ func (in *inode) Len() (n int) {
// Find an entry for the given child name and return its inode ID. // Find an entry for the given child name and return its inode ID.
// //
// REQUIRES: in.isDir() // REQUIRES: in.isDir()
// LOCKS_REQUIRED(in.mu)
func (in *inode) LookUpChild(name string) (id fuseops.InodeID, ok bool) { func (in *inode) LookUpChild(name string) (id fuseops.InodeID, ok bool) {
index, ok := in.findChild(name) index, ok := in.findChild(name)
if ok { if ok {
...@@ -223,7 +215,6 @@ func (in *inode) LookUpChild(name string) (id fuseops.InodeID, ok bool) { ...@@ -223,7 +215,6 @@ func (in *inode) LookUpChild(name string) (id fuseops.InodeID, ok bool) {
// //
// REQUIRES: in.isDir() // REQUIRES: in.isDir()
// REQUIRES: dt != fuseutil.DT_Unknown // REQUIRES: dt != fuseutil.DT_Unknown
// LOCKS_REQUIRED(in.mu)
func (in *inode) AddChild( func (in *inode) AddChild(
id fuseops.InodeID, id fuseops.InodeID,
name string, name string,
...@@ -263,7 +254,6 @@ func (in *inode) AddChild( ...@@ -263,7 +254,6 @@ func (in *inode) AddChild(
// //
// REQUIRES: in.isDir() // REQUIRES: in.isDir()
// REQUIRES: An entry for the given name exists. // REQUIRES: An entry for the given name exists.
// LOCKS_REQUIRED(in.mu)
func (in *inode) RemoveChild(name string) { func (in *inode) RemoveChild(name string) {
// Update the modification time. // Update the modification time.
in.attrs.Mtime = in.clock.Now() in.attrs.Mtime = in.clock.Now()
...@@ -284,7 +274,6 @@ func (in *inode) RemoveChild(name string) { ...@@ -284,7 +274,6 @@ func (in *inode) RemoveChild(name string) {
// Serve a ReadDir request. // Serve a ReadDir request.
// //
// REQUIRES: in.isDir() // REQUIRES: in.isDir()
// LOCKS_REQUIRED(in.mu)
func (in *inode) ReadDir(offset int, size int) (data []byte, err error) { func (in *inode) ReadDir(offset int, size int) (data []byte, err error) {
if !in.isDir() { if !in.isDir() {
panic("ReadDir called on non-directory.") panic("ReadDir called on non-directory.")
...@@ -313,7 +302,6 @@ func (in *inode) ReadDir(offset int, size int) (data []byte, err error) { ...@@ -313,7 +302,6 @@ func (in *inode) ReadDir(offset int, size int) (data []byte, err error) {
// Read from the file's contents. See documentation for ioutil.ReaderAt. // Read from the file's contents. See documentation for ioutil.ReaderAt.
// //
// REQUIRES: in.isFile() // REQUIRES: in.isFile()
// LOCKS_REQUIRED(in.mu)
func (in *inode) ReadAt(p []byte, off int64) (n int, err error) { func (in *inode) ReadAt(p []byte, off int64) (n int, err error) {
if !in.isFile() { if !in.isFile() {
panic("ReadAt called on non-file.") panic("ReadAt called on non-file.")
...@@ -337,7 +325,6 @@ func (in *inode) ReadAt(p []byte, off int64) (n int, err error) { ...@@ -337,7 +325,6 @@ func (in *inode) ReadAt(p []byte, off int64) (n int, err error) {
// Write to the file's contents. See documentation for ioutil.WriterAt. // Write to the file's contents. See documentation for ioutil.WriterAt.
// //
// REQUIRES: in.isFile() // REQUIRES: in.isFile()
// LOCKS_REQUIRED(in.mu)
func (in *inode) WriteAt(p []byte, off int64) (n int, err error) { func (in *inode) WriteAt(p []byte, off int64) (n int, err error) {
if !in.isFile() { if !in.isFile() {
panic("WriteAt called on non-file.") panic("WriteAt called on non-file.")
...@@ -366,8 +353,6 @@ func (in *inode) WriteAt(p []byte, off int64) (n int, err error) { ...@@ -366,8 +353,6 @@ func (in *inode) WriteAt(p []byte, off int64) (n int, err error) {
} }
// Update attributes from non-nil parameters. // Update attributes from non-nil parameters.
//
// LOCKS_REQUIRED(in.mu)
func (in *inode) SetAttributes( func (in *inode) SetAttributes(
size *uint64, size *uint64,
mode *os.FileMode, mode *os.FileMode,
......
...@@ -40,13 +40,13 @@ type memFS struct { ...@@ -40,13 +40,13 @@ type memFS struct {
// Mutable state // Mutable state
///////////////////////// /////////////////////////
// When acquiring this lock, the caller must hold no inode locks.
mu syncutil.InvariantMutex mu syncutil.InvariantMutex
// The collection of live inodes, indexed by ID. IDs of free inodes that may // The collection of live inodes, indexed by ID. IDs of free inodes that may
// be re-used have nil entries. No ID less than fuseops.RootInodeID is ever // be re-used have nil entries. No ID less than fuseops.RootInodeID is ever
// used. // used.
// //
// INVARIANT: For each inode in, in.CheckInvariants() does not panic.
// INVARIANT: len(inodes) > fuseops.RootInodeID // INVARIANT: len(inodes) > fuseops.RootInodeID
// INVARIANT: For all i < fuseops.RootInodeID, inodes[i] == nil // INVARIANT: For all i < fuseops.RootInodeID, inodes[i] == nil
// INVARIANT: inodes[fuseops.RootInodeID] != nil // INVARIANT: inodes[fuseops.RootInodeID] != nil
...@@ -132,33 +132,32 @@ func (fs *memFS) checkInvariants() { ...@@ -132,33 +132,32 @@ func (fs *memFS) checkInvariants() {
panic(fmt.Sprintf("Unexected free inode ID: %v", id)) panic(fmt.Sprintf("Unexected free inode ID: %v", id))
} }
} }
// INVARIANT: For each inode in, in.CheckInvariants() does not panic.
for _, in := range fs.inodes {
in.CheckInvariants()
}
} }
// Find the given inode and return it with its lock held. Panic if it doesn't // Find the given inode. Panic if it doesn't exist.
// exist.
// //
// LOCKS_REQUIRED(fs.mu) // LOCKS_REQUIRED(fs.mu)
// LOCK_FUNCTION(inode.mu)
func (fs *memFS) getInodeOrDie(id fuseops.InodeID) (inode *inode) { func (fs *memFS) getInodeOrDie(id fuseops.InodeID) (inode *inode) {
inode = fs.inodes[id] inode = fs.inodes[id]
if inode == nil { if inode == nil {
panic(fmt.Sprintf("Unknown inode: %v", id)) panic(fmt.Sprintf("Unknown inode: %v", id))
} }
inode.mu.Lock()
return return
} }
// Allocate a new inode, assigning it an ID that is not in use. Return it with // Allocate a new inode, assigning it an ID that is not in use.
// its lock held.
// //
// EXCLUSIVE_LOCKS_REQUIRED(fs.mu) // LOCKS_REQUIRED(fs.mu)
// EXCLUSIVE_LOCK_FUNCTION(inode.mu)
func (fs *memFS) allocateInode( func (fs *memFS) allocateInode(
attrs fuseops.InodeAttributes) (id fuseops.InodeID, inode *inode) { attrs fuseops.InodeAttributes) (id fuseops.InodeID, inode *inode) {
// Create and lock the inode. // Create the inode.
inode = newInode(fs.clock, attrs) inode = newInode(fs.clock, attrs)
inode.mu.Lock()
// Re-use a free ID if possible. Otherwise mint a new one. // Re-use a free ID if possible. Otherwise mint a new one.
numFree := len(fs.freeInodes) numFree := len(fs.freeInodes)
...@@ -174,7 +173,7 @@ func (fs *memFS) allocateInode( ...@@ -174,7 +173,7 @@ func (fs *memFS) allocateInode(
return return
} }
// EXCLUSIVE_LOCKS_REQUIRED(fs.mu) // LOCKS_REQUIRED(fs.mu)
func (fs *memFS) deallocateInode(id fuseops.InodeID) { func (fs *memFS) deallocateInode(id fuseops.InodeID) {
fs.freeInodes = append(fs.freeInodes, id) fs.freeInodes = append(fs.freeInodes, id)
fs.inodes[id] = nil fs.inodes[id] = nil
...@@ -191,7 +190,6 @@ func (fs *memFS) LookUpInode( ...@@ -191,7 +190,6 @@ func (fs *memFS) LookUpInode(
// Grab the parent directory. // Grab the parent directory.
inode := fs.getInodeOrDie(op.Parent) inode := fs.getInodeOrDie(op.Parent)
defer inode.mu.Unlock()
// Does the directory have an entry with the given name? // Does the directory have an entry with the given name?
childID, ok := inode.LookUpChild(op.Name) childID, ok := inode.LookUpChild(op.Name)
...@@ -202,7 +200,6 @@ func (fs *memFS) LookUpInode( ...@@ -202,7 +200,6 @@ func (fs *memFS) LookUpInode(
// Grab the child. // Grab the child.
child := fs.getInodeOrDie(childID) child := fs.getInodeOrDie(childID)
defer child.mu.Unlock()
// Fill in the response. // Fill in the response.
op.Entry.Child = childID op.Entry.Child = childID
...@@ -223,7 +220,6 @@ func (fs *memFS) GetInodeAttributes( ...@@ -223,7 +220,6 @@ func (fs *memFS) GetInodeAttributes(
// Grab the inode. // Grab the inode.
inode := fs.getInodeOrDie(op.Inode) inode := fs.getInodeOrDie(op.Inode)
defer inode.mu.Unlock()
// Fill in the response. // Fill in the response.
op.Attributes = inode.attrs op.Attributes = inode.attrs
...@@ -242,7 +238,6 @@ func (fs *memFS) SetInodeAttributes( ...@@ -242,7 +238,6 @@ func (fs *memFS) SetInodeAttributes(
// Grab the inode. // Grab the inode.
inode := fs.getInodeOrDie(op.Inode) inode := fs.getInodeOrDie(op.Inode)
defer inode.mu.Unlock()
// Handle the request. // Handle the request.
inode.SetAttributes(op.Size, op.Mode, op.Mtime) inode.SetAttributes(op.Size, op.Mode, op.Mtime)
...@@ -264,7 +259,6 @@ func (fs *memFS) MkDir( ...@@ -264,7 +259,6 @@ func (fs *memFS) MkDir(
// Grab the parent, which we will update shortly. // Grab the parent, which we will update shortly.
parent := fs.getInodeOrDie(op.Parent) parent := fs.getInodeOrDie(op.Parent)
defer parent.mu.Unlock()
// Ensure that the name doesn't already exist, so we don't wind up with a // Ensure that the name doesn't already exist, so we don't wind up with a
// duplicate. // duplicate.
...@@ -285,7 +279,6 @@ func (fs *memFS) MkDir( ...@@ -285,7 +279,6 @@ func (fs *memFS) MkDir(
// Allocate a child. // Allocate a child.
childID, child := fs.allocateInode(childAttrs) childID, child := fs.allocateInode(childAttrs)
defer child.mu.Unlock()
// Add an entry in the parent. // Add an entry in the parent.
parent.AddChild(childID, op.Name, fuseutil.DT_Directory) parent.AddChild(childID, op.Name, fuseutil.DT_Directory)
...@@ -309,7 +302,6 @@ func (fs *memFS) CreateFile( ...@@ -309,7 +302,6 @@ func (fs *memFS) CreateFile(
// Grab the parent, which we will update shortly. // Grab the parent, which we will update shortly.
parent := fs.getInodeOrDie(op.Parent) parent := fs.getInodeOrDie(op.Parent)
defer parent.mu.Unlock()
// Ensure that the name doesn't already exist, so we don't wind up with a // Ensure that the name doesn't already exist, so we don't wind up with a
// duplicate. // duplicate.
...@@ -335,7 +327,6 @@ func (fs *memFS) CreateFile( ...@@ -335,7 +327,6 @@ func (fs *memFS) CreateFile(
// Allocate a child. // Allocate a child.
childID, child := fs.allocateInode(childAttrs) childID, child := fs.allocateInode(childAttrs)
defer child.mu.Unlock()
// Add an entry in the parent. // Add an entry in the parent.
parent.AddChild(childID, op.Name, fuseutil.DT_File) parent.AddChild(childID, op.Name, fuseutil.DT_File)
...@@ -361,7 +352,6 @@ func (fs *memFS) CreateSymlink( ...@@ -361,7 +352,6 @@ func (fs *memFS) CreateSymlink(
// Grab the parent, which we will update shortly. // Grab the parent, which we will update shortly.
parent := fs.getInodeOrDie(op.Parent) parent := fs.getInodeOrDie(op.Parent)
defer parent.mu.Unlock()
// Ensure that the name doesn't already exist, so we don't wind up with a // Ensure that the name doesn't already exist, so we don't wind up with a
// duplicate. // duplicate.
...@@ -387,7 +377,6 @@ func (fs *memFS) CreateSymlink( ...@@ -387,7 +377,6 @@ func (fs *memFS) CreateSymlink(
// Allocate a child. // Allocate a child.
childID, child := fs.allocateInode(childAttrs) childID, child := fs.allocateInode(childAttrs)
defer child.mu.Unlock()
// Set up its target. // Set up its target.
child.target = op.Target child.target = op.Target
...@@ -414,7 +403,6 @@ func (fs *memFS) RmDir( ...@@ -414,7 +403,6 @@ func (fs *memFS) RmDir(
// Grab the parent, which we will update shortly. // Grab the parent, which we will update shortly.
parent := fs.getInodeOrDie(op.Parent) parent := fs.getInodeOrDie(op.Parent)
defer parent.mu.Unlock()
// Find the child within the parent. // Find the child within the parent.
childID, ok := parent.LookUpChild(op.Name) childID, ok := parent.LookUpChild(op.Name)
...@@ -425,7 +413,6 @@ func (fs *memFS) RmDir( ...@@ -425,7 +413,6 @@ func (fs *memFS) RmDir(
// Grab the child. // Grab the child.
child := fs.getInodeOrDie(childID) child := fs.getInodeOrDie(childID)
defer child.mu.Unlock()
// Make sure the child is empty. // Make sure the child is empty.
if child.Len() != 0 { if child.Len() != 0 {
...@@ -449,7 +436,6 @@ func (fs *memFS) Unlink( ...@@ -449,7 +436,6 @@ func (fs *memFS) Unlink(
// Grab the parent, which we will update shortly. // Grab the parent, which we will update shortly.
parent := fs.getInodeOrDie(op.Parent) parent := fs.getInodeOrDie(op.Parent)
defer parent.mu.Unlock()
// Find the child within the parent. // Find the child within the parent.
childID, ok := parent.LookUpChild(op.Name) childID, ok := parent.LookUpChild(op.Name)
...@@ -460,7 +446,6 @@ func (fs *memFS) Unlink( ...@@ -460,7 +446,6 @@ func (fs *memFS) Unlink(
// Grab the child. // Grab the child.
child := fs.getInodeOrDie(childID) child := fs.getInodeOrDie(childID)
defer child.mu.Unlock()
// Remove the entry within the parent. // Remove the entry within the parent.
parent.RemoveChild(op.Name) parent.RemoveChild(op.Name)
...@@ -480,7 +465,6 @@ func (fs *memFS) OpenDir( ...@@ -480,7 +465,6 @@ func (fs *memFS) OpenDir(
// inode that doesn't exist, something screwed up earlier (a lookup, a // inode that doesn't exist, something screwed up earlier (a lookup, a
// cache invalidation, etc.). // cache invalidation, etc.).
inode := fs.getInodeOrDie(op.Inode) inode := fs.getInodeOrDie(op.Inode)
defer inode.mu.Unlock()
if !inode.isDir() { if !inode.isDir() {
panic("Found non-dir.") panic("Found non-dir.")
...@@ -496,7 +480,6 @@ func (fs *memFS) ReadDir( ...@@ -496,7 +480,6 @@ func (fs *memFS) ReadDir(
// Grab the directory. // Grab the directory.
inode := fs.getInodeOrDie(op.Inode) inode := fs.getInodeOrDie(op.Inode)
defer inode.mu.Unlock()
// Serve the request. // Serve the request.
op.Data, err = inode.ReadDir(int(op.Offset), op.Size) op.Data, err = inode.ReadDir(int(op.Offset), op.Size)
...@@ -517,7 +500,6 @@ func (fs *memFS) OpenFile( ...@@ -517,7 +500,6 @@ func (fs *memFS) OpenFile(
// inode that doesn't exist, something screwed up earlier (a lookup, a // inode that doesn't exist, something screwed up earlier (a lookup, a
// cache invalidation, etc.). // cache invalidation, etc.).
inode := fs.getInodeOrDie(op.Inode) inode := fs.getInodeOrDie(op.Inode)
defer inode.mu.Unlock()
if !inode.isFile() { if !inode.isFile() {
panic("Found non-file.") panic("Found non-file.")
...@@ -533,7 +515,6 @@ func (fs *memFS) ReadFile( ...@@ -533,7 +515,6 @@ func (fs *memFS) ReadFile(
// Find the inode in question. // Find the inode in question.
inode := fs.getInodeOrDie(op.Inode) inode := fs.getInodeOrDie(op.Inode)
defer inode.mu.Unlock()
// Serve the request. // Serve the request.
op.Data = make([]byte, op.Size) op.Data = make([]byte, op.Size)
...@@ -555,7 +536,6 @@ func (fs *memFS) WriteFile( ...@@ -555,7 +536,6 @@ func (fs *memFS) WriteFile(
// Find the inode in question. // Find the inode in question.
inode := fs.getInodeOrDie(op.Inode) inode := fs.getInodeOrDie(op.Inode)
defer inode.mu.Unlock()
// Serve the request. // Serve the request.
_, err = inode.WriteAt(op.Data, op.Offset) _, err = inode.WriteAt(op.Data, op.Offset)
...@@ -570,7 +550,6 @@ func (fs *memFS) ReadSymlink( ...@@ -570,7 +550,6 @@ func (fs *memFS) ReadSymlink(
// Find the inode in question. // Find the inode in question.
inode := fs.getInodeOrDie(op.Inode) inode := fs.getInodeOrDie(op.Inode)
defer inode.mu.Unlock()
// Serve the request. // Serve the request.
op.Target = inode.target op.Target = inode.target
......
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