Skip to content

Commit 52fc3f8

Browse files
committed
fuse notify func impl v1
1 parent 679b527 commit 52fc3f8

8 files changed

Lines changed: 267 additions & 6 deletions

File tree

connection.go

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ func (c *Connection) beginOp(
241241
// should not record any state keyed on their ID.
242242
//
243243
// Cf. https://github.com/osxfuse/osxfuse/issues/208
244-
if opCode != fusekernel.OpForget {
244+
if opCode != fusekernel.OpForget && opCode < 100 {
245245
var cancel func()
246246
ctx, cancel = context.WithCancel(ctx)
247247
c.recordCancelFunc(fuseID, cancel)
@@ -411,6 +411,36 @@ func (c *Connection) ReadOp() (ctx context.Context, op interface{}, err error) {
411411
}
412412
}
413413

414+
func (c *Connection) SetNotifyContext(op interface{}) (context.Context, error) {
415+
416+
outMsg := c.getOutMessage()
417+
418+
err := c.buildNotify(outMsg, op)
419+
if err != nil {
420+
return nil, err
421+
}
422+
423+
ctx := context.Background()
424+
425+
switch op.(type) {
426+
case *fuseops.NotifyInvalInodeOp:
427+
ctx = c.beginOp(100+uint32(fusekernel.NotifyCodeInvalInode), 0)
428+
429+
case *fuseops.NotifyInvalEntryOp:
430+
ctx = c.beginOp(100+uint32(fusekernel.NotifyCodeInvalEntry), 0)
431+
432+
case *fuseops.NotifyDeleteOp:
433+
ctx = c.beginOp(100+uint32(fusekernel.NotifyCodeDelete), 0)
434+
435+
default:
436+
panic(fmt.Sprintf("Unexpected op: %#v", op))
437+
}
438+
439+
ctx = context.WithValue(ctx, contextKey, opState{nil, outMsg, op})
440+
return ctx, nil
441+
442+
}
443+
414444
// Skip errors that happen as a matter of course, since they spook users.
415445
func (c *Connection) shouldLogError(
416446
op interface{},
@@ -498,6 +528,29 @@ func (c *Connection) Reply(ctx context.Context, opErr error) {
498528
}
499529
}
500530

531+
func (c *Connection) NotifyKernel(ctx context.Context) {
532+
533+
// we should get outmsg from context
534+
var key interface{} = contextKey
535+
foo := ctx.Value(key)
536+
state, ok := foo.(opState)
537+
if !ok {
538+
panic(fmt.Sprintf("Reply called with invalid context: %#v", ctx))
539+
}
540+
541+
outMsg := state.outMsg
542+
defer c.putOutMessage(outMsg)
543+
544+
c.debugLogger.Println("dev fd is:unique:notifycode ", c.dev.Fd(), outMsg.OutHeader().Unique, outMsg.OutHeader().Error)
545+
err := c.writeMessage(outMsg.Bytes())
546+
if err != nil && c.errorLogger != nil {
547+
c.errorLogger.Printf("writeMessage: %v %v", err, outMsg.Bytes())
548+
// c.debugLogger.Println("%#v %v %v", ctx, err, outMsg.Bytes())
549+
// panic(fmt.Sprintf(" %#v %v %v", ctx, err, outMsg.Bytes()))
550+
}
551+
552+
}
553+
501554
// Close the connection. Must not be called until operations that were read
502555
// from the connection have been responded to.
503556
func (c *Connection) close() (err error) {

conversions.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,59 @@ func (c *Connection) kernelResponse(
597597
return
598598
}
599599

600+
func (c *Connection) buildNotify(
601+
m *buffer.OutMessage,
602+
op interface{}) error {
603+
604+
h := m.OutHeader()
605+
h.Unique = 0
606+
// Create the appropriate output message
607+
switch o := op.(type) {
608+
case *fuseops.NotifyInvalInodeOp:
609+
h.Error = fusekernel.NotifyCodeInvalInode
610+
size := fusekernel.NotifyInvalInodeOutSize
611+
out := (*fusekernel.NotifyInvalInodeOut)(m.Grow(size))
612+
out.Ino = uint64(o.Ino)
613+
out.Off = int64(o.Off)
614+
out.Len = int64(o.Len)
615+
616+
case *fuseops.NotifyInvalEntryOp:
617+
err := checkName(o.Name)
618+
if err != nil {
619+
return err
620+
}
621+
h.Error = fusekernel.NotifyCodeInvalEntry
622+
size := fusekernel.NotifyInvalEntryOutSize
623+
out := (*fusekernel.NotifyInvalEntryOut)(m.Grow(size))
624+
out.Parent = uint64(o.Parent)
625+
out.Namelen = uint32(len(o.Name))
626+
m.Append([]byte(o.Name))
627+
b := []byte{'\x00'}
628+
m.Append(b)
629+
630+
case *fuseops.NotifyDeleteOp:
631+
err := checkName(o.Name)
632+
if err != nil {
633+
return err
634+
}
635+
h.Error = fusekernel.NotifyCodeDelete
636+
size := fusekernel.NotifyDeleteOutSize
637+
out := (*fusekernel.NotifyDeleteOut)(m.Grow(size))
638+
out.Parent = uint64(o.Parent)
639+
out.Child = uint64(o.Child)
640+
out.Namelen = uint32(len(o.Name))
641+
m.Append([]byte(o.Name))
642+
b := []byte{'\x00'}
643+
m.Append(b)
644+
645+
default:
646+
return errors.New("unexpectedop")
647+
}
648+
h.Len = uint32(m.Len())
649+
650+
return nil
651+
}
652+
600653
// Like kernelResponse, but assumes the user replied with a nil error to the
601654
// op.
602655
func (c *Connection) kernelResponseForOp(
@@ -888,3 +941,11 @@ func writeXattrSize(m *buffer.OutMessage, size uint32) {
888941
out := (*fusekernel.GetxattrOut)(m.Grow(int(unsafe.Sizeof(fusekernel.GetxattrOut{}))))
889942
out.Size = size
890943
}
944+
func checkName(name string) error {
945+
const maxUint32 = ^uint32(0)
946+
if uint64(len(name)) > uint64(maxUint32) {
947+
// very unlikely, but we don't want to silently truncate
948+
return syscall.ENAMETOOLONG
949+
}
950+
return nil
951+
}

fuseops/ops.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -845,3 +845,24 @@ type SetXattrOp struct {
845845
// simply replace the value if the attribute exists.
846846
Flags uint32
847847
}
848+
type NotifyPollOp struct {
849+
}
850+
851+
type NotifyInvalInodeOp struct {
852+
Ino InodeID
853+
Off int64
854+
Len int64
855+
}
856+
type NotifyInvalEntryOp struct {
857+
Parent InodeID
858+
Name string
859+
}
860+
type NotifyStoreOp struct {
861+
}
862+
type NotifyRetrieveOp struct {
863+
}
864+
type NotifyDeleteOp struct {
865+
Parent InodeID
866+
Child InodeID
867+
Name string
868+
}

fuseutil/file_system.go

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// Copyright 2015 Google Inc. All Rights Reserved.
2-
//
31
// Licensed under the Apache License, Version 2.0 (the "License");
42
// you may not use this file except in compliance with the License.
53
// You may obtain a copy of the License at
@@ -88,6 +86,8 @@ func NewFileSystemServer(fs FileSystem) fuse.Server {
8886
type fileSystemServer struct {
8987
fs FileSystem
9088
opsInFlight sync.WaitGroup
89+
//use set/get to use mfs not Mfs
90+
Mfs *fuse.MountedFileSystem
9191
}
9292

9393
func (s *fileSystemServer) ServeOps(c *fuse.Connection) {
@@ -113,6 +113,59 @@ func (s *fileSystemServer) ServeOps(c *fuse.Connection) {
113113
}
114114
}
115115

116+
func (s *fileSystemServer) InvalidateEntry(parent fuseops.InodeID, name string) error {
117+
c := s.GetMfs().Conn.(*fuse.Connection)
118+
119+
op := &fuseops.NotifyInvalEntryOp{
120+
Parent: fuseops.InodeID(parent),
121+
Name: string(name),
122+
}
123+
ctx, _ := c.SetNotifyContext(op)
124+
s.opsInFlight.Add(1)
125+
go func(ctx context.Context) {
126+
defer s.opsInFlight.Done()
127+
c.NotifyKernel(ctx)
128+
}(ctx)
129+
return nil
130+
}
131+
func (s *fileSystemServer) NotifyDelete(
132+
parent fuseops.InodeID,
133+
child fuseops.InodeID,
134+
name string) error {
135+
c := s.GetMfs().Conn.(*fuse.Connection)
136+
op := &fuseops.NotifyDeleteOp{
137+
Parent: fuseops.InodeID(parent),
138+
Child: fuseops.InodeID(child),
139+
Name: string(name),
140+
}
141+
ctx, _ := c.SetNotifyContext(op)
142+
s.opsInFlight.Add(1)
143+
go func(ctx context.Context) {
144+
defer s.opsInFlight.Done()
145+
c.NotifyKernel(ctx)
146+
}(ctx)
147+
return nil
148+
149+
}
150+
func (s *fileSystemServer) InvalidateInode(
151+
ino fuseops.InodeID,
152+
off int64,
153+
len int64) error {
154+
c := s.GetMfs().Conn.(*fuse.Connection)
155+
op := &fuseops.NotifyInvalInodeOp{
156+
Ino: fuseops.InodeID(ino),
157+
Off: off,
158+
Len: len,
159+
}
160+
ctx, _ := c.SetNotifyContext(op)
161+
s.opsInFlight.Add(1)
162+
go func(ctx context.Context) {
163+
defer s.opsInFlight.Done()
164+
c.NotifyKernel(ctx)
165+
}(ctx)
166+
return nil
167+
168+
}
116169
func (s *fileSystemServer) handleOp(
117170
c *fuse.Connection,
118171
ctx context.Context,
@@ -206,3 +259,12 @@ func (s *fileSystemServer) handleOp(
206259

207260
c.Reply(ctx, err)
208261
}
262+
263+
func (s *fileSystemServer) GetMfs() *fuse.MountedFileSystem {
264+
return s.Mfs
265+
266+
}
267+
func (s *fileSystemServer) SetMfs(mfs *fuse.MountedFileSystem) {
268+
s.Mfs = mfs
269+
270+
}

internal/fusekernel/fuse_kernel.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -756,6 +756,9 @@ const (
756756
NotifyCodePoll int32 = 1
757757
NotifyCodeInvalInode int32 = 2
758758
NotifyCodeInvalEntry int32 = 3
759+
NotifyCodeStore int32 = 4
760+
NotifyCodeRetrieve int32 = 5
761+
NotifyCodeDelete int32 = 6
759762
)
760763

761764
type NotifyInvalInodeOut struct {
@@ -764,8 +767,46 @@ type NotifyInvalInodeOut struct {
764767
Len int64
765768
}
766769

770+
const NotifyInvalInodeOutSize = int(unsafe.Sizeof(NotifyInvalInodeOut{}))
771+
767772
type NotifyInvalEntryOut struct {
768773
Parent uint64
769774
Namelen uint32
770775
padding uint32
771776
}
777+
778+
const NotifyInvalEntryOutSize = int(unsafe.Sizeof(NotifyInvalEntryOut{}))
779+
780+
type NotifyDeleteOut struct {
781+
Parent uint64
782+
Child uint64
783+
Namelen uint32
784+
padding uint32
785+
}
786+
787+
const NotifyDeleteOutSize = int(unsafe.Sizeof(NotifyDeleteOut{}))
788+
789+
type NotifyStoreOut struct {
790+
Nodeid uint64
791+
Offset uint64
792+
Size uint32
793+
padding uint32
794+
}
795+
796+
type NotifyRetrieveOut struct {
797+
NotifyUnique uint64
798+
Nodeid uint64
799+
Offset uint64
800+
Size uint32
801+
padding uint32
802+
}
803+
804+
/* Matches the size of fuse_write_in */
805+
type NotifyRetrieveIn struct {
806+
Dummy1 uint64
807+
Offset uint64
808+
Size uint32
809+
Dummy2 uint32
810+
Dummy3 uint64
811+
Dummy4 uint64
812+
}

mount.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// Copyright 2015 Google Inc. All Rights Reserved.
2-
//
31
// Licensed under the Apache License, Version 2.0 (the "License");
42
// you may not use this file except in compliance with the License.
53
// You may obtain a copy of the License at
@@ -18,6 +16,7 @@ import (
1816
"fmt"
1917
"os"
2018

19+
"github.com/jacobsa/fuse/fuseops"
2120
"golang.org/x/net/context"
2221
)
2322

@@ -28,6 +27,11 @@ type Server interface {
2827
// until all operations have been responded to. Must not be called more than
2928
// once.
3029
ServeOps(*Connection)
30+
InvalidateEntry(fuseops.InodeID, string) error
31+
InvalidateInode(fuseops.InodeID, int64, int64) error
32+
NotifyDelete(fuseops.InodeID, fuseops.InodeID, string) error
33+
SetMfs(*MountedFileSystem)
34+
GetMfs() *MountedFileSystem
3135
}
3236

3337
// Mount attempts to mount a file system on the given directory, using the
@@ -85,7 +89,8 @@ func Mount(
8589
return
8690
}
8791

88-
// Serve the connection in the background. When done, set the join status.
92+
mfs.Conn = connection
93+
server.SetMfs(mfs)
8994
go func() {
9095
server.ServeOps(connection)
9196
mfs.joinStatus = connection.close()

mounted_file_system.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ type MountedFileSystem struct {
2424
// The result to return from Join. Not valid until the channel is closed.
2525
joinStatus error
2626
joinStatusAvailable chan struct{}
27+
Conn interface{}
2728
}
2829

2930
// Dir returns the directory on which the file system is mounted (or where we

samples/forgetfs/forget_fs.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,23 @@ type ForgetFS struct {
9999
func (fs *ForgetFS) ServeOps(c *fuse.Connection) {
100100
fs.server.ServeOps(c)
101101
}
102+
func (fs *ForgetFS) SetMfs(mfs *fuse.MountedFileSystem) {
103+
fs.server.SetMfs(mfs)
104+
}
105+
func (fs *ForgetFS) GetMfs() *fuse.MountedFileSystem {
106+
return fs.server.GetMfs()
107+
}
108+
func (fs *ForgetFS) InvalidateEntry(nodeid fuseops.InodeID, name string) error {
109+
return nil
110+
}
111+
112+
func (fs *ForgetFS) InvalidateInode(nodeid fuseops.InodeID, parent int64, nlookup int64) error {
113+
return nil
114+
}
115+
116+
func (fs *ForgetFS) NotifyDelete(nodeid fuseops.InodeID, parent fuseops.InodeID, name string) error {
117+
return nil
118+
}
102119

103120
// Panic if there are any inodes that have a non-zero reference count. For use
104121
// after unmounting.

0 commit comments

Comments
 (0)