Commit 1eca9006 authored by Yufeng Cheng's avatar Yufeng Cheng Committed by Han-Wen Nienhuys

Implement file locking: getlk/setlk/setlkw/flock

Co-authored-by: default avatarPaul Warren <paul.warren@emc.com>
Co-authored-by: default avatarMaria Shaldibina <mshaldibina@pivotal.io>
Co-authored-by: default avatarHan-Wen Nienhuys <hanwen@google.com>
parent 291273cb
......@@ -7,10 +7,13 @@ Haitao Li <lihaitao@gmail.com>
Jakob Unterwurzacher <jakobunt@gmail.com>
James D. Nurmi <james@abneptis.com>
Jeff <leterip@me.com>
Kaoet Ibe <kaoet.ibe@outlook.com>
Logan Hanks <logan@bitcasa.com>
Maria Shaldibina <mshaldibina@pivotal.io>
Nick Cooper <gh@smoogle.org>
Patrick Crosby <pcrosby@gmail.com>
Paul Jolly <paul@myitcv.org.uk>
Paul Warren <paul.warren@emc.com>
Shayan Pooya <shayan@arista.com>
Valient Gough <vgough@pobox.com>
Yongwoo Park <nnnlife@gmail.com>
......@@ -134,7 +134,10 @@ type RawFileSystem interface {
Open(input *OpenIn, out *OpenOut) (status Status)
Read(input *ReadIn, buf []byte) (ReadResult, Status)
Flock(input *FlockIn, flags int) (code Status)
// File locking
GetLk(input *LkIn, out *LkOut) (code Status)
SetLk(input *LkIn) (code Status)
SetLkw(input *LkIn) (code Status)
Release(input *ReleaseIn)
Write(input *WriteIn, data []byte) (written uint32, code Status)
......
......@@ -117,7 +117,15 @@ func (fs *defaultRawFileSystem) Read(input *ReadIn, buf []byte) (ReadResult, Sta
return nil, ENOSYS
}
func (fs *defaultRawFileSystem) Flock(input *FlockIn, flags int) Status {
func (fs *defaultRawFileSystem) GetLk(in *LkIn, out *LkOut) (code Status) {
return ENOSYS
}
func (fs *defaultRawFileSystem) SetLk(in *LkIn) (code Status) {
return ENOSYS
}
func (fs *defaultRawFileSystem) SetLkw(in *LkIn) (code Status) {
return ENOSYS
}
......
......@@ -159,9 +159,19 @@ func (fs *lockingRawFileSystem) Read(input *ReadIn, buf []byte) (ReadResult, Sta
return fs.RawFS.Read(input, buf)
}
func (fs *lockingRawFileSystem) Flock(input *FlockIn, flags int) Status {
func (fs *lockingRawFileSystem) GetLk(in *LkIn, out *LkOut) (code Status) {
defer fs.locked()()
return fs.RawFS.Flock(input, flags)
return fs.RawFS.GetLk(in, out)
}
func (fs *lockingRawFileSystem) SetLk(in *LkIn) (code Status) {
defer fs.locked()()
return fs.RawFS.SetLk(in)
}
func (fs *lockingRawFileSystem) SetLkw(in *LkIn) (code Status) {
defer fs.locked()()
return fs.RawFS.SetLkw(in)
}
func (fs *lockingRawFileSystem) Write(input *WriteIn, data []byte) (written uint32, code Status) {
......
......@@ -103,6 +103,17 @@ type Node interface {
SetXAttr(attr string, data []byte, flags int, context *fuse.Context) fuse.Status
ListXAttr(context *fuse.Context) (attrs []string, code fuse.Status)
// File locking
//
// GetLk returns existing lock information for file.
GetLk(file File, owner uint64, lk *fuse.FileLock, flags uint32, out *fuse.FileLock, context *fuse.Context) (code fuse.Status)
// Sets or clears the lock described by lk on file.
SetLk(file File, owner uint64, lk *fuse.FileLock, flags uint32, context *fuse.Context) (code fuse.Status)
// Sets or clears the lock described by lk. This call blocks until the operation can be completed.
SetLkw(file File, owner uint64, lk *fuse.FileLock, flags uint32, context *fuse.Context) (code fuse.Status)
// Attributes
GetAttr(out *fuse.Attr, file File, context *fuse.Context) (code fuse.Status)
Chmod(file File, perms uint32, context *fuse.Context) (code fuse.Status)
......@@ -131,7 +142,10 @@ type File interface {
Read(dest []byte, off int64) (fuse.ReadResult, fuse.Status)
Write(data []byte, off int64) (written uint32, code fuse.Status)
Flock(flags int) fuse.Status
// File locking
GetLk(owner uint64, lk *fuse.FileLock, flags uint32, out *fuse.FileLock) (code fuse.Status)
SetLk(owner uint64, lk *fuse.FileLock, flags uint32) (code fuse.Status)
SetLkw(owner uint64, lk *fuse.FileLock, flags uint32) (code fuse.Status)
// Flush is called for close() call on a file descriptor. In
// case of duplicated descriptor, it may be called more than
......
......@@ -37,7 +37,18 @@ func (f *defaultFile) Write(data []byte, off int64) (uint32, fuse.Status) {
return 0, fuse.ENOSYS
}
func (f *defaultFile) Flock(flags int) fuse.Status { return fuse.ENOSYS }
func (f *defaultFile) GetLk(owner uint64, lk *fuse.FileLock, flags uint32, out *fuse.FileLock) (code fuse.Status) {
return fuse.ENOSYS
}
func (f *defaultFile) SetLk(owner uint64, lk *fuse.FileLock, flags uint32) (code fuse.Status) {
return fuse.ENOSYS
}
func (f *defaultFile) SetLkw(owner uint64, lk *fuse.FileLock, flags uint32) (code fuse.Status) {
return fuse.ENOSYS
}
func (f *defaultFile) Flush() fuse.Status {
return fuse.OK
}
......
......@@ -137,6 +137,18 @@ func (n *defaultNode) GetAttr(out *fuse.Attr, file File, context *fuse.Context)
return fuse.OK
}
func (n *defaultNode) GetLk(file File, owner uint64, lk *fuse.FileLock, flags uint32, out *fuse.FileLock, context *fuse.Context) (code fuse.Status) {
return fuse.ENOSYS
}
func (n *defaultNode) SetLk(file File, owner uint64, lk *fuse.FileLock, flags uint32, context *fuse.Context) (code fuse.Status) {
return fuse.ENOSYS
}
func (n *defaultNode) SetLkw(file File, owner uint64, lk *fuse.FileLock, flags uint32, context *fuse.Context) (code fuse.Status) {
return fuse.ENOSYS
}
func (n *defaultNode) Chmod(file File, perms uint32, context *fuse.Context) (code fuse.Status) {
return fuse.ENOSYS
}
......
......@@ -167,12 +167,56 @@ func (f *loopbackFile) Fsync(flags int) (code fuse.Status) {
return r
}
func (f *loopbackFile) Flock(flags int) fuse.Status {
f.lock.Lock()
r := fuse.ToStatus(syscall.Flock(int(f.File.Fd()), flags))
f.lock.Unlock()
const (
F_OFD_GETLK = 36
F_OFD_SETLK = 37
F_OFD_SETLKW = 38
)
return r
func (f *loopbackFile) GetLk(owner uint64, lk *fuse.FileLock, flags uint32, out *fuse.FileLock) (code fuse.Status) {
flk := syscall.Flock_t{}
lk.ToFlockT(&flk)
code = fuse.ToStatus(syscall.FcntlFlock(f.File.Fd(), F_OFD_GETLK, &flk))
out.FromFlockT(&flk)
return
}
func (f *loopbackFile) SetLk(owner uint64, lk *fuse.FileLock, flags uint32) (code fuse.Status) {
return f.setLock(owner, lk, flags, false)
}
func (f *loopbackFile) SetLkw(owner uint64, lk *fuse.FileLock, flags uint32) (code fuse.Status) {
return f.setLock(owner, lk, flags, true)
}
func (f *loopbackFile) setLock(owner uint64, lk *fuse.FileLock, flags uint32, blocking bool) (code fuse.Status) {
if (flags & fuse.FUSE_LK_FLOCK) != 0 {
var op int
switch lk.Typ {
case syscall.F_RDLCK:
op = syscall.LOCK_SH
case syscall.F_WRLCK:
op = syscall.LOCK_EX
case syscall.F_UNLCK:
op = syscall.LOCK_UN
default:
return fuse.EINVAL
}
if !blocking {
op |= syscall.LOCK_NB
}
return fuse.ToStatus(syscall.Flock(int(f.File.Fd()), op))
} else {
flk := syscall.Flock_t{}
lk.ToFlockT(&flk)
var op int
if blocking {
op = F_OFD_SETLKW
} else {
op = F_OFD_SETLK
}
return fuse.ToStatus(syscall.FcntlFlock(f.File.Fd(), op, &flk))
}
}
func (f *loopbackFile) Truncate(size uint64) fuse.Status {
......
......@@ -452,15 +452,25 @@ func (c *rawBridge) Read(input *fuse.ReadIn, buf []byte) (fuse.ReadResult, fuse.
return node.Node().Read(f, buf, int64(input.Offset), &input.Context)
}
func (c *rawBridge) Flock(input *fuse.FlockIn, flags int) fuse.Status {
node := c.toInode(input.NodeId)
opened := node.mount.getOpenedFile(input.Fh)
func (c *rawBridge) GetLk(input *fuse.LkIn, out *fuse.LkOut) (code fuse.Status) {
n := c.toInode(input.NodeId)
opened := n.mount.getOpenedFile(input.Fh)
if opened != nil {
return opened.WithFlags.File.Flock(flags)
}
return n.fsInode.GetLk(opened, input.Owner, &input.Lk, input.LkFlags, &out.Lk, &input.Context)
}
func (c *rawBridge) SetLk(input *fuse.LkIn) (code fuse.Status) {
n := c.toInode(input.NodeId)
opened := n.mount.getOpenedFile(input.Fh)
return n.fsInode.SetLk(opened, input.Owner, &input.Lk, input.LkFlags, &input.Context)
}
func (c *rawBridge) SetLkw(input *fuse.LkIn) (code fuse.Status) {
n := c.toInode(input.NodeId)
opened := n.mount.getOpenedFile(input.Fh)
return fuse.EBADF
return n.fsInode.SetLkw(opened, input.Owner, &input.Lk, input.LkFlags, &input.Context)
}
func (c *rawBridge) StatFs(header *fuse.InHeader, out *fuse.StatfsOut) fuse.Status {
......
......@@ -54,10 +54,22 @@ func (f *lockingFile) Flush() fuse.Status {
return f.file.Flush()
}
func (f *lockingFile) Flock(flags int) fuse.Status {
func (f *lockingFile) GetLk(owner uint64, lk *fuse.FileLock, flags uint32, out *fuse.FileLock) (code fuse.Status) {
f.mu.Lock()
defer f.mu.Unlock()
return f.file.Flock(flags)
return f.file.GetLk(owner, lk, flags, out)
}
func (f *lockingFile) SetLk(owner uint64, lk *fuse.FileLock, flags uint32) (code fuse.Status) {
f.mu.Lock()
defer f.mu.Unlock()
return f.file.SetLk(owner, lk, flags)
}
func (f *lockingFile) SetLkw(owner uint64, lk *fuse.FileLock, flags uint32) (code fuse.Status) {
f.mu.Lock()
defer f.mu.Unlock()
return f.file.SetLkw(owner, lk, flags)
}
func (f *lockingFile) Release() {
......
......@@ -83,7 +83,7 @@ func doInit(server *Server, req *request) {
server.reqMu.Lock()
server.kernelSettings = *input
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_AUTO_INVAL_DATA | CAP_READDIRPLUS | CAP_NO_OPEN_SUPPORT | CAP_FLOCK_LOCKS | CAP_POSIX_LOCKS)
if input.Minor >= 13 {
server.setSplice()
......@@ -390,6 +390,18 @@ func doFallocate(server *Server, req *request) {
req.status = server.fileSystem.Fallocate((*FallocateIn)(req.inData))
}
func doGetLk(server *Server, req *request) {
req.status = server.fileSystem.GetLk((*LkIn)(req.inData), (*LkOut)(req.outData()))
}
func doSetLk(server *Server, req *request) {
req.status = server.fileSystem.SetLk((*LkIn)(req.inData))
}
func doSetLkw(server *Server, req *request) {
req.status = server.fileSystem.SetLkw((*LkIn)(req.inData))
}
////////////////////////////////////////////////////////////////
type operationFunc func(*Server, *request)
......@@ -457,6 +469,9 @@ func init() {
_OP_READDIR: unsafe.Sizeof(ReadIn{}),
_OP_RELEASEDIR: unsafe.Sizeof(ReleaseIn{}),
_OP_FSYNCDIR: unsafe.Sizeof(FsyncIn{}),
_OP_GETLK: unsafe.Sizeof(LkIn{}),
_OP_SETLK: unsafe.Sizeof(LkIn{}),
_OP_SETLKW: unsafe.Sizeof(LkIn{}),
_OP_ACCESS: unsafe.Sizeof(AccessIn{}),
_OP_CREATE: unsafe.Sizeof(CreateIn{}),
_OP_INTERRUPT: unsafe.Sizeof(InterruptIn{}),
......@@ -484,6 +499,7 @@ func init() {
_OP_LISTXATTR: unsafe.Sizeof(GetXAttrOut{}),
_OP_INIT: unsafe.Sizeof(InitOut{}),
_OP_OPENDIR: unsafe.Sizeof(OpenOut{}),
_OP_GETLK: unsafe.Sizeof(LkOut{}),
_OP_CREATE: unsafe.Sizeof(CreateOut{}),
_OP_BMAP: unsafe.Sizeof(_BmapOut{}),
_OP_IOCTL: unsafe.Sizeof(_IoctlOut{}),
......@@ -572,6 +588,9 @@ func init() {
_OP_FSYNCDIR: doFsyncDir,
_OP_SETXATTR: doSetXAttr,
_OP_REMOVEXATTR: doRemoveXAttr,
_OP_GETLK: doGetLk,
_OP_SETLK: doSetLk,
_OP_SETLKW: doSetLkw,
_OP_ACCESS: doAccess,
_OP_SYMLINK: doSymlink,
_OP_RENAME: doRename,
......@@ -600,6 +619,7 @@ func init() {
_OP_NOTIFY_DELETE: func(ptr unsafe.Pointer) interface{} { return (*NotifyInvalDeleteOut)(ptr) },
_OP_STATFS: func(ptr unsafe.Pointer) interface{} { return (*StatfsOut)(ptr) },
_OP_SYMLINK: func(ptr unsafe.Pointer) interface{} { return (*EntryOut)(ptr) },
_OP_GETLK: func(ptr unsafe.Pointer) interface{} { return (*LkOut)(ptr) },
} {
operationHandlers[op].DecodeOut = f
}
......@@ -629,6 +649,9 @@ func init() {
_OP_FALLOCATE: func(ptr unsafe.Pointer) interface{} { return (*FallocateIn)(ptr) },
_OP_READDIRPLUS: func(ptr unsafe.Pointer) interface{} { return (*ReadIn)(ptr) },
_OP_RENAME: func(ptr unsafe.Pointer) interface{} { return (*RenameIn)(ptr) },
_OP_GETLK: func(ptr unsafe.Pointer) interface{} { return (*LkIn)(ptr) },
_OP_SETLK: func(ptr unsafe.Pointer) interface{} { return (*LkIn)(ptr) },
_OP_SETLKW: func(ptr unsafe.Pointer) interface{} { return (*LkIn)(ptr) },
} {
operationHandlers[op].DecodeIn = f
}
......
......@@ -752,3 +752,24 @@ func (n *pathInode) Write(file nodefs.File, data []byte, off int64, context *fus
}
return 0, fuse.ENOSYS
}
func (n *pathInode) GetLk(file nodefs.File, owner uint64, lk *fuse.FileLock, flags uint32, out *fuse.FileLock, context *fuse.Context) (code fuse.Status) {
if file != nil {
return file.GetLk(owner, lk, flags, out)
}
return fuse.ENOSYS
}
func (n *pathInode) SetLk(file nodefs.File, owner uint64, lk *fuse.FileLock, flags uint32, context *fuse.Context) (code fuse.Status) {
if file != nil {
return file.SetLk(owner, lk, flags)
}
return fuse.ENOSYS
}
func (n *pathInode) SetLkw(file nodefs.File, owner uint64, lk *fuse.FileLock, flags uint32, context *fuse.Context) (code fuse.Status) {
if file != nil {
return file.SetLkw(owner, lk, flags)
}
return fuse.ENOSYS
}
// Copyright 2018 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build linux
package test
import (
"os"
"os/exec"
"path/filepath"
"sync"
"syscall"
"testing"
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/fuse/nodefs"
"github.com/hanwen/go-fuse/internal/testutil"
)
func TestFlockExclusive(t *testing.T) {
cmd, err := exec.LookPath("flock")
if err != nil {
t.Skip("flock command not found.")
}
tc := NewTestCase(t)
defer tc.Cleanup()
contents := []byte{1, 2, 3}
tc.WriteFile(tc.origFile, []byte(contents), 0700)
f, err := os.OpenFile(tc.mountFile, os.O_WRONLY, 0)
if err != nil {
t.Fatalf("OpenFile(%q): %v", tc.mountFile, err)
}
defer f.Close()
if err = syscall.Flock(int(f.Fd()), syscall.LOCK_EX); err != nil {
t.Errorf("Flock returned: %v", err)
return
}
_, err = runExternalFlock(cmd, tc.mountFile)
if err == nil {
t.Errorf("Expected flock to fail, but it did not")
}
}
func runExternalFlock(flockPath, fname string) ([]byte, error) {
f, err := os.OpenFile(fname, os.O_WRONLY, 0)
if err != nil {
return nil, err
}
defer f.Close()
// in order to test the lock property we must use cmd.ExtraFiles (instead of passing the actual file)
// if we were to pass the file then this flock command would fail to place the lock (returning a
// 'file busy' error) as it is already opened and locked at this point (see above)
cmd := exec.Command(flockPath, "--exclusive", "--nonblock", "3")
cmd.Env = append(cmd.Env, "LC_ALL=C") // in case the user's shell language is different
cmd.ExtraFiles = []*os.File{f}
return cmd.CombinedOutput()
}
type lockingNode struct {
nodefs.Node
mu sync.Mutex
getLkInvoked bool
setLkInvoked bool
setLkwInvoked bool
}
func (n *lockingNode) GetLkInvoked() bool {
n.mu.Lock()
defer n.mu.Unlock()
return n.getLkInvoked
}
func (n *lockingNode) SetLkInvoked() bool {
n.mu.Lock()
defer n.mu.Unlock()
return n.setLkInvoked
}
func (n *lockingNode) SetLkwInvoked() bool {
n.mu.Lock()
defer n.mu.Unlock()
return n.setLkwInvoked
}
func (n *lockingNode) Open(flags uint32, context *fuse.Context) (file nodefs.File, code fuse.Status) {
return nodefs.NewDataFile([]byte("hello world")), fuse.OK
}
func (n *lockingNode) GetLk(file nodefs.File, owner uint64, lk *fuse.FileLock, flags uint32, out *fuse.FileLock, context *fuse.Context) (code fuse.Status) {
n.mu.Lock()
defer n.mu.Unlock()
n.getLkInvoked = true
return fuse.OK
}
func (n *lockingNode) SetLk(file nodefs.File, owner uint64, lk *fuse.FileLock, flags uint32, context *fuse.Context) (code fuse.Status) {
n.mu.Lock()
defer n.mu.Unlock()
n.setLkInvoked = true
return fuse.OK
}
func (n *lockingNode) SetLkw(file nodefs.File, owner uint64, lk *fuse.FileLock, flags uint32, context *fuse.Context) (code fuse.Status) {
n.mu.Lock()
defer n.mu.Unlock()
n.setLkwInvoked = true
return fuse.OK
}
func TestFlockInvoked(t *testing.T) {
flock, err := exec.LookPath("flock")
if err != nil {
t.Skip("flock command not found.")
}
dir := testutil.TempDir()
defer os.RemoveAll(dir)
opts := &nodefs.Options{
Owner: fuse.CurrentOwner(),
Debug: testutil.VerboseTest(),
}
root := nodefs.NewDefaultNode()
s, _, err := nodefs.MountRoot(dir, root, opts)
if err != nil {
t.Fatalf("MountRoot: %v", err)
}
go s.Serve()
if err := s.WaitMount(); err != nil {
t.Fatal("WaitMount", err)
}
defer s.Unmount()
node := &lockingNode{
Node: nodefs.NewDefaultNode(),
}
root.Inode().NewChild("foo", false, node)
realPath := filepath.Join(dir, "foo")
if node.SetLkInvoked() {
t.Fatalf("SetLk is invoked")
}
cmd := exec.Command(flock, "--nonblock", realPath, "echo", "locked")
out, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("flock %v: %v", err, string(out))
}
if !node.SetLkInvoked() {
t.Fatalf("SetLk is not invoked")
}
if node.SetLkwInvoked() {
t.Fatalf("SetLkw is invoked")
}
cmd = exec.Command(flock, realPath, "echo", "locked")
out, err = cmd.CombinedOutput()
if err != nil {
t.Fatalf("flock %v: %v", err, string(out))
}
if !node.SetLkwInvoked() {
t.Fatalf("SetLkw is not invoked")
}
}
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build linux
package test
import (
"bytes"
"os"
"os/exec"
"syscall"
"testing"
)
// See https://github.com/hanwen/go-fuse/issues/170
func disabledTestFlock(t *testing.T) {
cmd, err := exec.LookPath("flock")
if err != nil {
t.Skip("flock command not found.")
}
tc := NewTestCase(t)
defer tc.Cleanup()
contents := []byte{1, 2, 3}
tc.WriteFile(tc.origFile, []byte(contents), 0700)
f, err := os.OpenFile(tc.mountFile, os.O_WRONLY, 0)
if err != nil {
t.Fatalf("OpenFile(%q): %v", tc.mountFile, err)
}
defer f.Close()
if err = syscall.Flock(int(f.Fd()), syscall.LOCK_EX); err != nil {
t.Errorf("Flock returned: %v", err)
return
}
if out, err := runExternalFlock(cmd, tc.mountFile); !bytes.Contains(out, []byte("failed to get lock")) {
t.Errorf("runExternalFlock(%q): %s (%v)", tc.mountFile, out, err)
}
}
func runExternalFlock(flockPath, fname string) ([]byte, error) {
f, err := os.OpenFile(fname, os.O_WRONLY, 0)
if err != nil {
return nil, err
}
defer f.Close()
cmd := exec.Command(flockPath, "--verbose", "--exclusive", "--nonblock", "3")
cmd.Env = append(cmd.Env, "LC_ALL=C") // in case the user's shell language is different
cmd.ExtraFiles = []*os.File{f}
return cmd.CombinedOutput()
}
......@@ -5,6 +5,7 @@
package fuse
import (
"io"
"syscall"
)
......@@ -306,24 +307,24 @@ type GetXAttrOut struct {
Padding uint32
}
type _FileLock struct {
type FileLock struct {
Start uint64
End uint64
Typ uint32
Pid uint32
}
type _LkIn struct {
type LkIn struct {
InHeader
Fh uint64
Owner uint64
Lk _FileLock
Lk FileLock
LkFlags uint32
Padding uint32
}
type _LkOut struct {
Lk _FileLock
type LkOut struct {
Lk FileLock
}
// For AccessIn.Mask.
......@@ -467,7 +468,26 @@ type FallocateIn struct {
Padding uint32
}
type FlockIn struct {
InHeader
Fh uint64
func (lk *FileLock) ToFlockT(flockT *syscall.Flock_t) {
flockT.Start = int64(lk.Start)
if lk.End == (1<<63)-1 {
flockT.Len = 0
} else {
flockT.Len = int64(lk.End - lk.Start + 1)
}
flockT.Whence = int16(io.SeekStart)
flockT.Type = int16(lk.Typ)
}
func (lk *FileLock) FromFlockT(flockT *syscall.Flock_t) {
lk.Typ = uint32(flockT.Type)
if flockT.Type != syscall.F_UNLCK {
lk.Start = uint64(flockT.Start)
if flockT.Len == 0 {
lk.End = (1 << 63) - 1
} else {
lk.End = uint64(flockT.Start + flockT.Len - 1)
}
}
lk.Pid = uint32(flockT.Pid)
}
......@@ -244,11 +244,29 @@ func (fs *wrappingFS) Read(input *ReadIn, buf []byte) (ReadResult, Status) {
return nil, ENOSYS
}
func (fs *wrappingFS) Flock(input *FlockIn, flags int) Status {
func (fs *wrappingFS) GetLk(in *LkIn, out *LkOut) (code Status) {
if s, ok := fs.fs.(interface {
Flock(input *FlockIn, flags int) Status
GetLk(in *LkIn, out *LkOut) (code Status)
}); ok {
return s.Flock(input, flags)
return s.GetLk(in, out)
}
return ENOSYS
}
func (fs *wrappingFS) SetLk(in *LkIn) (code Status) {
if s, ok := fs.fs.(interface {
SetLk(in *LkIn) (code Status)
}); ok {
return s.SetLk(in)
}
return ENOSYS
}
func (fs *wrappingFS) SetLkw(in *LkIn) (code Status) {
if s, ok := fs.fs.(interface {
SetLkw(in *LkIn) (code Status)
}); ok {
return s.SetLkw(in)
}
return ENOSYS
}
......
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