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

Implement BATCH_FORGET. Bump kernel interface to 7.16.

parent 72dbac68
......@@ -248,7 +248,7 @@ type DefaultFile struct{}
// Include DefaultRawFileSystem to inherit a null implementation.
type RawFileSystem interface {
Lookup(header *InHeader, name string) (out *EntryOut, status Status)
Forget(header *InHeader, input *ForgetIn)
Forget(nodeid, nlookup uint64)
// Attributes.
GetAttr(header *InHeader, input *GetAttrIn) (out *AttrOut, code Status)
......
......@@ -11,7 +11,7 @@ func (me *DefaultRawFileSystem) Lookup(h *InHeader, name string) (out *EntryOut,
return nil, ENOSYS
}
func (me *DefaultRawFileSystem) Forget(h *InHeader, input *ForgetIn) {
func (me *DefaultRawFileSystem) Forget(nodeID, nlookup uint64) {
}
func (me *DefaultRawFileSystem) GetAttr(header *InHeader, input *GetAttrIn) (out *AttrOut, code Status) {
......
......@@ -137,7 +137,6 @@ func (me *FileSystemConnector) forgetUpdate(node *Inode, forgetCount int) {
me.recursiveConsiderDropInode(node)
}
// InodeCount returns the number of inodes registered with the kernel.
func (me *FileSystemConnector) InodeHandleCount() int {
return me.inodeMap.Count()
......
......@@ -73,9 +73,9 @@ func (me *FileSystemConnector) Lookup(header *InHeader, name string) (out *Entry
return out, OK
}
func (me *FileSystemConnector) Forget(h *InHeader, input *ForgetIn) {
node := me.toInode(h.NodeId)
me.forgetUpdate(node, int(input.Nlookup))
func (me *FileSystemConnector) Forget(nodeID, nlookup uint64) {
node := me.toInode(nodeID)
me.forgetUpdate(node, int(nlookup))
}
func (me *FileSystemConnector) GetAttr(header *InHeader, input *GetAttrIn) (out *AttrOut, code Status) {
......
......@@ -163,9 +163,9 @@ func (me *LockingRawFileSystem) Lookup(h *InHeader, name string) (out *EntryOut,
return me.RawFileSystem.Lookup(h, name)
}
func (me *LockingRawFileSystem) Forget(h *InHeader, input *ForgetIn) {
func (me *LockingRawFileSystem) Forget(nodeID uint64, nlookup uint64) {
defer me.locked()()
me.RawFileSystem.Forget(h, input)
me.RawFileSystem.Forget(nodeID, nlookup)
}
func (me *LockingRawFileSystem) GetAttr(header *InHeader, input *GetAttrIn) (out *AttrOut, code Status) {
......
......@@ -248,10 +248,8 @@ func (me *MountState) handleRequest(req *request) {
}
func (me *MountState) write(req *request) Status {
// If we try to write OK, nil, we will get
// error: writer: Writev [[16 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0]]
// failed, err: writev: no such file or directory
if req.inHeader.opcode == _OP_FORGET {
// Forget does not wait for reply.
if req.inHeader.opcode == _OP_FORGET || req.inHeader.opcode == _OP_BATCH_FORGET {
return OK
}
......
......@@ -4,6 +4,7 @@ import (
"bytes"
"fmt"
"log"
"reflect"
"unsafe"
)
......@@ -51,6 +52,8 @@ const (
_OP_DESTROY = opcode(38)
_OP_IOCTL = opcode(39)
_OP_POLL = opcode(40)
_OP_NOTIFY_REPLY = opcode(41)
_OP_BATCH_FORGET = opcode(42)
// Ugh - what will happen if FUSE introduces a new opcode here?
_OP_NOTIFY_ENTRY = opcode(51)
......@@ -64,7 +67,8 @@ const (
func doInit(state *MountState, req *request) {
const (
FUSE_KERNEL_VERSION = 7
FUSE_KERNEL_MINOR_VERSION = 13
MINIMUM_MINOR_VERSION = 13
OUR_MINOR_VERSION = 16
)
input := (*InitIn)(req.inData)
......@@ -73,8 +77,8 @@ func doInit(state *MountState, req *request) {
req.status = EIO
return
}
if input.Minor < FUSE_KERNEL_MINOR_VERSION {
log.Printf("Minor version is less than we support. Given %d, want at least %d\n", input.Minor, FUSE_KERNEL_MINOR_VERSION)
if input.Minor < MINIMUM_MINOR_VERSION {
log.Printf("Minor version is less than we support. Given %d, want at least %d\n", input.Minor, MINIMUM_MINOR_VERSION)
req.status = EIO
return
}
......@@ -83,13 +87,16 @@ func doInit(state *MountState, req *request) {
state.kernelSettings.Flags = input.Flags & (CAP_ASYNC_READ | CAP_BIG_WRITES | CAP_FILE_OPS)
out := &InitOut{
Major: FUSE_KERNEL_VERSION,
Minor: FUSE_KERNEL_MINOR_VERSION,
Minor: OUR_MINOR_VERSION,
MaxReadAhead: input.MaxReadAhead,
Flags: state.kernelSettings.Flags,
MaxWrite: uint32(state.opts.MaxWrite),
CongestionThreshold: uint16(state.opts.MaxBackground * 3 / 4),
MaxBackground: uint16(state.opts.MaxBackground),
}
if out.Minor > input.Minor {
out.Minor = input.Minor
}
req.outData = unsafe.Pointer(out)
req.status = OK
......@@ -210,7 +217,24 @@ func doGetAttr(state *MountState, req *request) {
}
func doForget(state *MountState, req *request) {
state.fileSystem.Forget(req.inHeader, (*ForgetIn)(req.inData))
state.fileSystem.Forget(req.inHeader.NodeId, (*ForgetIn)(req.inData).Nlookup)
}
func doBatchForget(state *MountState, req *request) {
in := (*BatchForgetIn)(req.inData)
wantBytes := uintptr(in.Count)*unsafe.Sizeof(BatchForgetIn{})
if uintptr(len(req.arg)) < wantBytes {
// We have no return value to complain, so log an error.
log.Printf("Too few bytes for batch forget. Got %d bytes, want %d (%d entries)",
len(req.arg), wantBytes, in.Count)
}
h := &reflect.SliceHeader{uintptr(unsafe.Pointer(&req.arg[0])), int(in.Count), int(in.Count)}
forgets := *(*[]ForgetOne)(unsafe.Pointer(h))
for _, f := range forgets {
state.fileSystem.Forget(f.NodeId, f.Nlookup)
}
}
func doReadlink(state *MountState, req *request) {
......@@ -363,6 +387,7 @@ func init() {
for op, sz := range map[opcode]uintptr{
_OP_FORGET: unsafe.Sizeof(ForgetIn{}),
_OP_BATCH_FORGET: unsafe.Sizeof(BatchForgetIn{}),
_OP_GETATTR: unsafe.Sizeof(GetAttrIn{}),
_OP_SETATTR: unsafe.Sizeof(SetAttrIn{}),
_OP_MKNOD: unsafe.Sizeof(MknodIn{}),
......@@ -421,6 +446,7 @@ func init() {
for op, v := range map[opcode]string{
_OP_LOOKUP: "LOOKUP",
_OP_FORGET: "FORGET",
_OP_BATCH_FORGET: "BATCH_FORGET",
_OP_GETATTR: "GETATTR",
_OP_SETATTR: "SETATTR",
_OP_READLINK: "READLINK",
......@@ -474,6 +500,7 @@ func init() {
_OP_LISTXATTR: doGetXAttr,
_OP_GETATTR: doGetAttr,
_OP_FORGET: doForget,
_OP_BATCH_FORGET: doBatchForget,
_OP_READLINK: doReadlink,
_OP_INIT: doInit,
_OP_LOOKUP: doLookup,
......@@ -530,6 +557,7 @@ func init() {
_OP_READDIR: func(ptr unsafe.Pointer) interface{} { return (*ReadIn)(ptr) },
_OP_ACCESS: func(ptr unsafe.Pointer) interface{} { return (*AccessIn)(ptr) },
_OP_FORGET: func(ptr unsafe.Pointer) interface{} { return (*ForgetIn)(ptr) },
_OP_BATCH_FORGET: func(ptr unsafe.Pointer) interface{} { return (*BatchForgetIn)(ptr) },
_OP_LINK: func(ptr unsafe.Pointer) interface{} { return (*LinkIn)(ptr) },
_OP_MKDIR: func(ptr unsafe.Pointer) interface{} { return (*MkdirIn)(ptr) },
_OP_RELEASE: func(ptr unsafe.Pointer) interface{} { return (*ReleaseIn)(ptr) },
......
......@@ -231,3 +231,11 @@ func (me *WithFlags) String() string {
me.File, me.Description, flagString(openFlagNames, int(me.OpenFlags), "O_RDONLY"),
flagString(fuseOpenFlagNames, int(me.FuseFlags), ""))
}
func (me *ForgetIn) String() string {
return fmt.Sprintf("{%d}", me.Nlookup)
}
func (me *BatchForgetIn) String() string {
return fmt.Sprintf("{%d}", me.Count)
}
......@@ -127,6 +127,16 @@ type ForgetIn struct {
Nlookup uint64
}
type ForgetOne struct {
NodeId uint64
Nlookup uint64
}
type BatchForgetIn struct {
Count uint32
Dummy uint32
}
const (
// Mask for GetAttrIn.Flags. If set, GetAttrIn has a file handle set.
FUSE_GETATTR_FH = (1 << 0)
......
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