Commit 6c43d2aa authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

Support FALLOCATE opcode.

parent cb4ffbc0
...@@ -79,6 +79,7 @@ type FsNode interface { ...@@ -79,6 +79,7 @@ type FsNode interface {
Chown(file File, uid uint32, gid uint32, context *Context) (code Status) Chown(file File, uid uint32, gid uint32, context *Context) (code Status)
Truncate(file File, size uint64, context *Context) (code Status) Truncate(file File, size uint64, context *Context) (code Status)
Utimens(file File, atime *time.Time, mtime *time.Time, context *Context) (code Status) Utimens(file File, atime *time.Time, mtime *time.Time, context *Context) (code Status)
Fallocate(file File, off uint64, size uint64, mode uint32, context *Context) (code Status)
StatFs() *StatfsOut StatFs() *StatfsOut
} }
...@@ -180,6 +181,7 @@ type File interface { ...@@ -180,6 +181,7 @@ type File interface {
Chown(uid uint32, gid uint32) Status Chown(uid uint32, gid uint32) Status
Chmod(perms uint32) Status Chmod(perms uint32) Status
Utimens(atime *time.Time, mtime *time.Time) Status Utimens(atime *time.Time, mtime *time.Time) Status
Allocate(off uint64, size uint64, mode uint32) (code Status)
} }
// The result of Read is an array of bytes, but for performance // The result of Read is an array of bytes, but for performance
...@@ -321,6 +323,7 @@ type RawFileSystem interface { ...@@ -321,6 +323,7 @@ type RawFileSystem interface {
Write(*Context, *raw.WriteIn, []byte) (written uint32, code Status) Write(*Context, *raw.WriteIn, []byte) (written uint32, code Status)
Flush(context *Context, input *raw.FlushIn) Status Flush(context *Context, input *raw.FlushIn) Status
Fsync(*Context, *raw.FsyncIn) (code Status) Fsync(*Context, *raw.FsyncIn) (code Status)
Fallocate(Context *Context, in *raw.FallocateIn) (code Status)
// Directory handling // Directory handling
OpenDir(out *raw.OpenOut, context *Context, input *raw.OpenIn) (status Status) OpenDir(out *raw.OpenOut, context *Context, input *raw.OpenIn) (status Status)
......
...@@ -65,3 +65,7 @@ func (f *DefaultFile) Chmod(perms uint32) Status { ...@@ -65,3 +65,7 @@ func (f *DefaultFile) Chmod(perms uint32) Status {
func (f *DefaultFile) Ioctl(input *raw.IoctlIn) (output *raw.IoctlOut, data []byte, code Status) { func (f *DefaultFile) Ioctl(input *raw.IoctlIn) (output *raw.IoctlOut, data []byte, code Status) {
return nil, nil, ENOSYS return nil, nil, ENOSYS
} }
func (f *DefaultFile) Allocate(off uint64, size uint64, mode uint32) (code Status) {
return ENOSYS
}
...@@ -154,3 +154,7 @@ func (n *DefaultFsNode) Truncate(file File, size uint64, context *Context) (code ...@@ -154,3 +154,7 @@ func (n *DefaultFsNode) Truncate(file File, size uint64, context *Context) (code
func (n *DefaultFsNode) Utimens(file File, atime *time.Time, mtime *time.Time, context *Context) (code Status) { func (n *DefaultFsNode) Utimens(file File, atime *time.Time, mtime *time.Time, context *Context) (code Status) {
return ENOSYS return ENOSYS
} }
func (n *DefaultFsNode) Fallocate(file File, off uint64, size uint64, mode uint32, context *Context) (code Status) {
return ENOSYS
}
...@@ -131,3 +131,7 @@ func (fs *DefaultRawFileSystem) ReleaseDir(context *Context, input *raw.ReleaseI ...@@ -131,3 +131,7 @@ func (fs *DefaultRawFileSystem) ReleaseDir(context *Context, input *raw.ReleaseI
func (fs *DefaultRawFileSystem) FsyncDir(context *Context, input *raw.FsyncIn) (code Status) { func (fs *DefaultRawFileSystem) FsyncDir(context *Context, input *raw.FsyncIn) (code Status) {
return ENOSYS return ENOSYS
} }
func (fs *DefaultRawFileSystem) Fallocate(context *Context, in *raw.FallocateIn) (code Status) {
return ENOSYS
}
...@@ -193,6 +193,16 @@ func (f *LoopbackFile) GetAttr(a *Attr) Status { ...@@ -193,6 +193,16 @@ func (f *LoopbackFile) GetAttr(a *Attr) Status {
return OK return OK
} }
func (f *LoopbackFile) Allocate(off uint64, sz uint64, mode uint32) Status {
f.lock.Lock()
err := syscall.Fallocate(int(f.File.Fd()), mode, int64(off), int64(sz))
f.lock.Unlock()
if err != nil {
return ToStatus(err)
}
return OK
}
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
// ReadOnlyFile is a wrapper that denies writable operations // ReadOnlyFile is a wrapper that denies writable operations
...@@ -226,3 +236,7 @@ func (f *ReadOnlyFile) Chmod(mode uint32) Status { ...@@ -226,3 +236,7 @@ func (f *ReadOnlyFile) Chmod(mode uint32) Status {
func (f *ReadOnlyFile) Chown(uid uint32, gid uint32) Status { func (f *ReadOnlyFile) Chown(uid uint32, gid uint32) Status {
return EPERM return EPERM
} }
func (f *ReadOnlyFile) Allocate(off uint64, sz uint64, mode uint32) Status {
return EPERM
}
...@@ -214,6 +214,13 @@ func (c *FileSystemConnector) SetAttr(out *raw.AttrOut, context *Context, input ...@@ -214,6 +214,13 @@ func (c *FileSystemConnector) SetAttr(out *raw.AttrOut, context *Context, input
return code return code
} }
func (c *FileSystemConnector) Fallocate(context *Context, in *raw.FallocateIn) (code Status) {
n := c.toInode(context.NodeId)
opened := n.mount.getOpenedFile(in.Fh)
return n.fsInode.Fallocate(opened, in.Offset, in.Length, in.Mode, context)
}
func (c *FileSystemConnector) Readlink(context *Context) (out []byte, code Status) { func (c *FileSystemConnector) Readlink(context *Context) (out []byte, code Status) {
n := c.toInode(context.NodeId) n := c.toInode(context.NodeId)
return n.fsInode.Readlink(context) return n.fsInode.Readlink(context)
......
...@@ -332,6 +332,11 @@ func (fs *LockingRawFileSystem) StatFs(out *StatfsOut, context *Context) (code S ...@@ -332,6 +332,11 @@ func (fs *LockingRawFileSystem) StatFs(out *StatfsOut, context *Context) (code S
return fs.RawFS.StatFs(out, context) return fs.RawFS.StatFs(out, context)
} }
func (fs *LockingRawFileSystem) Fallocate(c *Context, in *raw.FallocateIn) (code Status) {
defer fs.locked()()
return fs.RawFS.Fallocate(c, in)
}
func (fs *LockingRawFileSystem) String() string { func (fs *LockingRawFileSystem) String() string {
defer fs.locked()() defer fs.locked()()
return fmt.Sprintf("Locked(%s)", fs.RawFS.String()) return fmt.Sprintf("Locked(%s)", fs.RawFS.String())
......
...@@ -166,3 +166,6 @@ func (fs *LoopbackFileSystem) Create(path string, flags uint32, mode uint32, con ...@@ -166,3 +166,6 @@ func (fs *LoopbackFileSystem) Create(path string, flags uint32, mode uint32, con
f, err := os.OpenFile(fs.GetPath(path), int(flags)|os.O_CREATE, os.FileMode(mode)) f, err := os.OpenFile(fs.GetPath(path), int(flags)|os.O_CREATE, os.FileMode(mode))
return &LoopbackFile{File: f}, ToStatus(err) return &LoopbackFile{File: f}, ToStatus(err)
} }
...@@ -815,3 +815,19 @@ func TestUmask(t *testing.T) { ...@@ -815,3 +815,19 @@ func TestUmask(t *testing.T) {
t.Errorf("got %o, expect mode %o for file %s", got, expect, fn) t.Errorf("got %o, expect mode %o for file %s", got, expect, fn)
} }
} }
func TestFallocate(t *testing.T) {
ts := NewTestCase(t)
defer ts.Cleanup()
rwFile, err := os.OpenFile(ts.mnt+"/file", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666)
CheckSuccess(err)
defer rwFile.Close()
err = syscall.Fallocate(int(rwFile.Fd()), 0, 1024, 4096)
CheckSuccess(err)
fi, err := os.Lstat(ts.orig + "/file")
CheckSuccess(err)
if fi.Size() < (1024+4096) {
t.Fatalf("fallocate should have changed file size. Got %d bytes",
fi.Size())
}
}
...@@ -54,13 +54,14 @@ const ( ...@@ -54,13 +54,14 @@ const (
_OP_POLL = int32(40) _OP_POLL = int32(40)
_OP_NOTIFY_REPLY = int32(41) _OP_NOTIFY_REPLY = int32(41)
_OP_BATCH_FORGET = int32(42) _OP_BATCH_FORGET = int32(42)
_OP_FALLOCATE = int32(43) // protocol version 19.
// Ugh - what will happen if FUSE introduces a new opcode here? // Ugh - what will happen if FUSE introduces a new opcode here?
_OP_NOTIFY_ENTRY = int32(51) _OP_NOTIFY_ENTRY = int32(100)
_OP_NOTIFY_INODE = int32(52) _OP_NOTIFY_INODE = int32(101)
_OP_NOTIFY_DELETE = int32(53) _OP_NOTIFY_DELETE = int32(102) // protocol version 18
_OPCODE_COUNT = int32(54) _OPCODE_COUNT = int32(103)
) )
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
...@@ -337,6 +338,10 @@ func doDestroy(state *MountState, req *request) { ...@@ -337,6 +338,10 @@ func doDestroy(state *MountState, req *request) {
req.status = OK req.status = OK
} }
func doFallocate(state *MountState, req *request) {
req.status = state.fileSystem.Fallocate(&req.context, (*raw.FallocateIn)(req.inData))
}
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
type operationFunc func(*MountState, *request) type operationFunc func(*MountState, *request)
...@@ -410,6 +415,7 @@ func init() { ...@@ -410,6 +415,7 @@ func init() {
_OP_BMAP: unsafe.Sizeof(raw.BmapIn{}), _OP_BMAP: unsafe.Sizeof(raw.BmapIn{}),
_OP_IOCTL: unsafe.Sizeof(raw.IoctlIn{}), _OP_IOCTL: unsafe.Sizeof(raw.IoctlIn{}),
_OP_POLL: unsafe.Sizeof(raw.PollIn{}), _OP_POLL: unsafe.Sizeof(raw.PollIn{}),
_OP_FALLOCATE: unsafe.Sizeof(raw.FallocateIn{}),
} { } {
operationHandlers[op].InputSize = sz operationHandlers[op].InputSize = sz
} }
...@@ -483,6 +489,7 @@ func init() { ...@@ -483,6 +489,7 @@ func init() {
_OP_NOTIFY_ENTRY: "NOTIFY_ENTRY", _OP_NOTIFY_ENTRY: "NOTIFY_ENTRY",
_OP_NOTIFY_INODE: "NOTIFY_INODE", _OP_NOTIFY_INODE: "NOTIFY_INODE",
_OP_NOTIFY_DELETE: "NOTIFY_DELETE", _OP_NOTIFY_DELETE: "NOTIFY_DELETE",
_OP_FALLOCATE: "FALLOCATE",
} { } {
operationHandlers[op].Name = v operationHandlers[op].Name = v
} }
...@@ -521,6 +528,7 @@ func init() { ...@@ -521,6 +528,7 @@ func init() {
_OP_STATFS: doStatFs, _OP_STATFS: doStatFs,
_OP_IOCTL: doIoctl, _OP_IOCTL: doIoctl,
_OP_DESTROY: doDestroy, _OP_DESTROY: doDestroy,
_OP_FALLOCATE: doFallocate,
} { } {
operationHandlers[op].Func = v operationHandlers[op].Func = v
} }
...@@ -565,6 +573,7 @@ func init() { ...@@ -565,6 +573,7 @@ func init() {
_OP_MKDIR: func(ptr unsafe.Pointer) interface{} { return (*raw.MkdirIn)(ptr) }, _OP_MKDIR: func(ptr unsafe.Pointer) interface{} { return (*raw.MkdirIn)(ptr) },
_OP_RELEASE: func(ptr unsafe.Pointer) interface{} { return (*raw.ReleaseIn)(ptr) }, _OP_RELEASE: func(ptr unsafe.Pointer) interface{} { return (*raw.ReleaseIn)(ptr) },
_OP_RELEASEDIR: func(ptr unsafe.Pointer) interface{} { return (*raw.ReleaseIn)(ptr) }, _OP_RELEASEDIR: func(ptr unsafe.Pointer) interface{} { return (*raw.ReleaseIn)(ptr) },
_OP_FALLOCATE: func(ptr unsafe.Pointer) interface{} { return (*raw.FallocateIn)(ptr) },
} { } {
operationHandlers[op].DecodeIn = f operationHandlers[op].DecodeIn = f
} }
......
...@@ -640,3 +640,23 @@ func (n *pathInode) Utimens(file File, atime *time.Time, mtime *time.Time, conte ...@@ -640,3 +640,23 @@ func (n *pathInode) Utimens(file File, atime *time.Time, mtime *time.Time, conte
} }
return code return code
} }
func (n *pathInode) Fallocate(file File, off uint64, size uint64, mode uint32, context *Context) (code Status) {
if file != nil {
code = file.Allocate(off, size, mode)
if code.Ok() {
return code
}
}
files := n.inode.Files(O_ANYWRITE)
for _, f := range files {
// TODO - pass context
code = f.Allocate(off, size, mode)
if code.Ok() {
return code
}
}
return code
}
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