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

Add deletion notify.

parent eb2fc3e9
...@@ -349,4 +349,5 @@ type DefaultRawFileSystem struct{} ...@@ -349,4 +349,5 @@ type DefaultRawFileSystem struct{}
type RawFsInit struct { type RawFsInit struct {
InodeNotify func(*raw.NotifyInvalInodeOut) Status InodeNotify func(*raw.NotifyInvalInodeOut) Status
EntryNotify func(parent uint64, name string) Status EntryNotify func(parent uint64, name string) Status
DeleteNotify func(parent uint64, child uint64, name string) Status
} }
...@@ -3,7 +3,6 @@ package fuse ...@@ -3,7 +3,6 @@ package fuse
import ( import (
"bytes" "bytes"
"io/ioutil" "io/ioutil"
"log"
"os" "os"
"os/exec" "os/exec"
"syscall" "syscall"
...@@ -79,39 +78,28 @@ func TestDeleteNotify(t *testing.T) { ...@@ -79,39 +78,28 @@ func TestDeleteNotify(t *testing.T) {
} }
defer func() { defer func() {
log.Println("killing process...")
cmd.Process.Kill() cmd.Process.Kill()
cmd.Wait()
log.Println("waited")
time.Sleep(100*time.Millisecond) time.Sleep(100*time.Millisecond)
}() }()
// Wait until we see the subprocess moving. // Wait until tail opened the file.
deadline := time.Now().Add(2 * time.Second) time.Sleep(100*time.Millisecond)
for { err = os.Remove(mnt + "/testdir/testfile")
_, err := os.Lstat(mnt + "/testdir/testfile") if err != nil {
if err == nil { t.Fatal(err)
break
}
if time.Now().After(deadline) {
t.Fatal("timeout; process did not start?")
}
time.Sleep(10 * time.Millisecond)
} }
// Simulate deletion+mkdir coming from the network // Simulate deletion+mkdir coming from the network
close(flip.ok) close(flip.ok)
fs.Root().Inode().RmChild("testdir") oldCh := fs.Root().Inode().RmChild("testdir")
_, code = fs.Root().Inode().FsNode().Mkdir("testdir", 0755, nil) _, code = fs.Root().Inode().FsNode().Mkdir("testdir", 0755, nil)
if !code.Ok() { if !code.Ok() {
t.Fatal("mkdir status", code) t.Fatal("mkdir status", code)
} }
conn.EntryNotify(fs.Root().Inode(), "testdir") conn.DeleteNotify(fs.Root().Inode(), oldCh, "testdir")
fi, err := os.Lstat(mnt + "/testdir") _, err = os.Lstat(mnt + "/testdir")
log.Println("lsta", fi, err)
if err != nil { if err != nil {
t.Fatalf("lstat after del + mkdir failed: %v", err) t.Fatalf("lstat after del + mkdir failed: %v", err)
} }
t.Log(fi)
} }
...@@ -370,3 +370,14 @@ func (c *FileSystemConnector) EntryNotify(dir *Inode, name string) Status { ...@@ -370,3 +370,14 @@ func (c *FileSystemConnector) EntryNotify(dir *Inode, name string) Status {
} }
return c.fsInit.EntryNotify(n, name) return c.fsInit.EntryNotify(n, name)
} }
func (c *FileSystemConnector) DeleteNotify(dir *Inode, child *Inode, name string) Status {
n := dir.nodeId
if dir == c.rootNode {
n = raw.FUSE_ROOT_ID
}
if n == 0 {
return OK
}
return c.fsInit.DeleteNotify(n, child.nodeId, name)
}
...@@ -20,6 +20,9 @@ func (code Status) String() string { ...@@ -20,6 +20,9 @@ func (code Status) String() string {
"NOTIFY_POLL", "NOTIFY_POLL",
"NOTIFY_INVAL_INODE", "NOTIFY_INVAL_INODE",
"NOTIFY_INVAL_ENTRY", "NOTIFY_INVAL_ENTRY",
"NOTIFY_INVAL_STORE",
"NOTIFY_INVAL_RETRIEVE",
"NOTIFY_INVAL_DELETE",
}[-code] }[-code]
} }
return fmt.Sprintf("%d=%v", int(code), syscall.Errno(code)) return fmt.Sprintf("%d=%v", int(code), syscall.Errno(code))
......
...@@ -107,6 +107,9 @@ func (ms *MountState) Mount(mountPoint string, opts *MountOptions) error { ...@@ -107,6 +107,9 @@ func (ms *MountState) Mount(mountPoint string, opts *MountOptions) error {
EntryNotify: func(parent uint64, n string) Status { EntryNotify: func(parent uint64, n string) Status {
return ms.writeEntryNotify(parent, n) return ms.writeEntryNotify(parent, n)
}, },
DeleteNotify: func(parent uint64, child uint64, n string) Status {
return ms.writeDeleteNotify(parent, child, n)
},
} }
ms.fileSystem.Init(&initParams) ms.fileSystem.Init(&initParams)
ms.mountPoint = mp ms.mountPoint = mp
...@@ -442,6 +445,39 @@ func (ms *MountState) writeInodeNotify(entry *raw.NotifyInvalInodeOut) Status { ...@@ -442,6 +445,39 @@ func (ms *MountState) writeInodeNotify(entry *raw.NotifyInvalInodeOut) Status {
return result return result
} }
func (ms *MountState) writeDeleteNotify(parent uint64, child uint64, name string) Status {
if ms.kernelSettings.Minor < 18 {
return ms.writeEntryNotify(parent, name)
}
req := request{
inHeader: &raw.InHeader{
Opcode: _OP_NOTIFY_DELETE,
},
handler: operationHandlers[_OP_NOTIFY_DELETE],
status: raw.NOTIFY_INVAL_DELETE,
}
entry := &raw.NotifyInvalDeleteOut{
Parent: parent,
Child: child,
NameLen: uint32(len(name)),
}
// Many versions of FUSE generate stacktraces if the
// terminating null byte is missing.
nameBytes := make([]byte, len(name)+1)
copy(nameBytes, name)
nameBytes[len(nameBytes)-1] = '\000'
req.outData = unsafe.Pointer(entry)
req.flatData = nameBytes
result := ms.write(&req)
if ms.Debug {
log.Printf("Response: DELETE_NOTIFY: %v", result)
}
return result
}
func (ms *MountState) writeEntryNotify(parent uint64, name string) Status { func (ms *MountState) writeEntryNotify(parent uint64, name string) Status {
req := request{ req := request{
inHeader: &raw.InHeader{ inHeader: &raw.InHeader{
......
...@@ -59,8 +59,9 @@ const ( ...@@ -59,8 +59,9 @@ const (
// Ugh - what will happen if FUSE introduces a new opcode here? // Ugh - what will happen if FUSE introduces a new opcode here?
_OP_NOTIFY_ENTRY = int32(51) _OP_NOTIFY_ENTRY = int32(51)
_OP_NOTIFY_INODE = int32(52) _OP_NOTIFY_INODE = int32(52)
_OP_NOTIFY_DELETE = int32(53)
_OPCODE_COUNT = int32(53) _OPCODE_COUNT = int32(54)
) )
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
...@@ -372,7 +373,7 @@ func init() { ...@@ -372,7 +373,7 @@ func init() {
operationHandlers[i] = &operationHandler{Name: "UNKNOWN"} operationHandlers[i] = &operationHandler{Name: "UNKNOWN"}
} }
fileOps := []int32{_OP_READLINK, _OP_NOTIFY_ENTRY} fileOps := []int32{_OP_READLINK, _OP_NOTIFY_ENTRY, _OP_NOTIFY_DELETE}
for _, op := range fileOps { for _, op := range fileOps {
operationHandlers[op].FileNameOut = true operationHandlers[op].FileNameOut = true
} }
...@@ -431,6 +432,7 @@ func init() { ...@@ -431,6 +432,7 @@ func init() {
_OP_POLL: unsafe.Sizeof(raw.PollOut{}), _OP_POLL: unsafe.Sizeof(raw.PollOut{}),
_OP_NOTIFY_ENTRY: unsafe.Sizeof(raw.NotifyInvalEntryOut{}), _OP_NOTIFY_ENTRY: unsafe.Sizeof(raw.NotifyInvalEntryOut{}),
_OP_NOTIFY_INODE: unsafe.Sizeof(raw.NotifyInvalInodeOut{}), _OP_NOTIFY_INODE: unsafe.Sizeof(raw.NotifyInvalInodeOut{}),
_OP_NOTIFY_DELETE: unsafe.Sizeof(raw.NotifyInvalDeleteOut{}),
} { } {
operationHandlers[op].OutputSize = sz operationHandlers[op].OutputSize = sz
} }
...@@ -477,6 +479,7 @@ func init() { ...@@ -477,6 +479,7 @@ func init() {
_OP_POLL: "POLL", _OP_POLL: "POLL",
_OP_NOTIFY_ENTRY: "NOTIFY_ENTRY", _OP_NOTIFY_ENTRY: "NOTIFY_ENTRY",
_OP_NOTIFY_INODE: "NOTIFY_INODE", _OP_NOTIFY_INODE: "NOTIFY_INODE",
_OP_NOTIFY_DELETE: "NOTIFY_DELETE",
} { } {
operationHandlers[op].Name = v operationHandlers[op].Name = v
} }
...@@ -531,6 +534,7 @@ func init() { ...@@ -531,6 +534,7 @@ func init() {
_OP_MKDIR: func(ptr unsafe.Pointer) interface{} { return (*raw.EntryOut)(ptr) }, _OP_MKDIR: func(ptr unsafe.Pointer) interface{} { return (*raw.EntryOut)(ptr) },
_OP_NOTIFY_ENTRY: func(ptr unsafe.Pointer) interface{} { return (*raw.NotifyInvalEntryOut)(ptr) }, _OP_NOTIFY_ENTRY: func(ptr unsafe.Pointer) interface{} { return (*raw.NotifyInvalEntryOut)(ptr) },
_OP_NOTIFY_INODE: func(ptr unsafe.Pointer) interface{} { return (*raw.NotifyInvalInodeOut)(ptr) }, _OP_NOTIFY_INODE: func(ptr unsafe.Pointer) interface{} { return (*raw.NotifyInvalInodeOut)(ptr) },
_OP_NOTIFY_DELETE: func(ptr unsafe.Pointer) interface{} { return (*raw.NotifyInvalDeleteOut)(ptr) },
_OP_STATFS: func(ptr unsafe.Pointer) interface{} { return (*StatfsOut)(ptr) }, _OP_STATFS: func(ptr unsafe.Pointer) interface{} { return (*StatfsOut)(ptr) },
} { } {
operationHandlers[op].DecodeOut = f operationHandlers[op].DecodeOut = f
......
...@@ -298,11 +298,22 @@ type NotifyInvalEntryOut struct { ...@@ -298,11 +298,22 @@ type NotifyInvalEntryOut struct {
Padding uint32 Padding uint32
} }
type NotifyInvalDeleteOut struct {
Parent uint64;
Child uint64;
NameLen uint32;
Padding uint32;
}
const ( const (
NOTIFY_POLL = -1 NOTIFY_POLL = -1
NOTIFY_INVAL_INODE = -2 NOTIFY_INVAL_INODE = -2
NOTIFY_INVAL_ENTRY = -3 NOTIFY_INVAL_ENTRY = -3
NOTIFY_CODE_MAX = -4 NOTIFY_STORE = -4
NOTIFY_RETRIEVE = -5
NOTIFY_INVAL_DELETE = -6
NOTIFY_CODE_MAX = -6
) )
type FlushIn struct { type FlushIn struct {
......
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