fusefrontend: xattr: fix hang on FIFOs
An Open() a fifo blocks until it is opened for writing. This meant that xattr operations on FIFOs would block. Pass O_NONBLOCK to fix that, and add a test.
This commit is contained in:
parent
1d5500c3db
commit
60e7a0ca9f
@ -35,11 +35,12 @@ func procFd(fd int) string {
|
|||||||
|
|
||||||
// getFileFd calls fs.Open() on relative plaintext path "relPath" and returns
|
// getFileFd calls fs.Open() on relative plaintext path "relPath" and returns
|
||||||
// the resulting fusefrontend.*File along with the underlying fd. The caller
|
// the resulting fusefrontend.*File along with the underlying fd. The caller
|
||||||
// MUST call file.Release() when done with the file.
|
// MUST call file.Release() when done with the file. The O_NONBLOCK flag is
|
||||||
|
// used to not block on FIFOs.
|
||||||
//
|
//
|
||||||
// Used by xattrGet() and friends.
|
// Used by xattrGet() and friends.
|
||||||
func (fs *FS) getFileFd(relPath string, context *fuse.Context) (*File, int, fuse.Status) {
|
func (fs *FS) getFileFd(relPath string, context *fuse.Context) (*File, int, fuse.Status) {
|
||||||
fuseFile, status := fs.Open(relPath, syscall.O_RDONLY, context)
|
fuseFile, status := fs.Open(relPath, syscall.O_RDONLY|syscall.O_NONBLOCK, context)
|
||||||
if !status.Ok() {
|
if !status.Ok() {
|
||||||
return nil, -1, status
|
return nil, -1, status
|
||||||
}
|
}
|
||||||
|
@ -49,37 +49,75 @@ func TestMain(m *testing.M) {
|
|||||||
os.Exit(r)
|
os.Exit(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestXattrSetGetRm(t *testing.T) {
|
func setGetRmList(fn string) error {
|
||||||
attr := "user.foo"
|
// List
|
||||||
fn := test_helpers.DefaultPlainDir + "/TestXattrSetGetRm"
|
list, err := xattr.LList(fn)
|
||||||
err := ioutil.WriteFile(fn, nil, 0700)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("creating empty file failed: %v", err)
|
return err
|
||||||
}
|
}
|
||||||
|
if len(list) > 0 {
|
||||||
|
return fmt.Errorf("Should have gotten empty result, got %v", list)
|
||||||
|
}
|
||||||
|
attr := "user.foo"
|
||||||
// Set
|
// Set
|
||||||
val1 := []byte("123456789")
|
val1 := []byte("123456789")
|
||||||
err = xattr.LSet(fn, attr, val1)
|
err = xattr.LSet(fn, attr, val1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
return err
|
||||||
}
|
}
|
||||||
// Read back
|
// Read back
|
||||||
val2, err := xattr.LGet(fn, attr)
|
val2, err := xattr.LGet(fn, attr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
return err
|
||||||
}
|
}
|
||||||
if !bytes.Equal(val1, val2) {
|
if !bytes.Equal(val1, val2) {
|
||||||
t.Fatalf("wrong readback value: %v != %v", val1, val2)
|
return fmt.Errorf("wrong readback value: %v != %v", val1, val2)
|
||||||
}
|
}
|
||||||
// Remove
|
// Remove
|
||||||
err = xattr.LRemove(fn, attr)
|
err = xattr.LRemove(fn, attr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
return err
|
||||||
}
|
}
|
||||||
// Read back
|
// Read back
|
||||||
val3, err := xattr.LGet(fn, attr)
|
val3, err := xattr.LGet(fn, attr)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("attr is still there after deletion!? val3=%v", val3)
|
return fmt.Errorf("attr is still there after deletion!? val3=%v", val3)
|
||||||
}
|
}
|
||||||
|
// List
|
||||||
|
list, err = xattr.LList(fn)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(list) > 0 {
|
||||||
|
return fmt.Errorf("Should have gotten empty result, got %v", list)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test xattr set, get, rm on a regular file.
|
||||||
|
func TestSetGetRmRegularFile(t *testing.T) {
|
||||||
|
fn := test_helpers.DefaultPlainDir + "/TestSetGetRmRegularFile"
|
||||||
|
err := ioutil.WriteFile(fn, nil, 0700)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("creating empty file failed: %v", err)
|
||||||
|
}
|
||||||
|
err = setGetRmList(fn)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test xattr set, get, rm on a fifo. This should not hang.
|
||||||
|
func TestSetGetRmFifo(t *testing.T) {
|
||||||
|
fn := test_helpers.DefaultPlainDir + "/TestSetGetRmFifo"
|
||||||
|
err := syscall.Mkfifo(fn, 0700)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("creating fifo failed: %v", err)
|
||||||
|
}
|
||||||
|
// We expect to get EPERM, but we should not hang:
|
||||||
|
// $ setfattr -n user.foo -v XXXXX fifo
|
||||||
|
// setfattr: fifo: Operation not permitted
|
||||||
|
setGetRmList(fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestXattrSetEmpty(t *testing.T) {
|
func TestXattrSetEmpty(t *testing.T) {
|
||||||
|
Loading…
Reference in New Issue
Block a user