Pass OpenFlags for OpenFileOp followups (#129)

notifications
Mei Gui 2022-07-26 00:34:00 -07:00 committed by GitHub
parent 9cc4ff0bc9
commit 226fec2ce9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 63 additions and 19 deletions

View File

@ -299,11 +299,10 @@ func convertInMessage(
if in == nil { if in == nil {
return nil, errors.New("Corrupt OpOpen") return nil, errors.New("Corrupt OpOpen")
} }
openFlags := fusekernel.OpenFlags(in.Flags)
o = &fuseops.OpenFileOp{ o = &fuseops.OpenFileOp{
Inode: fuseops.InodeID(inMsg.Header().Nodeid), Inode: fuseops.InodeID(inMsg.Header().Nodeid),
OpenFlags: &openFlags, OpenFlags: fusekernel.OpenFlags(in.Flags),
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid}, OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
} }

View File

@ -648,7 +648,7 @@ type OpenFileOp struct {
// advance, for example, because contents are generated on the fly. // advance, for example, because contents are generated on the fly.
UseDirectIO bool UseDirectIO bool
OpenFlags *fusekernel.OpenFlags OpenFlags fusekernel.OpenFlags
OpContext OpContext OpContext OpContext
} }

View File

@ -33,6 +33,10 @@ type inode struct {
// Mutable state // Mutable state
///////////////////////// /////////////////////////
// Name of the inode, only contains relative path.
// For example, if the full path for an inode is /foo/bar/f1, its name is f1.
name string
// The current attributes of this inode. // The current attributes of this inode.
// //
// INVARIANT: attrs.Mode &^ (os.ModePerm|os.ModeDir|os.ModeSymlink) == 0 // INVARIANT: attrs.Mode &^ (os.ModePerm|os.ModeDir|os.ModeSymlink) == 0
@ -73,7 +77,7 @@ type inode struct {
// Create a new inode with the supplied attributes, which need not contain // Create a new inode with the supplied attributes, which need not contain
// time-related information (the inode object will take care of that). // time-related information (the inode object will take care of that).
func newInode(attrs fuseops.InodeAttributes) *inode { func newInode(attrs fuseops.InodeAttributes, name string) *inode {
// Update time info. // Update time info.
now := time.Now() now := time.Now()
attrs.Mtime = now attrs.Mtime = now
@ -81,6 +85,7 @@ func newInode(attrs fuseops.InodeAttributes) *inode {
// Create the object. // Create the object.
return &inode{ return &inode{
name: name,
attrs: attrs, attrs: attrs,
xattrs: make(map[string][]byte), xattrs: make(map[string][]byte),
} }

View File

@ -16,6 +16,7 @@ package memfs
import ( import (
"context" "context"
"encoding/binary"
"fmt" "fmt"
"io" "io"
"os" "os"
@ -29,6 +30,11 @@ import (
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )
const (
FileOpenFlagsXattrName = "fileOpenFlagsXattr"
CheckFileOpenFlagsFileName = "checkFileOpenFlags"
)
type memFS struct { type memFS struct {
fuseutil.NotImplementedFileSystem fuseutil.NotImplementedFileSystem
@ -85,7 +91,7 @@ func NewMemFS(
Gid: gid, Gid: gid,
} }
fs.inodes[fuseops.RootInodeID] = newInode(rootAttrs) fs.inodes[fuseops.RootInodeID] = newInode(rootAttrs, "")
// Set up invariant checking. // Set up invariant checking.
fs.mu = syncutil.NewInvariantMutex(fs.checkInvariants) fs.mu = syncutil.NewInvariantMutex(fs.checkInvariants)
@ -157,9 +163,9 @@ func (fs *memFS) getInodeOrDie(id fuseops.InodeID) *inode {
// //
// LOCKS_REQUIRED(fs.mu) // LOCKS_REQUIRED(fs.mu)
func (fs *memFS) allocateInode( func (fs *memFS) allocateInode(
attrs fuseops.InodeAttributes) (id fuseops.InodeID, inode *inode) { attrs fuseops.InodeAttributes, name string) (id fuseops.InodeID, inode *inode) {
// Create the inode. // Create the inode.
inode = newInode(attrs) inode = newInode(attrs, name)
// Re-use a free ID if possible. Otherwise mint a new one. // Re-use a free ID if possible. Otherwise mint a new one.
numFree := len(fs.freeInodes) numFree := len(fs.freeInodes)
@ -310,7 +316,7 @@ func (fs *memFS) MkDir(
} }
// Allocate a child. // Allocate a child.
childID, child := fs.allocateInode(childAttrs) childID, child := fs.allocateInode(childAttrs, op.Name)
// Add an entry in the parent. // Add an entry in the parent.
parent.AddChild(childID, op.Name, fuseutil.DT_Directory) parent.AddChild(childID, op.Name, fuseutil.DT_Directory)
@ -371,7 +377,7 @@ func (fs *memFS) createFile(
} }
// Allocate a child. // Allocate a child.
childID, child := fs.allocateInode(childAttrs) childID, child := fs.allocateInode(childAttrs, name)
// Add an entry in the parent. // Add an entry in the parent.
parent.AddChild(childID, name, fuseutil.DT_File) parent.AddChild(childID, name, fuseutil.DT_File)
@ -438,7 +444,7 @@ func (fs *memFS) CreateSymlink(
} }
// Allocate a child. // Allocate a child.
childID, child := fs.allocateInode(childAttrs) childID, child := fs.allocateInode(childAttrs, op.Name)
// Set up its target. // Set up its target.
child.target = op.Target child.target = op.Target
@ -661,9 +667,6 @@ func (fs *memFS) OpenFile(
// OpenFileOp should have a valid pid in context. // OpenFileOp should have a valid pid in context.
return fuse.EINVAL return fuse.EINVAL
} }
if op.OpenFlags == nil {
return fuse.EINVAL
}
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
@ -677,6 +680,21 @@ func (fs *memFS) OpenFile(
panic("Found non-file.") panic("Found non-file.")
} }
if inode.name == CheckFileOpenFlagsFileName {
// For testing purpose only.
// Set attribute (name=fileOpenFlagsXattr, value=OpenFlags) to test whether
// we set OpenFlags correctly. The value is checked in test with getXattr.
value := make([]byte, 4)
binary.LittleEndian.PutUint32(value, uint32(op.OpenFlags))
err := fs.setXattrHelper(inode, &fuseops.SetXattrOp{
Name: FileOpenFlagsXattrName,
Value: value,
})
if err != nil {
panic("unable to set fileOpenFlagsXattr")
}
}
return nil return nil
} }
@ -832,6 +850,11 @@ func (fs *memFS) SetXattr(ctx context.Context,
defer fs.mu.Unlock() defer fs.mu.Unlock()
inode := fs.getInodeOrDie(op.Inode) inode := fs.getInodeOrDie(op.Inode)
return fs.setXattrHelper(inode, op)
}
// Required to hold fs.mu
func (fs *memFS) setXattrHelper(inode *inode, op *fuseops.SetXattrOp) error {
_, ok := inode.xattrs[op.Name] _, ok := inode.xattrs[op.Name]
switch op.Flags { switch op.Flags {

View File

@ -16,6 +16,7 @@ package memfs_test
import ( import (
"bytes" "bytes"
"encoding/binary"
"io" "io"
"io/ioutil" "io/ioutil"
"os" "os"
@ -31,6 +32,7 @@ import (
fallocate "github.com/detailyang/go-fallocate" fallocate "github.com/detailyang/go-fallocate"
"github.com/jacobsa/fuse" "github.com/jacobsa/fuse"
"github.com/jacobsa/fuse/fusetesting" "github.com/jacobsa/fuse/fusetesting"
"github.com/jacobsa/fuse/internal/fusekernel"
"github.com/jacobsa/fuse/samples" "github.com/jacobsa/fuse/samples"
"github.com/jacobsa/fuse/samples/memfs" "github.com/jacobsa/fuse/samples/memfs"
. "github.com/jacobsa/oglematchers" . "github.com/jacobsa/oglematchers"
@ -88,6 +90,15 @@ func applyUmask(m os.FileMode) os.FileMode {
return m &^ os.FileMode(umask) return m &^ os.FileMode(umask)
} }
func (t *MemFSTest) checkOpenFlagsXattr(
fileName string, expectedOpenFlags fusekernel.OpenFlags) {
dest := make([]byte, 4)
_, err := unix.Getxattr(fileName, memfs.FileOpenFlagsXattrName, dest)
AssertEq(nil, err)
openFlags := binary.LittleEndian.Uint32(dest)
AssertEq(openFlags, uint32(expectedOpenFlags))
}
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
// Boilerplate // Boilerplate
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
@ -292,7 +303,7 @@ func (t *MemFSTest) CreateNewFile_InRoot() {
var stat *syscall.Stat_t var stat *syscall.Stat_t
// Write a file. // Write a file.
fileName := path.Join(t.Dir, "foo") fileName := path.Join(t.Dir, memfs.CheckFileOpenFlagsFileName)
const contents = "Hello\x00world" const contents = "Hello\x00world"
createTime := time.Now() createTime := time.Now()
@ -304,7 +315,7 @@ func (t *MemFSTest) CreateNewFile_InRoot() {
stat = fi.Sys().(*syscall.Stat_t) stat = fi.Sys().(*syscall.Stat_t)
AssertEq(nil, err) AssertEq(nil, err)
ExpectEq("foo", fi.Name()) ExpectEq(memfs.CheckFileOpenFlagsFileName, fi.Name())
ExpectEq(len(contents), fi.Size()) ExpectEq(len(contents), fi.Size())
ExpectEq(applyUmask(0400), fi.Mode()) ExpectEq(applyUmask(0400), fi.Mode())
ExpectThat(fi, fusetesting.MtimeIsWithin(createTime, timeSlop)) ExpectThat(fi, fusetesting.MtimeIsWithin(createTime, timeSlop))
@ -321,6 +332,7 @@ func (t *MemFSTest) CreateNewFile_InRoot() {
slice, err := ioutil.ReadFile(fileName) slice, err := ioutil.ReadFile(fileName)
AssertEq(nil, err) AssertEq(nil, err)
ExpectEq(contents, string(slice)) ExpectEq(contents, string(slice))
t.checkOpenFlagsXattr(fileName, fusekernel.OpenReadOnly)
} }
func (t *MemFSTest) CreateNewFile_InSubDir() { func (t *MemFSTest) CreateNewFile_InSubDir() {
@ -372,7 +384,7 @@ func (t *MemFSTest) ModifyExistingFile_InRoot() {
var stat *syscall.Stat_t var stat *syscall.Stat_t
// Write a file. // Write a file.
fileName := path.Join(t.Dir, "foo") fileName := path.Join(t.Dir, memfs.CheckFileOpenFlagsFileName)
createTime := time.Now() createTime := time.Now()
err = ioutil.WriteFile(fileName, []byte("Hello, world!"), 0600) err = ioutil.WriteFile(fileName, []byte("Hello, world!"), 0600)
@ -382,6 +394,7 @@ func (t *MemFSTest) ModifyExistingFile_InRoot() {
f, err := os.OpenFile(fileName, os.O_WRONLY, 0400) f, err := os.OpenFile(fileName, os.O_WRONLY, 0400)
t.ToClose = append(t.ToClose, f) t.ToClose = append(t.ToClose, f)
AssertEq(nil, err) AssertEq(nil, err)
t.checkOpenFlagsXattr(fileName, fusekernel.OpenWriteOnly)
modifyTime := time.Now() modifyTime := time.Now()
n, err = f.WriteAt([]byte("H"), 0) n, err = f.WriteAt([]byte("H"), 0)
@ -393,7 +406,7 @@ func (t *MemFSTest) ModifyExistingFile_InRoot() {
stat = fi.Sys().(*syscall.Stat_t) stat = fi.Sys().(*syscall.Stat_t)
AssertEq(nil, err) AssertEq(nil, err)
ExpectEq("foo", fi.Name()) ExpectEq(memfs.CheckFileOpenFlagsFileName, fi.Name())
ExpectEq(len("Hello, world!"), fi.Size()) ExpectEq(len("Hello, world!"), fi.Size())
ExpectEq(applyUmask(0600), fi.Mode()) ExpectEq(applyUmask(0600), fi.Mode())
ExpectThat(fi, fusetesting.MtimeIsWithin(modifyTime, timeSlop)) ExpectThat(fi, fusetesting.MtimeIsWithin(modifyTime, timeSlop))
@ -410,6 +423,7 @@ func (t *MemFSTest) ModifyExistingFile_InRoot() {
slice, err := ioutil.ReadFile(fileName) slice, err := ioutil.ReadFile(fileName)
AssertEq(nil, err) AssertEq(nil, err)
ExpectEq("Hello, world!", string(slice)) ExpectEq("Hello, world!", string(slice))
t.checkOpenFlagsXattr(fileName, fusekernel.OpenReadOnly)
} }
func (t *MemFSTest) ModifyExistingFile_InSubDir() { func (t *MemFSTest) ModifyExistingFile_InSubDir() {
@ -832,7 +846,7 @@ func (t *MemFSTest) AppendMode() {
buf := make([]byte, 1024) buf := make([]byte, 1024)
// Create a file with some contents. // Create a file with some contents.
fileName := path.Join(t.Dir, "foo") fileName := path.Join(t.Dir, memfs.CheckFileOpenFlagsFileName)
err = ioutil.WriteFile(fileName, []byte("Jello, "), 0600) err = ioutil.WriteFile(fileName, []byte("Jello, "), 0600)
AssertEq(nil, err) AssertEq(nil, err)
@ -840,6 +854,7 @@ func (t *MemFSTest) AppendMode() {
f, err := os.OpenFile(fileName, os.O_RDWR|os.O_APPEND, 0600) f, err := os.OpenFile(fileName, os.O_RDWR|os.O_APPEND, 0600)
t.ToClose = append(t.ToClose, f) t.ToClose = append(t.ToClose, f)
AssertEq(nil, err) AssertEq(nil, err)
t.checkOpenFlagsXattr(fileName, fusekernel.OpenReadWrite)
// Seek to somewhere silly and then write. // Seek to somewhere silly and then write.
off, err = f.Seek(2, 0) off, err = f.Seek(2, 0)
@ -907,7 +922,7 @@ func (t *MemFSTest) ReadsPastEndOfFile() {
func (t *MemFSTest) Truncate_Smaller() { func (t *MemFSTest) Truncate_Smaller() {
var err error var err error
fileName := path.Join(t.Dir, "foo") fileName := path.Join(t.Dir, memfs.CheckFileOpenFlagsFileName)
// Create a file. // Create a file.
err = ioutil.WriteFile(fileName, []byte("taco"), 0600) err = ioutil.WriteFile(fileName, []byte("taco"), 0600)
@ -917,6 +932,7 @@ func (t *MemFSTest) Truncate_Smaller() {
f, err := os.OpenFile(fileName, os.O_RDWR, 0) f, err := os.OpenFile(fileName, os.O_RDWR, 0)
t.ToClose = append(t.ToClose, f) t.ToClose = append(t.ToClose, f)
AssertEq(nil, err) AssertEq(nil, err)
t.checkOpenFlagsXattr(fileName, fusekernel.OpenReadWrite)
// Truncate it. // Truncate it.
err = f.Truncate(2) err = f.Truncate(2)
@ -931,6 +947,7 @@ func (t *MemFSTest) Truncate_Smaller() {
contents, err := ioutil.ReadFile(fileName) contents, err := ioutil.ReadFile(fileName)
AssertEq(nil, err) AssertEq(nil, err)
ExpectEq("ta", string(contents)) ExpectEq("ta", string(contents))
t.checkOpenFlagsXattr(fileName, fusekernel.OpenReadOnly)
} }
func (t *MemFSTest) Truncate_SameSize() { func (t *MemFSTest) Truncate_SameSize() {