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
parent
468f285a46
commit
37d63df227
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue