mirror of https://github.com/ceph/go-ceph
cephfs: add ceph_flock() function
Added ceph_flock() function which applies or removes an advisory lock on an open file. Fixes: https://github.com/ceph/go-ceph/issues/248 Signed-off-by: Mudit Agarwal muagarwa@redhat.com
This commit is contained in:
parent
1d30b636ff
commit
092c0b7832
|
@ -255,3 +255,41 @@ func (f *File) Fallocate(mode FallocFlags, offset, length int64) error {
|
||||||
ret := C.ceph_fallocate(f.mount.mount, f.fd, C.int(mode), C.int64_t(offset), C.int64_t(length))
|
ret := C.ceph_fallocate(f.mount.mount, f.fd, C.int(mode), C.int64_t(offset), C.int64_t(length))
|
||||||
return getError(ret)
|
return getError(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LockOp determines operations/type of locks which can be applied on a file.
|
||||||
|
type LockOp int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// LockSH places a shared lock.
|
||||||
|
// More than one process may hold a shared lock for a given file at a given time.
|
||||||
|
LockSH = LockOp(C.LOCK_SH)
|
||||||
|
// LockEX places an exclusive lock.
|
||||||
|
// Only one process may hold an exclusive lock for a given file at a given time.
|
||||||
|
LockEX = LockOp(C.LOCK_EX)
|
||||||
|
// LockUN removes and existing lock held by this process.
|
||||||
|
LockUN = LockOp(C.LOCK_UN)
|
||||||
|
// LockNB can be ORed with any of the above to make a nonblocking call.
|
||||||
|
LockNB = LockOp(C.LOCK_NB)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Flock applies or removes an advisory lock on an open file.
|
||||||
|
// Param owner is the user-supplied identifier for the owner of the
|
||||||
|
// lock, must be an arbitrary integer.
|
||||||
|
//
|
||||||
|
// Implements:
|
||||||
|
// int ceph_flock(struct ceph_mount_info *cmount, int fd, int operation, uint64_t owner);
|
||||||
|
func (f *File) Flock(operation LockOp, owner uint64) error {
|
||||||
|
if err := f.validate(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate the operation values before passing it on.
|
||||||
|
switch operation &^ LockNB {
|
||||||
|
case LockSH, LockEX, LockUN:
|
||||||
|
default:
|
||||||
|
return errInvalid
|
||||||
|
}
|
||||||
|
|
||||||
|
ret := C.ceph_flock(f.mount.mount, f.fd, C.int(operation), C.uint64_t(owner))
|
||||||
|
return getError(ret)
|
||||||
|
}
|
||||||
|
|
|
@ -615,3 +615,99 @@ func TestFallocate(t *testing.T) {
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFlock(t *testing.T) {
|
||||||
|
mount := fsConnect(t)
|
||||||
|
defer fsDisconnect(t, mount)
|
||||||
|
|
||||||
|
t.Run("validate", func(t *testing.T) {
|
||||||
|
f := &File{}
|
||||||
|
err := f.Flock(LockSH, 1010)
|
||||||
|
assert.Error(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("validateOperation", func(t *testing.T) {
|
||||||
|
fname := "Flockfile.txt"
|
||||||
|
f, err := mount.Open(fname, os.O_RDWR|os.O_CREATE, 0666)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, f)
|
||||||
|
defer func() {
|
||||||
|
assert.NoError(t, f.Close())
|
||||||
|
assert.NoError(t, mount.Unlink(fname))
|
||||||
|
}()
|
||||||
|
err = f.Flock(LockSH|LockEX, 1010)
|
||||||
|
assert.Error(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("basicLocking", func(t *testing.T) {
|
||||||
|
const (
|
||||||
|
anna = 42
|
||||||
|
bob = 43
|
||||||
|
chris = 44
|
||||||
|
)
|
||||||
|
fname1 := "Flockfile1.txt"
|
||||||
|
f1, err := mount.Open(fname1, os.O_RDWR|os.O_CREATE, 0666)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, f1)
|
||||||
|
defer func() {
|
||||||
|
assert.NoError(t, f1.Close())
|
||||||
|
assert.NoError(t, mount.Unlink(fname1))
|
||||||
|
}()
|
||||||
|
// Lock exclusively twice.
|
||||||
|
t.Run("exclusiveTwiceBlock", func(t *testing.T) {
|
||||||
|
err := f1.Flock(LockEX, anna)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
defer func() {
|
||||||
|
assert.NoError(t, f1.Flock(LockUN, anna))
|
||||||
|
}()
|
||||||
|
err = f1.Flock(LockEX|LockNB, bob)
|
||||||
|
assert.Error(t, err)
|
||||||
|
})
|
||||||
|
t.Run("exclusiveTwiceNonBlock", func(t *testing.T) {
|
||||||
|
err := f1.Flock(LockEX|LockNB, anna)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
defer func() {
|
||||||
|
assert.NoError(t, f1.Flock(LockUN, anna))
|
||||||
|
}()
|
||||||
|
err = f1.Flock(LockEX|LockNB, bob)
|
||||||
|
assert.Error(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Lock shared.
|
||||||
|
t.Run("sharedLock", func(t *testing.T) {
|
||||||
|
err := f1.Flock(LockSH, anna)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
err = f1.Flock(LockSH, bob)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
defer func() {
|
||||||
|
assert.NoError(t, f1.Flock(LockUN, anna))
|
||||||
|
assert.NoError(t, f1.Flock(LockUN, bob))
|
||||||
|
}()
|
||||||
|
// Now try to take exclusive lock.
|
||||||
|
err = f1.Flock(LockEX|LockNB, chris)
|
||||||
|
assert.Error(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Lock shared with upgrade to exclusive.
|
||||||
|
t.Run("sharedLockUpExclusive", func(t *testing.T) {
|
||||||
|
err := f1.Flock(LockSH, bob)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
defer func() {
|
||||||
|
assert.NoError(t, f1.Flock(LockUN, bob))
|
||||||
|
}()
|
||||||
|
err = f1.Flock(LockEX, bob)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Lock exclusive with downgrade to shared.
|
||||||
|
t.Run("exclusiveLockDownShared", func(t *testing.T) {
|
||||||
|
err := f1.Flock(LockEX, bob)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
defer func() {
|
||||||
|
assert.NoError(t, f1.Flock(LockUN, bob))
|
||||||
|
}()
|
||||||
|
err = f1.Flock(LockSH, bob)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue