Compare commits
8 Commits
master
...
notificati
Author | SHA1 | Date |
---|---|---|
Vitaliy Filippov | a091e49319 | |
Vitaliy Filippov | 54ad710d24 | |
Vitaliy Filippov | ac7ca2c754 | |
dependabot[bot] | 86031ac261 | |
Doug Schaapveld | 702f658418 | |
Doug Schaapveld | bb43c71d6f | |
Ayush Sethi | 5e0f2e6b43 | |
Lars Gohr | c2e09611e9 |
|
@ -369,18 +369,24 @@ func (c *Connection) readMessage() (*buffer.InMessage, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write the supplied message to the kernel.
|
// Write the supplied message to the kernel.
|
||||||
func (c *Connection) writeMessage(msg []byte) error {
|
func (c *Connection) writeMessage(outMsg *buffer.OutMessage) error {
|
||||||
// Avoid the retry loop in os.File.Write.
|
var err error
|
||||||
n, err := syscall.Write(int(c.dev.Fd()), msg)
|
var n int
|
||||||
if err != nil {
|
expectedLen := outMsg.Len()
|
||||||
return err
|
if outMsg.Sglist != nil {
|
||||||
|
n, err = writev(int(c.dev.Fd()), outMsg.Sglist)
|
||||||
|
} else {
|
||||||
|
// Avoid the retry loop in os.File.Write.
|
||||||
|
n, err = syscall.Write(int(c.dev.Fd()), outMsg.OutHeaderBytes())
|
||||||
}
|
}
|
||||||
|
if err == nil && n != expectedLen {
|
||||||
if n != len(msg) {
|
err = fmt.Errorf("Wrote %d bytes; expected %d", n, expectedLen)
|
||||||
return fmt.Errorf("Wrote %d bytes; expected %d", n, len(msg))
|
|
||||||
}
|
}
|
||||||
|
if err != nil && c.errorLogger != nil {
|
||||||
return nil
|
c.errorLogger.Printf("writeMessage: %v %v", err, outMsg.OutHeaderBytes())
|
||||||
|
}
|
||||||
|
outMsg.Sglist = nil
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadOp consumes the next op from the kernel process, returning the op and a
|
// ReadOp consumes the next op from the kernel process, returning the op and a
|
||||||
|
@ -510,19 +516,21 @@ func (c *Connection) Reply(ctx context.Context, opErr error) {
|
||||||
noResponse := c.kernelResponse(outMsg, inMsg.Header().Unique, op, opErr)
|
noResponse := c.kernelResponse(outMsg, inMsg.Header().Unique, op, opErr)
|
||||||
|
|
||||||
if !noResponse {
|
if !noResponse {
|
||||||
var err error
|
c.writeMessage(outMsg)
|
||||||
if outMsg.Sglist != nil {
|
|
||||||
_, err = writev(int(c.dev.Fd()), outMsg.Sglist)
|
|
||||||
} else {
|
|
||||||
err = c.writeMessage(outMsg.OutHeaderBytes())
|
|
||||||
}
|
|
||||||
if err != nil && c.errorLogger != nil {
|
|
||||||
c.errorLogger.Printf("writeMessage: %v %v", err, outMsg.OutHeaderBytes())
|
|
||||||
}
|
|
||||||
outMsg.Sglist = nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Send a notification to the kernel
|
||||||
|
// notification must be a pointer to one of fuseops.NotifyXXX structures
|
||||||
|
// To avoid a deadlock notifications must not be called in the execution path of a related filesytem operation or within any code that could hold a lock that could be needed to execute such an operation. As of kernel 4.18, a "related operation" is a lookup(), symlink(), mknod(), mkdir(), unlink(), rename(), link() or create() request for the parent, and a setattr(), unlink(), rmdir(), rename(), setxattr(), removexattr(), readdir() or readdirplus() request for the inode itself.
|
||||||
|
func (c *Connection) Notify(notification interface{}) error {
|
||||||
|
outMsg := c.getOutMessage()
|
||||||
|
defer c.putOutMessage(outMsg)
|
||||||
|
c.kernelNotification(outMsg, notification)
|
||||||
|
outMsg.OutHeader().Len = uint32(outMsg.Len())
|
||||||
|
return c.writeMessage(outMsg)
|
||||||
|
}
|
||||||
|
|
||||||
// Close the connection. Must not be called until operations that were read
|
// Close the connection. Must not be called until operations that were read
|
||||||
// from the connection have been responded to.
|
// from the connection have been responded to.
|
||||||
func (c *Connection) close() error {
|
func (c *Connection) close() error {
|
||||||
|
|
353
conversions.go
353
conversions.go
|
@ -51,15 +51,21 @@ func convertInMessage(
|
||||||
}
|
}
|
||||||
|
|
||||||
o = &fuseops.LookUpInodeOp{
|
o = &fuseops.LookUpInodeOp{
|
||||||
Parent: fuseops.InodeID(inMsg.Header().Nodeid),
|
Parent: fuseops.InodeID(inMsg.Header().Nodeid),
|
||||||
Name: string(buf[:n-1]),
|
Name: string(buf[:n-1]),
|
||||||
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
|
OpContext: fuseops.OpContext{
|
||||||
|
FuseID: inMsg.Header().Unique,
|
||||||
|
Pid: inMsg.Header().Pid,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
case fusekernel.OpGetattr:
|
case fusekernel.OpGetattr:
|
||||||
o = &fuseops.GetInodeAttributesOp{
|
o = &fuseops.GetInodeAttributesOp{
|
||||||
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
|
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
|
||||||
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
|
OpContext: fuseops.OpContext{
|
||||||
|
FuseID: inMsg.Header().Unique,
|
||||||
|
Pid: inMsg.Header().Pid,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
case fusekernel.OpSetattr:
|
case fusekernel.OpSetattr:
|
||||||
|
@ -70,8 +76,11 @@ func convertInMessage(
|
||||||
}
|
}
|
||||||
|
|
||||||
to := &fuseops.SetInodeAttributesOp{
|
to := &fuseops.SetInodeAttributesOp{
|
||||||
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
|
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
|
||||||
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
|
OpContext: fuseops.OpContext{
|
||||||
|
FuseID: inMsg.Header().Unique,
|
||||||
|
Pid: inMsg.Header().Pid,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
o = to
|
o = to
|
||||||
|
|
||||||
|
@ -116,9 +125,12 @@ func convertInMessage(
|
||||||
}
|
}
|
||||||
|
|
||||||
o = &fuseops.ForgetInodeOp{
|
o = &fuseops.ForgetInodeOp{
|
||||||
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
|
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
|
||||||
N: in.Nlookup,
|
N: in.Nlookup,
|
||||||
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
|
OpContext: fuseops.OpContext{
|
||||||
|
FuseID: inMsg.Header().Unique,
|
||||||
|
Pid: inMsg.Header().Pid,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
case fusekernel.OpBatchForget:
|
case fusekernel.OpBatchForget:
|
||||||
|
@ -143,8 +155,11 @@ func convertInMessage(
|
||||||
}
|
}
|
||||||
|
|
||||||
o = &fuseops.BatchForgetOp{
|
o = &fuseops.BatchForgetOp{
|
||||||
Entries: entries,
|
Entries: entries,
|
||||||
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
|
OpContext: fuseops.OpContext{
|
||||||
|
FuseID: inMsg.Header().Unique,
|
||||||
|
Pid: inMsg.Header().Pid,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
case fusekernel.OpMkdir:
|
case fusekernel.OpMkdir:
|
||||||
|
@ -170,8 +185,11 @@ func convertInMessage(
|
||||||
// the fact that this is a directory is implicit in the fact that the
|
// the fact that this is a directory is implicit in the fact that the
|
||||||
// opcode is mkdir. But we want the correct mode to go through, so ensure
|
// opcode is mkdir. But we want the correct mode to go through, so ensure
|
||||||
// that os.ModeDir is set.
|
// that os.ModeDir is set.
|
||||||
Mode: convertFileMode(in.Mode) | os.ModeDir,
|
Mode: convertFileMode(in.Mode) | os.ModeDir,
|
||||||
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
|
OpContext: fuseops.OpContext{
|
||||||
|
FuseID: inMsg.Header().Unique,
|
||||||
|
Pid: inMsg.Header().Pid,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
case fusekernel.OpMknod:
|
case fusekernel.OpMknod:
|
||||||
|
@ -188,10 +206,13 @@ func convertInMessage(
|
||||||
name = name[:i]
|
name = name[:i]
|
||||||
|
|
||||||
o = &fuseops.MkNodeOp{
|
o = &fuseops.MkNodeOp{
|
||||||
Parent: fuseops.InodeID(inMsg.Header().Nodeid),
|
Parent: fuseops.InodeID(inMsg.Header().Nodeid),
|
||||||
Name: string(name),
|
Name: string(name),
|
||||||
Mode: convertFileMode(in.Mode),
|
Mode: convertFileMode(in.Mode),
|
||||||
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
|
OpContext: fuseops.OpContext{
|
||||||
|
FuseID: inMsg.Header().Unique,
|
||||||
|
Pid: inMsg.Header().Pid,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
case fusekernel.OpCreate:
|
case fusekernel.OpCreate:
|
||||||
|
@ -208,10 +229,13 @@ func convertInMessage(
|
||||||
name = name[:i]
|
name = name[:i]
|
||||||
|
|
||||||
o = &fuseops.CreateFileOp{
|
o = &fuseops.CreateFileOp{
|
||||||
Parent: fuseops.InodeID(inMsg.Header().Nodeid),
|
Parent: fuseops.InodeID(inMsg.Header().Nodeid),
|
||||||
Name: string(name),
|
Name: string(name),
|
||||||
Mode: convertFileMode(in.Mode),
|
Mode: convertFileMode(in.Mode),
|
||||||
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
|
OpContext: fuseops.OpContext{
|
||||||
|
FuseID: inMsg.Header().Unique,
|
||||||
|
Pid: inMsg.Header().Pid,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
case fusekernel.OpSymlink:
|
case fusekernel.OpSymlink:
|
||||||
|
@ -227,10 +251,13 @@ func convertInMessage(
|
||||||
newName, target := names[0:i], names[i+1:len(names)-1]
|
newName, target := names[0:i], names[i+1:len(names)-1]
|
||||||
|
|
||||||
o = &fuseops.CreateSymlinkOp{
|
o = &fuseops.CreateSymlinkOp{
|
||||||
Parent: fuseops.InodeID(inMsg.Header().Nodeid),
|
Parent: fuseops.InodeID(inMsg.Header().Nodeid),
|
||||||
Name: string(newName),
|
Name: string(newName),
|
||||||
Target: string(target),
|
Target: string(target),
|
||||||
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
|
OpContext: fuseops.OpContext{
|
||||||
|
FuseID: inMsg.Header().Unique,
|
||||||
|
Pid: inMsg.Header().Pid,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
case fusekernel.OpRename:
|
case fusekernel.OpRename:
|
||||||
|
@ -272,7 +299,10 @@ func convertInMessage(
|
||||||
OldName: string(oldName),
|
OldName: string(oldName),
|
||||||
NewParent: fuseops.InodeID(in.Newdir),
|
NewParent: fuseops.InodeID(in.Newdir),
|
||||||
NewName: string(newName),
|
NewName: string(newName),
|
||||||
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
|
OpContext: fuseops.OpContext{
|
||||||
|
FuseID: inMsg.Header().Unique,
|
||||||
|
Pid: inMsg.Header().Pid,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
case fusekernel.OpUnlink:
|
case fusekernel.OpUnlink:
|
||||||
|
@ -283,9 +313,12 @@ func convertInMessage(
|
||||||
}
|
}
|
||||||
|
|
||||||
o = &fuseops.UnlinkOp{
|
o = &fuseops.UnlinkOp{
|
||||||
Parent: fuseops.InodeID(inMsg.Header().Nodeid),
|
Parent: fuseops.InodeID(inMsg.Header().Nodeid),
|
||||||
Name: string(buf[:n-1]),
|
Name: string(buf[:n-1]),
|
||||||
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
|
OpContext: fuseops.OpContext{
|
||||||
|
FuseID: inMsg.Header().Unique,
|
||||||
|
Pid: inMsg.Header().Pid,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
case fusekernel.OpRmdir:
|
case fusekernel.OpRmdir:
|
||||||
|
@ -296,9 +329,12 @@ func convertInMessage(
|
||||||
}
|
}
|
||||||
|
|
||||||
o = &fuseops.RmDirOp{
|
o = &fuseops.RmDirOp{
|
||||||
Parent: fuseops.InodeID(inMsg.Header().Nodeid),
|
Parent: fuseops.InodeID(inMsg.Header().Nodeid),
|
||||||
Name: string(buf[:n-1]),
|
Name: string(buf[:n-1]),
|
||||||
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
|
OpContext: fuseops.OpContext{
|
||||||
|
FuseID: inMsg.Header().Unique,
|
||||||
|
Pid: inMsg.Header().Pid,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
case fusekernel.OpOpen:
|
case fusekernel.OpOpen:
|
||||||
|
@ -311,13 +347,19 @@ func convertInMessage(
|
||||||
o = &fuseops.OpenFileOp{
|
o = &fuseops.OpenFileOp{
|
||||||
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
|
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
|
||||||
OpenFlags: fusekernel.OpenFlags(in.Flags),
|
OpenFlags: fusekernel.OpenFlags(in.Flags),
|
||||||
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
|
OpContext: fuseops.OpContext{
|
||||||
|
FuseID: inMsg.Header().Unique,
|
||||||
|
Pid: inMsg.Header().Pid,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
case fusekernel.OpOpendir:
|
case fusekernel.OpOpendir:
|
||||||
o = &fuseops.OpenDirOp{
|
o = &fuseops.OpenDirOp{
|
||||||
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
|
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
|
||||||
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
|
OpContext: fuseops.OpContext{
|
||||||
|
FuseID: inMsg.Header().Unique,
|
||||||
|
Pid: inMsg.Header().Pid,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
case fusekernel.OpRead:
|
case fusekernel.OpRead:
|
||||||
|
@ -327,11 +369,14 @@ func convertInMessage(
|
||||||
}
|
}
|
||||||
|
|
||||||
to := &fuseops.ReadFileOp{
|
to := &fuseops.ReadFileOp{
|
||||||
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
|
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
|
||||||
Handle: fuseops.HandleID(in.Fh),
|
Handle: fuseops.HandleID(in.Fh),
|
||||||
Offset: int64(in.Offset),
|
Offset: int64(in.Offset),
|
||||||
Size: int64(in.Size),
|
Size: int64(in.Size),
|
||||||
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
|
OpContext: fuseops.OpContext{
|
||||||
|
FuseID: inMsg.Header().Unique,
|
||||||
|
Pid: inMsg.Header().Pid,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
if !config.UseVectoredRead {
|
if !config.UseVectoredRead {
|
||||||
// Use part of the incoming message storage as the read buffer
|
// Use part of the incoming message storage as the read buffer
|
||||||
|
@ -347,10 +392,13 @@ func convertInMessage(
|
||||||
}
|
}
|
||||||
|
|
||||||
to := &fuseops.ReadDirOp{
|
to := &fuseops.ReadDirOp{
|
||||||
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
|
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
|
||||||
Handle: fuseops.HandleID(in.Fh),
|
Handle: fuseops.HandleID(in.Fh),
|
||||||
Offset: fuseops.DirOffset(in.Offset),
|
Offset: fuseops.DirOffset(in.Offset),
|
||||||
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
|
OpContext: fuseops.OpContext{
|
||||||
|
FuseID: inMsg.Header().Unique,
|
||||||
|
Pid: inMsg.Header().Pid,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
o = to
|
o = to
|
||||||
|
|
||||||
|
@ -373,8 +421,11 @@ func convertInMessage(
|
||||||
}
|
}
|
||||||
|
|
||||||
o = &fuseops.ReleaseFileHandleOp{
|
o = &fuseops.ReleaseFileHandleOp{
|
||||||
Handle: fuseops.HandleID(in.Fh),
|
Handle: fuseops.HandleID(in.Fh),
|
||||||
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
|
OpContext: fuseops.OpContext{
|
||||||
|
FuseID: inMsg.Header().Unique,
|
||||||
|
Pid: inMsg.Header().Pid,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
case fusekernel.OpReleasedir:
|
case fusekernel.OpReleasedir:
|
||||||
|
@ -385,8 +436,11 @@ func convertInMessage(
|
||||||
}
|
}
|
||||||
|
|
||||||
o = &fuseops.ReleaseDirHandleOp{
|
o = &fuseops.ReleaseDirHandleOp{
|
||||||
Handle: fuseops.HandleID(in.Fh),
|
Handle: fuseops.HandleID(in.Fh),
|
||||||
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
|
OpContext: fuseops.OpContext{
|
||||||
|
FuseID: inMsg.Header().Unique,
|
||||||
|
Pid: inMsg.Header().Pid,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
case fusekernel.OpWrite:
|
case fusekernel.OpWrite:
|
||||||
|
@ -401,11 +455,14 @@ func convertInMessage(
|
||||||
}
|
}
|
||||||
|
|
||||||
o = &fuseops.WriteFileOp{
|
o = &fuseops.WriteFileOp{
|
||||||
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
|
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
|
||||||
Handle: fuseops.HandleID(in.Fh),
|
Handle: fuseops.HandleID(in.Fh),
|
||||||
Data: buf,
|
Data: buf,
|
||||||
Offset: int64(in.Offset),
|
Offset: int64(in.Offset),
|
||||||
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
|
OpContext: fuseops.OpContext{
|
||||||
|
FuseID: inMsg.Header().Unique,
|
||||||
|
Pid: inMsg.Header().Pid,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
case fusekernel.OpFsync, fusekernel.OpFsyncdir:
|
case fusekernel.OpFsync, fusekernel.OpFsyncdir:
|
||||||
|
@ -416,9 +473,12 @@ func convertInMessage(
|
||||||
}
|
}
|
||||||
|
|
||||||
o = &fuseops.SyncFileOp{
|
o = &fuseops.SyncFileOp{
|
||||||
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
|
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
|
||||||
Handle: fuseops.HandleID(in.Fh),
|
Handle: fuseops.HandleID(in.Fh),
|
||||||
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
|
OpContext: fuseops.OpContext{
|
||||||
|
FuseID: inMsg.Header().Unique,
|
||||||
|
Pid: inMsg.Header().Pid,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
case fusekernel.OpFlush:
|
case fusekernel.OpFlush:
|
||||||
|
@ -429,15 +489,21 @@ func convertInMessage(
|
||||||
}
|
}
|
||||||
|
|
||||||
o = &fuseops.FlushFileOp{
|
o = &fuseops.FlushFileOp{
|
||||||
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
|
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
|
||||||
Handle: fuseops.HandleID(in.Fh),
|
Handle: fuseops.HandleID(in.Fh),
|
||||||
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
|
OpContext: fuseops.OpContext{
|
||||||
|
FuseID: inMsg.Header().Unique,
|
||||||
|
Pid: inMsg.Header().Pid,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
case fusekernel.OpReadlink:
|
case fusekernel.OpReadlink:
|
||||||
o = &fuseops.ReadSymlinkOp{
|
o = &fuseops.ReadSymlinkOp{
|
||||||
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
|
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
|
||||||
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
|
OpContext: fuseops.OpContext{
|
||||||
|
FuseID: inMsg.Header().Unique,
|
||||||
|
Pid: inMsg.Header().Pid,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
case fusekernel.OpStatfs:
|
case fusekernel.OpStatfs:
|
||||||
|
@ -485,10 +551,13 @@ func convertInMessage(
|
||||||
}
|
}
|
||||||
|
|
||||||
o = &fuseops.CreateLinkOp{
|
o = &fuseops.CreateLinkOp{
|
||||||
Parent: fuseops.InodeID(inMsg.Header().Nodeid),
|
Parent: fuseops.InodeID(inMsg.Header().Nodeid),
|
||||||
Name: string(name),
|
Name: string(name),
|
||||||
Target: fuseops.InodeID(in.Oldnodeid),
|
Target: fuseops.InodeID(in.Oldnodeid),
|
||||||
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
|
OpContext: fuseops.OpContext{
|
||||||
|
FuseID: inMsg.Header().Unique,
|
||||||
|
Pid: inMsg.Header().Pid,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
case fusekernel.OpRemovexattr:
|
case fusekernel.OpRemovexattr:
|
||||||
|
@ -499,9 +568,12 @@ func convertInMessage(
|
||||||
}
|
}
|
||||||
|
|
||||||
o = &fuseops.RemoveXattrOp{
|
o = &fuseops.RemoveXattrOp{
|
||||||
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
|
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
|
||||||
Name: string(buf[:n-1]),
|
Name: string(buf[:n-1]),
|
||||||
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
|
OpContext: fuseops.OpContext{
|
||||||
|
FuseID: inMsg.Header().Unique,
|
||||||
|
Pid: inMsg.Header().Pid,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
case fusekernel.OpGetxattr:
|
case fusekernel.OpGetxattr:
|
||||||
|
@ -519,9 +591,12 @@ func convertInMessage(
|
||||||
name = name[:i]
|
name = name[:i]
|
||||||
|
|
||||||
to := &fuseops.GetXattrOp{
|
to := &fuseops.GetXattrOp{
|
||||||
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
|
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
|
||||||
Name: string(name),
|
Name: string(name),
|
||||||
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
|
OpContext: fuseops.OpContext{
|
||||||
|
FuseID: inMsg.Header().Unique,
|
||||||
|
Pid: inMsg.Header().Pid,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
o = to
|
o = to
|
||||||
|
|
||||||
|
@ -548,8 +623,11 @@ func convertInMessage(
|
||||||
}
|
}
|
||||||
|
|
||||||
to := &fuseops.ListXattrOp{
|
to := &fuseops.ListXattrOp{
|
||||||
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
|
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
|
||||||
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
|
OpContext: fuseops.OpContext{
|
||||||
|
FuseID: inMsg.Header().Unique,
|
||||||
|
Pid: inMsg.Header().Pid,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
o = to
|
o = to
|
||||||
|
|
||||||
|
@ -584,11 +662,13 @@ func convertInMessage(
|
||||||
name, value := payload[:i], payload[i+1:len(payload)]
|
name, value := payload[:i], payload[i+1:len(payload)]
|
||||||
|
|
||||||
o = &fuseops.SetXattrOp{
|
o = &fuseops.SetXattrOp{
|
||||||
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
|
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
|
||||||
Name: string(name),
|
Name: string(name),
|
||||||
Value: value,
|
Value: value,
|
||||||
Flags: in.Flags,
|
Flags: in.Flags,
|
||||||
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
|
OpContext: fuseops.OpContext{
|
||||||
|
FuseID: inMsg.Header().Unique,
|
||||||
|
Pid: inMsg.Header().Pid},
|
||||||
}
|
}
|
||||||
case fusekernel.OpFallocate:
|
case fusekernel.OpFallocate:
|
||||||
type input fusekernel.FallocateIn
|
type input fusekernel.FallocateIn
|
||||||
|
@ -598,11 +678,49 @@ func convertInMessage(
|
||||||
}
|
}
|
||||||
|
|
||||||
o = &fuseops.FallocateOp{
|
o = &fuseops.FallocateOp{
|
||||||
|
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
|
||||||
|
Handle: fuseops.HandleID(in.Fh),
|
||||||
|
Offset: in.Offset,
|
||||||
|
Length: in.Length,
|
||||||
|
Mode: in.Mode,
|
||||||
|
OpContext: fuseops.OpContext{
|
||||||
|
FuseID: inMsg.Header().Unique,
|
||||||
|
Pid: inMsg.Header().Pid},
|
||||||
|
}
|
||||||
|
|
||||||
|
case fusekernel.OpPoll:
|
||||||
|
type input fusekernel.PollIn
|
||||||
|
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
|
||||||
|
if in == nil {
|
||||||
|
return nil, errors.New("Corrupt OpPoll")
|
||||||
|
}
|
||||||
|
|
||||||
|
o = &fuseops.PollOp{
|
||||||
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
|
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
|
||||||
Handle: fuseops.HandleID(in.Fh),
|
Handle: fuseops.HandleID(in.Fh),
|
||||||
|
Kh: in.Kh,
|
||||||
|
Flags: fusekernel.PollFlags(in.Flags),
|
||||||
|
Events: fusekernel.PollEvents(in.Events),
|
||||||
|
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
|
||||||
|
}
|
||||||
|
|
||||||
|
case fusekernel.OpNotifyReply:
|
||||||
|
type input fusekernel.NotifyRetrieveIn
|
||||||
|
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
|
||||||
|
if in == nil {
|
||||||
|
return nil, errors.New("Corrupt OpNotifyReply")
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := inMsg.ConsumeBytes(inMsg.Len())
|
||||||
|
if len(buf) < int(in.Size) {
|
||||||
|
return nil, errors.New("Corrupt OpNotifyReply")
|
||||||
|
}
|
||||||
|
|
||||||
|
o = &fuseops.NotifyRetrieveReplyOp{
|
||||||
|
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
|
||||||
|
Unique: inMsg.Header().Unique,
|
||||||
Offset: in.Offset,
|
Offset: in.Offset,
|
||||||
Length: in.Length,
|
Length: in.Size,
|
||||||
Mode: in.Mode,
|
|
||||||
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
|
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -639,6 +757,9 @@ func (c *Connection) kernelResponse(
|
||||||
case *fuseops.BatchForgetOp:
|
case *fuseops.BatchForgetOp:
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
case *fuseops.NotifyRetrieveReplyOp:
|
||||||
|
return true
|
||||||
|
|
||||||
case *interruptOp:
|
case *interruptOp:
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -862,6 +983,13 @@ func (c *Connection) kernelResponseForOp(
|
||||||
out.TimeGran = 1
|
out.TimeGran = 1
|
||||||
out.MaxPages = o.MaxPages
|
out.MaxPages = o.MaxPages
|
||||||
|
|
||||||
|
case *fuseops.PollOp:
|
||||||
|
out := (*fusekernel.PollOut)(m.Grow(int(unsafe.Sizeof(fusekernel.PollOut{}))))
|
||||||
|
out.Revents = uint32(o.Revents)
|
||||||
|
|
||||||
|
case *fuseops.NotifyRetrieveReplyOp:
|
||||||
|
// Empty response
|
||||||
|
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("Unexpected op: %#v", op))
|
panic(fmt.Sprintf("Unexpected op: %#v", op))
|
||||||
}
|
}
|
||||||
|
@ -869,6 +997,69 @@ func (c *Connection) kernelResponseForOp(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Like kernelResponse, but assumes the user replied with a nil error to the op.
|
||||||
|
func (c *Connection) kernelNotification(
|
||||||
|
m *buffer.OutMessage,
|
||||||
|
op interface{}) {
|
||||||
|
|
||||||
|
h := m.OutHeader()
|
||||||
|
h.Unique = 0
|
||||||
|
|
||||||
|
// Create the appropriate output message
|
||||||
|
switch o := op.(type) {
|
||||||
|
case *fuseops.NotifyPollWakeup:
|
||||||
|
h.Error = fusekernel.NotifyCodePoll
|
||||||
|
out := (*fusekernel.NotifyPollWakeupOut)(m.Grow(int(unsafe.Sizeof(fusekernel.NotifyPollWakeupOut{}))))
|
||||||
|
out.Kh = o.Kh
|
||||||
|
|
||||||
|
case *fuseops.NotifyInvalInode:
|
||||||
|
h.Error = fusekernel.NotifyCodeInvalInode
|
||||||
|
out := (*fusekernel.NotifyInvalInodeOut)(m.Grow(int(unsafe.Sizeof(fusekernel.NotifyInvalInodeOut{}))))
|
||||||
|
out.Ino = uint64(o.Inode)
|
||||||
|
out.Off = o.Offset
|
||||||
|
out.Len = o.Length
|
||||||
|
|
||||||
|
case *fuseops.NotifyInvalEntry:
|
||||||
|
h.Error = fusekernel.NotifyCodeInvalEntry
|
||||||
|
out := (*fusekernel.NotifyInvalEntryOut)(m.Grow(int(unsafe.Sizeof(fusekernel.NotifyInvalEntryOut{}))))
|
||||||
|
out.Parent = uint64(o.Parent)
|
||||||
|
out.Namelen = uint32(len(o.Name))
|
||||||
|
m.AppendString(o.Name)
|
||||||
|
m.AppendString("\x00")
|
||||||
|
|
||||||
|
case *fuseops.NotifyDelete:
|
||||||
|
h.Error = fusekernel.NotifyCodeDelete
|
||||||
|
out := (*fusekernel.NotifyDeleteOut)(m.Grow(int(unsafe.Sizeof(fusekernel.NotifyDeleteOut{}))))
|
||||||
|
out.Parent = uint64(o.Parent)
|
||||||
|
out.Child = uint64(o.Child)
|
||||||
|
out.Namelen = uint32(len(o.Name))
|
||||||
|
m.AppendString(o.Name)
|
||||||
|
m.AppendString("\x00")
|
||||||
|
|
||||||
|
case *fuseops.NotifyStore:
|
||||||
|
h.Error = fusekernel.NotifyCodeStore
|
||||||
|
out := (*fusekernel.NotifyStoreOut)(m.Grow(int(unsafe.Sizeof(fusekernel.NotifyStoreOut{}))))
|
||||||
|
out.Nodeid = uint64(o.Inode)
|
||||||
|
out.Offset = o.Offset
|
||||||
|
out.Size = o.Length
|
||||||
|
m.Append(o.Data...)
|
||||||
|
m.ShrinkTo(buffer.OutMessageHeaderSize + int(unsafe.Sizeof(fusekernel.NotifyStoreOut{})) + int(o.Length))
|
||||||
|
|
||||||
|
case *fuseops.NotifyRetrieve:
|
||||||
|
h.Error = fusekernel.NotifyCodeRetrieve
|
||||||
|
out := (*fusekernel.NotifyRetrieveOut)(m.Grow(int(unsafe.Sizeof(fusekernel.NotifyRetrieveOut{}))))
|
||||||
|
out.Unique = o.Unique
|
||||||
|
out.Nodeid = uint64(o.Inode)
|
||||||
|
out.Offset = o.Offset
|
||||||
|
out.Size = o.Length
|
||||||
|
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("Unexpected notification: %#v", op))
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
// General conversions
|
// General conversions
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
|
127
fuseops/ops.go
127
fuseops/ops.go
|
@ -28,6 +28,9 @@ import (
|
||||||
// OpContext contains extra context that may be needed by some file systems.
|
// OpContext contains extra context that may be needed by some file systems.
|
||||||
// See https://libfuse.github.io/doxygen/structfuse__context.html as a reference.
|
// See https://libfuse.github.io/doxygen/structfuse__context.html as a reference.
|
||||||
type OpContext struct {
|
type OpContext struct {
|
||||||
|
// FuseID is the Unique identifier for each operation from the kernel.
|
||||||
|
FuseID uint64
|
||||||
|
|
||||||
// PID of the process that is invoking the operation.
|
// PID of the process that is invoking the operation.
|
||||||
// Not filled in case of a writepage operation.
|
// Not filled in case of a writepage operation.
|
||||||
Pid uint32
|
Pid uint32
|
||||||
|
@ -962,3 +965,127 @@ type FallocateOp struct {
|
||||||
Mode uint32
|
Mode uint32
|
||||||
OpContext OpContext
|
OpContext OpContext
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Request notifications when the file system user calls poll/select or
|
||||||
|
// similar operations on a file.
|
||||||
|
type PollOp struct {
|
||||||
|
// The inode and handle the user wants to poll
|
||||||
|
Inode InodeID
|
||||||
|
Handle HandleID
|
||||||
|
|
||||||
|
// Kh is the "kernel handle". The reason behind it is that it's allocated
|
||||||
|
// by the kernel on file allocation and guaranteed to be unique as opposed
|
||||||
|
// to regular file handles (HandleID) generated by the userland server
|
||||||
|
// (by us). Kh has to be used in NotifyPollWakeupOut replies.
|
||||||
|
Kh uint64
|
||||||
|
|
||||||
|
// Poll flags
|
||||||
|
Flags fusekernel.PollFlags
|
||||||
|
|
||||||
|
// Requested events
|
||||||
|
Events fusekernel.PollEvents
|
||||||
|
|
||||||
|
// Set by the file system: the actual events that have happened
|
||||||
|
// since the last poll
|
||||||
|
Revents fusekernel.PollEvents
|
||||||
|
OpContext OpContext
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify consumers waiting for poll/epoll that events are incoming
|
||||||
|
// for the specified kernel handle. The kernel will send a PollOp request
|
||||||
|
// to get the event mask after receiving this notification
|
||||||
|
type NotifyPollWakeup struct {
|
||||||
|
Kh uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify to invalidate cache for an inode.
|
||||||
|
//
|
||||||
|
// If the filesystem has writeback caching enabled, invalidating an inode
|
||||||
|
// will first trigger a writeback of all dirty pages. The call will block
|
||||||
|
// until all writeback requests have completed and the inode has been
|
||||||
|
// invalidated. It will, however, not wait for completion of pending writeback
|
||||||
|
// requests that have been issued before.
|
||||||
|
type NotifyInvalInode struct {
|
||||||
|
Inode InodeID
|
||||||
|
Offset int64
|
||||||
|
Length int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify to invalidate parent attributes and the dentry matching parent/name
|
||||||
|
//
|
||||||
|
// To avoid a deadlock this request must not be sent in the execution path
|
||||||
|
// of a related filesytem operation or within any code that could hold a lock
|
||||||
|
// that could be needed to execute such an operation. As of kernel 4.18, a
|
||||||
|
// "related operation" is a lookup(), symlink(), mknod(), mkdir(), unlink(),
|
||||||
|
// rename(), link() or create() request for the parent, and a setattr(),
|
||||||
|
// unlink(), rmdir(), rename(), setxattr(), removexattr(), readdir() or
|
||||||
|
// readdirplus() request for the inode itself.
|
||||||
|
//
|
||||||
|
// When called correctly, it will never block.
|
||||||
|
type NotifyInvalEntry struct {
|
||||||
|
Parent InodeID
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
// This request behaves like NotifyInvalEntry with the following additional
|
||||||
|
// effect (at least as of Linux kernel 4.8):
|
||||||
|
//
|
||||||
|
// If the provided child inode matches the inode that is currently associated
|
||||||
|
// with the cached dentry, and if there are any inotify watches registered for
|
||||||
|
// the dentry, then the watchers are informed that the dentry has been deleted.
|
||||||
|
//
|
||||||
|
// To avoid a deadlock this request must not be sent while executing a
|
||||||
|
// related filesytem operation or while holding a lock that could be needed to
|
||||||
|
// execute such an operation.
|
||||||
|
type NotifyDelete struct {
|
||||||
|
Parent InodeID
|
||||||
|
Child InodeID
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store data to the kernel buffers
|
||||||
|
//
|
||||||
|
// Synchronously store data in the kernel buffers belonging to the given inode.
|
||||||
|
// The stored data is marked up-to-date (no read will be performed against it,
|
||||||
|
// unless it's invalidated or evicted from the cache).
|
||||||
|
//
|
||||||
|
// If the stored data overflows the current file size, then the size is extended,
|
||||||
|
// similarly to a write(2) on the filesystem.
|
||||||
|
//
|
||||||
|
// If this request returns an error, then the store wasn't fully completed, but
|
||||||
|
// it may have been partially completed.
|
||||||
|
type NotifyStore struct {
|
||||||
|
Inode InodeID
|
||||||
|
Offset uint64
|
||||||
|
Length uint32
|
||||||
|
Data [][]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve data from the kernel buffers belonging to the given inode
|
||||||
|
//
|
||||||
|
// If successful then the kernel will send a NotifyRetrieveReplyOp as a reply.
|
||||||
|
// Only present pages are returned in the retrieve reply. Retrieving stops when it
|
||||||
|
// finds a non-present page and only data prior to that is returned.
|
||||||
|
//
|
||||||
|
// If this request returns an error, then the retrieve will not be completed and
|
||||||
|
// no reply will be sent.
|
||||||
|
//
|
||||||
|
// This request doesn't change the dirty state of pages in the kernel buffer. For
|
||||||
|
// dirty pages the write() method will be called regardless of having been retrieved
|
||||||
|
// previously.
|
||||||
|
type NotifyRetrieve struct {
|
||||||
|
Inode InodeID
|
||||||
|
Unique uint64
|
||||||
|
Offset uint64
|
||||||
|
Length uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// Matches the size of WriteIn
|
||||||
|
type NotifyRetrieveReplyOp struct {
|
||||||
|
Inode InodeID
|
||||||
|
Unique uint64
|
||||||
|
Offset uint64
|
||||||
|
Length uint32
|
||||||
|
|
||||||
|
OpContext OpContext
|
||||||
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ type Dirent struct {
|
||||||
Type DirentType
|
Type DirentType
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write the supplied directory entry intto the given buffer in the format
|
// Write the supplied directory entry into the given buffer in the format
|
||||||
// expected in fuseops.ReadFileOp.Data, returning the number of bytes written.
|
// expected in fuseops.ReadFileOp.Data, returning the number of bytes written.
|
||||||
// Return zero if the entry would not fit.
|
// Return zero if the entry would not fit.
|
||||||
func WriteDirent(buf []byte, d Dirent) (n int) {
|
func WriteDirent(buf []byte, d Dirent) (n int) {
|
||||||
|
|
|
@ -63,6 +63,9 @@ type FileSystem interface {
|
||||||
ListXattr(context.Context, *fuseops.ListXattrOp) error
|
ListXattr(context.Context, *fuseops.ListXattrOp) error
|
||||||
SetXattr(context.Context, *fuseops.SetXattrOp) error
|
SetXattr(context.Context, *fuseops.SetXattrOp) error
|
||||||
Fallocate(context.Context, *fuseops.FallocateOp) error
|
Fallocate(context.Context, *fuseops.FallocateOp) error
|
||||||
|
Poll(context.Context, *fuseops.PollOp) error
|
||||||
|
|
||||||
|
SetConnection(*fuse.Connection)
|
||||||
|
|
||||||
// Regard all inodes (including the root inode) as having their lookup counts
|
// Regard all inodes (including the root inode) as having their lookup counts
|
||||||
// decremented to zero, and clean up any resources associated with the file
|
// decremented to zero, and clean up any resources associated with the file
|
||||||
|
@ -95,6 +98,8 @@ type fileSystemServer struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *fileSystemServer) ServeOps(c *fuse.Connection) {
|
func (s *fileSystemServer) ServeOps(c *fuse.Connection) {
|
||||||
|
s.fs.SetConnection(c)
|
||||||
|
|
||||||
// When we are done, we clean up by waiting for all in-flight ops then
|
// When we are done, we clean up by waiting for all in-flight ops then
|
||||||
// destroying the file system.
|
// destroying the file system.
|
||||||
defer func() {
|
defer func() {
|
||||||
|
@ -236,6 +241,9 @@ func (s *fileSystemServer) handleOp(
|
||||||
|
|
||||||
case *fuseops.FallocateOp:
|
case *fuseops.FallocateOp:
|
||||||
err = s.fs.Fallocate(ctx, typed)
|
err = s.fs.Fallocate(ctx, typed)
|
||||||
|
|
||||||
|
case *fuseops.PollOp:
|
||||||
|
err = s.fs.Poll(ctx, typed)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Reply(ctx, err)
|
c.Reply(ctx, err)
|
||||||
|
|
|
@ -204,5 +204,14 @@ func (fs *NotImplementedFileSystem) Fallocate(
|
||||||
return fuse.ENOSYS
|
return fuse.ENOSYS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fs *NotImplementedFileSystem) Poll(
|
||||||
|
ctx context.Context,
|
||||||
|
op *fuseops.PollOp) error {
|
||||||
|
return fuse.ENOSYS
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *NotImplementedFileSystem) SetConnection(*fuse.Connection) {
|
||||||
|
}
|
||||||
|
|
||||||
func (fs *NotImplementedFileSystem) Destroy() {
|
func (fs *NotImplementedFileSystem) Destroy() {
|
||||||
}
|
}
|
||||||
|
|
14
go.mod
14
go.mod
|
@ -1,17 +1,19 @@
|
||||||
module github.com/jacobsa/fuse
|
module github.com/jacobsa/fuse
|
||||||
|
|
||||||
go 1.18
|
go 1.19
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e
|
github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e
|
||||||
github.com/jacobsa/oglematchers v0.0.0-20150720000706-141901ea67cd
|
github.com/jacobsa/oglematchers v0.0.0-20150720000706-141901ea67cd
|
||||||
github.com/jacobsa/oglemock v0.0.0-20150831005832-e94d794d06ff // indirect
|
|
||||||
github.com/jacobsa/ogletest v0.0.0-20170503003838-80d50a735a11
|
github.com/jacobsa/ogletest v0.0.0-20170503003838-80d50a735a11
|
||||||
github.com/jacobsa/reqtrace v0.0.0-20150505043853-245c9e0234cb // indirect
|
|
||||||
github.com/jacobsa/syncutil v0.0.0-20180201203307-228ac8e5a6c3
|
github.com/jacobsa/syncutil v0.0.0-20180201203307-228ac8e5a6c3
|
||||||
github.com/jacobsa/timeutil v0.0.0-20170205232429-577e5acbbcf6
|
github.com/jacobsa/timeutil v0.0.0-20170205232429-577e5acbbcf6
|
||||||
github.com/kylelemons/godebug v1.1.0
|
github.com/kylelemons/godebug v1.1.0
|
||||||
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect
|
golang.org/x/net v0.7.0
|
||||||
golang.org/x/net v0.0.0-20220526153639-5463443f8c37
|
golang.org/x/sys v0.5.0
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/jacobsa/oglemock v0.0.0-20150831005832-e94d794d06ff // indirect
|
||||||
|
github.com/jacobsa/reqtrace v0.0.0-20150505043853-245c9e0234cb // indirect
|
||||||
)
|
)
|
||||||
|
|
26
go.sum
26
go.sum
|
@ -14,25 +14,7 @@ github.com/jacobsa/timeutil v0.0.0-20170205232429-577e5acbbcf6 h1:XKHJmHcgU9glxk
|
||||||
github.com/jacobsa/timeutil v0.0.0-20170205232429-577e5acbbcf6/go.mod h1:JEWKD6V8xETMW+DEv+IQVz++f8Cn8O/X0HPeDY3qNis=
|
github.com/jacobsa/timeutil v0.0.0-20170205232429-577e5acbbcf6/go.mod h1:JEWKD6V8xETMW+DEv+IQVz++f8Cn8O/X0HPeDY3qNis=
|
||||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
||||||
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM=
|
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
|
||||||
golang.org/x/net v0.0.0-20220526153639-5463443f8c37 h1:lUkvobShwKsOesNfWWlCS5q7fnbG1MEliIzwu886fn8=
|
|
||||||
golang.org/x/net v0.0.0-20220526153639-5463443f8c37/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So=
|
|
||||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
|
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
|
|
|
@ -346,6 +346,34 @@ var releaseFlagNames = []flagName{
|
||||||
{uint32(ReleaseFlush), "ReleaseFlush"},
|
{uint32(ReleaseFlush), "ReleaseFlush"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Poll flags and events are used in the Poll exchange.
|
||||||
|
type PollFlags uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
// From the kernel source:
|
||||||
|
// Ask for notification if there's someone waiting for it.
|
||||||
|
// The client may ignore the flag and always notify.
|
||||||
|
PollScheduleNotify PollFlags = 1 << 0
|
||||||
|
)
|
||||||
|
|
||||||
|
type PollEvents uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
PollInEvent PollEvents = 0x0001
|
||||||
|
PollPriEvent PollEvents = 0x0002
|
||||||
|
PollOutEvent PollEvents = 0x0004
|
||||||
|
PollErrEvent PollEvents = 0x0008
|
||||||
|
PollHupEvent PollEvents = 0x0010
|
||||||
|
PollNvalEvent PollEvents = 0x0020
|
||||||
|
PollRdNormEvent PollEvents = 0x0040
|
||||||
|
PollRdBandEvent PollEvents = 0x0080
|
||||||
|
PollWrNormEvent PollEvents = 0x0100
|
||||||
|
PollWrBandEvent PollEvents = 0x0200
|
||||||
|
PollMsgEvent PollEvents = 0x0400
|
||||||
|
PollRemoveEvent PollEvents = 0x1000
|
||||||
|
PollRdHupEvent PollEvents = 0x2000
|
||||||
|
)
|
||||||
|
|
||||||
// Opcodes
|
// Opcodes
|
||||||
const (
|
const (
|
||||||
OpLookup = 1
|
OpLookup = 1
|
||||||
|
@ -386,6 +414,7 @@ const (
|
||||||
OpDestroy = 38
|
OpDestroy = 38
|
||||||
OpIoctl = 39 // Linux?
|
OpIoctl = 39 // Linux?
|
||||||
OpPoll = 40 // Linux?
|
OpPoll = 40 // Linux?
|
||||||
|
OpNotifyReply = 41
|
||||||
OpBatchForget = 42
|
OpBatchForget = 42
|
||||||
OpFallocate = 43
|
OpFallocate = 43
|
||||||
|
|
||||||
|
@ -552,6 +581,18 @@ func CreateInSize(p Protocol) uintptr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PollIn struct {
|
||||||
|
Fh uint64
|
||||||
|
Kh uint64
|
||||||
|
Flags uint32
|
||||||
|
Events uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type PollOut struct {
|
||||||
|
Revents uint32
|
||||||
|
padding uint32
|
||||||
|
}
|
||||||
|
|
||||||
type ReleaseIn struct {
|
type ReleaseIn struct {
|
||||||
Fh uint64
|
Fh uint64
|
||||||
Flags uint32
|
Flags uint32
|
||||||
|
@ -787,8 +828,15 @@ const (
|
||||||
NotifyCodePoll int32 = 1
|
NotifyCodePoll int32 = 1
|
||||||
NotifyCodeInvalInode int32 = 2
|
NotifyCodeInvalInode int32 = 2
|
||||||
NotifyCodeInvalEntry int32 = 3
|
NotifyCodeInvalEntry int32 = 3
|
||||||
|
NotifyCodeStore int32 = 4
|
||||||
|
NotifyCodeRetrieve int32 = 5
|
||||||
|
NotifyCodeDelete int32 = 6
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type NotifyPollWakeupOut struct {
|
||||||
|
Kh uint64
|
||||||
|
}
|
||||||
|
|
||||||
type NotifyInvalInodeOut struct {
|
type NotifyInvalInodeOut struct {
|
||||||
Ino uint64
|
Ino uint64
|
||||||
Off int64
|
Off int64
|
||||||
|
@ -800,3 +848,35 @@ type NotifyInvalEntryOut struct {
|
||||||
Namelen uint32
|
Namelen uint32
|
||||||
padding uint32
|
padding uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NotifyDeleteOut struct {
|
||||||
|
Parent uint64
|
||||||
|
Child uint64
|
||||||
|
Namelen uint32
|
||||||
|
padding uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type NotifyStoreOut struct {
|
||||||
|
Nodeid uint64
|
||||||
|
Offset uint64
|
||||||
|
Size uint32
|
||||||
|
padding uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type NotifyRetrieveOut struct {
|
||||||
|
Unique uint64
|
||||||
|
Nodeid uint64
|
||||||
|
Offset uint64
|
||||||
|
Size uint32
|
||||||
|
padding uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// Matches the size of WriteIn
|
||||||
|
type NotifyRetrieveIn struct {
|
||||||
|
dummy1 uint64
|
||||||
|
Offset uint64
|
||||||
|
Size uint32
|
||||||
|
dummy2 uint32
|
||||||
|
dummy3 uint64
|
||||||
|
dummy4 uint64
|
||||||
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ package statfs_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/jacobsa/oglematchers"
|
||||||
"math"
|
"math"
|
||||||
"regexp"
|
"regexp"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
@ -68,7 +69,7 @@ func (t *StatFSTest) Syscall_ZeroValues() {
|
||||||
ExpectEq(0, stat.Bavail)
|
ExpectEq(0, stat.Bavail)
|
||||||
ExpectEq(0, stat.Files)
|
ExpectEq(0, stat.Files)
|
||||||
ExpectEq(0, stat.Ffree)
|
ExpectEq(0, stat.Ffree)
|
||||||
ExpectEq("osxfuse", convertName(stat.Fstypename[:]))
|
ExpectThat(convertName(stat.Fstypename[:]), oglematchers.AnyOf(oglematchers.Equals("osxfuse"), oglematchers.Equals("macfuse")))
|
||||||
ExpectEq(t.canonicalDir, convertName(stat.Mntonname[:]))
|
ExpectEq(t.canonicalDir, convertName(stat.Mntonname[:]))
|
||||||
ExpectEq(fsName, convertName(stat.Mntfromname[:]))
|
ExpectEq(fsName, convertName(stat.Mntfromname[:]))
|
||||||
}
|
}
|
||||||
|
@ -103,7 +104,7 @@ func (t *StatFSTest) Syscall_NonZeroValues() {
|
||||||
ExpectEq(canned.BlocksAvailable, stat.Bavail)
|
ExpectEq(canned.BlocksAvailable, stat.Bavail)
|
||||||
ExpectEq(canned.Inodes, stat.Files)
|
ExpectEq(canned.Inodes, stat.Files)
|
||||||
ExpectEq(canned.InodesFree, stat.Ffree)
|
ExpectEq(canned.InodesFree, stat.Ffree)
|
||||||
ExpectEq("osxfuse", convertName(stat.Fstypename[:]))
|
ExpectThat(convertName(stat.Fstypename[:]), oglematchers.AnyOf(oglematchers.Equals("osxfuse"), oglematchers.Equals("macfuse")))
|
||||||
ExpectEq(t.canonicalDir, convertName(stat.Mntonname[:]))
|
ExpectEq(t.canonicalDir, convertName(stat.Mntonname[:]))
|
||||||
ExpectEq(fsName, convertName(stat.Mntfromname[:]))
|
ExpectEq(fsName, convertName(stat.Mntfromname[:]))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue