Commit 8393ebf1 authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

Add fuse.Options.EnableLocks option.

This ensure VFS locking continues working, ensuring backward compatibility.
parent 32297eb3
...@@ -64,6 +64,7 @@ type MountOptions struct { ...@@ -64,6 +64,7 @@ type MountOptions struct {
// Values shown in "df -T" and friends // Values shown in "df -T" and friends
// First column, "Filesystem" // First column, "Filesystem"
FsName string FsName string
// Second column, "Type", will be shown as "fuse." + Name // Second column, "Type", will be shown as "fuse." + Name
Name string Name string
...@@ -76,6 +77,10 @@ type MountOptions struct { ...@@ -76,6 +77,10 @@ type MountOptions struct {
// If set, print debugging information. // If set, print debugging information.
Debug bool Debug bool
// If set, ask kernel to forward file locks to FUSE. If using,
// you must implement the GetLk/SetLk/SetLkw methods.
EnableLocks bool
} }
// RawFileSystem is an interface close to the FUSE wire protocol. // RawFileSystem is an interface close to the FUSE wire protocol.
......
...@@ -8,7 +8,8 @@ import ( ...@@ -8,7 +8,8 @@ import (
"github.com/hanwen/go-fuse/fuse" "github.com/hanwen/go-fuse/fuse"
) )
// Mounts a filesystem with the given root node on the given directory // Mounts a filesystem with the given root node on the given directory.
// Convenience wrapper around fuse.NewServer
func MountRoot(mountpoint string, root Node, opts *Options) (*fuse.Server, *FileSystemConnector, error) { func MountRoot(mountpoint string, root Node, opts *Options) (*fuse.Server, *FileSystemConnector, error) {
conn := NewFileSystemConnector(root, opts) conn := NewFileSystemConnector(root, opts)
......
...@@ -83,7 +83,11 @@ func doInit(server *Server, req *request) { ...@@ -83,7 +83,11 @@ func doInit(server *Server, req *request) {
server.reqMu.Lock() server.reqMu.Lock()
server.kernelSettings = *input server.kernelSettings = *input
server.kernelSettings.Flags = input.Flags & (CAP_ASYNC_READ | CAP_BIG_WRITES | CAP_FILE_OPS | server.kernelSettings.Flags = input.Flags & (CAP_ASYNC_READ | CAP_BIG_WRITES | CAP_FILE_OPS |
CAP_AUTO_INVAL_DATA | CAP_READDIRPLUS | CAP_NO_OPEN_SUPPORT | CAP_FLOCK_LOCKS | CAP_POSIX_LOCKS) CAP_AUTO_INVAL_DATA | CAP_READDIRPLUS | CAP_NO_OPEN_SUPPORT)
if server.opts.EnableLocks {
server.kernelSettings.Flags |= CAP_FLOCK_LOCKS | CAP_POSIX_LOCKS
}
if input.Minor >= 13 { if input.Minor >= 13 {
server.setSplice() server.setSplice()
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
package test package test
import ( import (
"io/ioutil"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
...@@ -130,10 +131,15 @@ func TestFlockInvoked(t *testing.T) { ...@@ -130,10 +131,15 @@ func TestFlockInvoked(t *testing.T) {
} }
root := nodefs.NewDefaultNode() root := nodefs.NewDefaultNode()
s, _, err := nodefs.MountRoot(dir, root, opts) conn := nodefs.NewFileSystemConnector(root, opts)
mountOpts := fuse.MountOptions{
EnableLocks: true
}
s, err := fuse.NewServer(conn.RawFS(), dir, &mountOpts)
if err != nil { if err != nil {
t.Fatalf("MountRoot: %v", err) t.Fatal("NewServer", err)
} }
go s.Serve() go s.Serve()
if err := s.WaitMount(); err != nil { if err := s.WaitMount(); err != nil {
t.Fatal("WaitMount", err) t.Fatal("WaitMount", err)
...@@ -150,6 +156,7 @@ func TestFlockInvoked(t *testing.T) { ...@@ -150,6 +156,7 @@ func TestFlockInvoked(t *testing.T) {
if node.SetLkInvoked() { if node.SetLkInvoked() {
t.Fatalf("SetLk is invoked") t.Fatalf("SetLk is invoked")
} }
cmd := exec.Command(flock, "--nonblock", realPath, "echo", "locked") cmd := exec.Command(flock, "--nonblock", realPath, "echo", "locked")
out, err := cmd.CombinedOutput() out, err := cmd.CombinedOutput()
if err != nil { if err != nil {
...@@ -171,3 +178,58 @@ func TestFlockInvoked(t *testing.T) { ...@@ -171,3 +178,58 @@ func TestFlockInvoked(t *testing.T) {
t.Fatalf("SetLkw is not invoked") t.Fatalf("SetLkw is not invoked")
} }
} }
// Test that file system that don't implement locking are still
// handled in the VFS layer.
func TestNoLockSupport(t *testing.T) {
flock, err := exec.LookPath("flock")
if err != nil {
t.Skip("flock command not found.")
}
tmp, err := ioutil.TempDir("", "TestNoLockSupport")
if err != nil {
t.Fatal(err)
}
mnt, err := ioutil.TempDir("", "TestNoLockSupport")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmp)
defer os.RemoveAll(mnt)
opts := &nodefs.Options{
Owner: fuse.CurrentOwner(),
Debug: testutil.VerboseTest(),
}
root := nodefs.NewMemNodeFSRoot(tmp)
lock := fuse.FileLock{}
outLock := fuse.FileLock{}
ctx := fuse.Context{}
if status := root.GetLk(nil, uint64(1), &lock, uint32(0x0), &outLock, &ctx); status != fuse.ENOSYS {
t.Fatalf("MemNodeFs should not implement locking")
}
s, _, err := nodefs.MountRoot(mnt, root, opts)
if err != nil {
t.Fatalf("MountRoot: %v", err)
}
go s.Serve()
if err := s.WaitMount(); err != nil {
t.Fatalf("WaitMount: %v", err)
}
defer s.Unmount()
fn := mnt + "/file.txt"
if err := ioutil.WriteFile(fn, []byte("content"), 0644); err != nil {
t.Fatalf("WriteFile: %v", err)
}
cmd := exec.Command(flock, "--nonblock", fn, "echo", "locked")
out, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("flock %v: %v", err, string(out))
}
}
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