Add support for the FUSE_BATCH_FORGET operation (#123)

There are certain Kernel versions which do not send individual
Forget operations after they receive "not implemented" for Batch Forget.
One example is "5.4.0-110-generic" on Ubuntu 20.04. I am sure there are
plenty of others.

This leads to inode "leaks". Where reference counts are never decreased
and the inodes were left hanging around long after they are not needed
any more.

The best way to fix that was adding support for batch operations to the
lib. This way all users will be able to benefit from the batching
optimization.

Co-authored-by: Doychin Atanasov <doychin.atanasov@chaosgroup.com>
notifications
Doychin Atanasov 2022-05-27 09:49:15 +03:00 committed by GitHub
parent 468f285a46
commit 37d63df227
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 76 additions and 0 deletions

View File

@ -113,6 +113,32 @@ func convertInMessage(
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
}
case fusekernel.OpBatchForget:
type input fusekernel.BatchForgetCountIn
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
if in == nil {
return nil, errors.New("Corrupt OpBatchForget")
}
entries := make([]fuseops.BatchForgetEntry, 0, in.Count)
for i := uint32(0); i < in.Count; i++ {
type entry fusekernel.BatchForgetEntryIn
ein := (*entry)(inMsg.Consume(unsafe.Sizeof(entry{})))
if ein == nil {
return nil, errors.New("Corrupt OpBatchForget")
}
entries = append(entries, fuseops.BatchForgetEntry{
Inode: fuseops.InodeID(ein.Inode),
N: ein.Nlookup,
})
}
o = &fuseops.BatchForgetOp{
Entries: entries,
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
}
case fusekernel.OpMkdir:
in := (*fusekernel.MkdirIn)(inMsg.Consume(fusekernel.MkdirInSize(protocol)))
if in == nil {
@ -595,6 +621,9 @@ func (c *Connection) kernelResponse(
case *fuseops.ForgetInodeOp:
return true
case *fuseops.BatchForgetOp:
return true
case *interruptOp:
return true
}

View File

@ -220,6 +220,32 @@ type ForgetInodeOp struct {
OpContext OpContext
}
// BatchForgetEntry represents one Inode entry to forget in the BatchForgetOp.
//
// Everything written in the ForgetInodeOp docs applies for the BatchForgetEntry
// too.
type BatchForgetEntry struct {
// The inode whose reference count should be decremented.
Inode InodeID
// The amount to decrement the reference count.
N uint64
}
// Decrement the reference counts for a list of inode IDs previously issued by the file
// system.
//
// This operation is a batch of ForgetInodeOp operations. Every entry in
// Entries is one ForgetInodeOp operation. See the docs of ForgetInodeOp
// for further details.
type BatchForgetOp struct {
// Entries is a list of Forget operations. One could treat every entry in the
// list as a single ForgetInodeOp operation.
Entries []BatchForgetEntry
OpContext OpContext
}
////////////////////////////////////////////////////////////////////////
// Inode creation
////////////////////////////////////////////////////////////////////////

View File

@ -39,6 +39,7 @@ type FileSystem interface {
GetInodeAttributes(context.Context, *fuseops.GetInodeAttributesOp) error
SetInodeAttributes(context.Context, *fuseops.SetInodeAttributesOp) error
ForgetInode(context.Context, *fuseops.ForgetInodeOp) error
BatchForget(context.Context, *fuseops.BatchForgetOp) error
MkDir(context.Context, *fuseops.MkDirOp) error
MkNode(context.Context, *fuseops.MkNodeOp) error
CreateFile(context.Context, *fuseops.CreateFileOp) error
@ -151,6 +152,9 @@ func (s *fileSystemServer) handleOp(
case *fuseops.ForgetInodeOp:
err = s.fs.ForgetInode(ctx, typed)
case *fuseops.BatchForgetOp:
err = s.fs.BatchForget(ctx, typed)
case *fuseops.MkDirOp:
err = s.fs.MkDir(ctx, typed)

View File

@ -60,6 +60,12 @@ func (fs *NotImplementedFileSystem) ForgetInode(
return fuse.ENOSYS
}
func (fs *NotImplementedFileSystem) BatchForget(
ctx context.Context,
op *fuseops.BatchForgetOp) error {
return fuse.ENOSYS
}
func (fs *NotImplementedFileSystem) MkDir(
ctx context.Context,
op *fuseops.MkDirOp) error {

View File

@ -386,6 +386,7 @@ const (
OpDestroy = 38
OpIoctl = 39 // Linux?
OpPoll = 40 // Linux?
OpBatchForget = 42
OpFallocate = 43
// OS X
@ -417,6 +418,16 @@ type ForgetIn struct {
Nlookup uint64
}
type BatchForgetCountIn struct {
Count uint32
dummy uint32
}
type BatchForgetEntryIn struct {
Inode int64
Nlookup uint64
}
type GetattrIn struct {
GetattrFlags uint32
dummy uint32