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

Support FALLOCATE opcode.

parent cb4ffbc0
......@@ -79,6 +79,7 @@ type FsNode interface {
Chown(file File, uid uint32, gid uint32, 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)
Fallocate(file File, off uint64, size uint64, mode uint32, context *Context) (code Status)
StatFs() *StatfsOut
}
......@@ -180,6 +181,7 @@ type File interface {
Chown(uid uint32, gid uint32) Status
Chmod(perms uint32) 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
......@@ -321,6 +323,7 @@ type RawFileSystem interface {
Write(*Context, *raw.WriteIn, []byte) (written uint32, code Status)
Flush(context *Context, input *raw.FlushIn) Status
Fsync(*Context, *raw.FsyncIn) (code Status)
Fallocate(Context *Context, in *raw.FallocateIn) (code Status)
// Directory handling
OpenDir(out *raw.OpenOut, context *Context, input *raw.OpenIn) (status 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) {
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
func (n *DefaultFsNode) Utimens(file File, atime *time.Time, mtime *time.Time, context *Context) (code Status) {
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
func (fs *DefaultRawFileSystem) FsyncDir(context *Context, input *raw.FsyncIn) (code Status) {
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 {
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
......@@ -226,3 +236,7 @@ func (f *ReadOnlyFile) Chmod(mode uint32) Status {
func (f *ReadOnlyFile) Chown(uid uint32, gid uint32) Status {
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
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) {
n := c.toInode(context.NodeId)
return n.fsInode.Readlink(context)
......
......@@ -332,6 +332,11 @@ func (fs *LockingRawFileSystem) StatFs(out *StatfsOut, context *Context) (code S
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 {
defer fs.locked()()
return fmt.Sprintf("Locked(%s)", fs.RawFS.String())
......
......@@ -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))
return &LoopbackFile{File: f}, ToStatus(err)
}
......@@ -815,3 +815,19 @@ func TestUmask(t *testing.T) {
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 (
_OP_POLL = int32(40)
_OP_NOTIFY_REPLY = int32(41)
_OP_BATCH_FORGET = int32(42)
_OP_FALLOCATE = int32(43) // protocol version 19.
// Ugh - what will happen if FUSE introduces a new opcode here?
_OP_NOTIFY_ENTRY = int32(51)
_OP_NOTIFY_INODE = int32(52)
_OP_NOTIFY_DELETE = int32(53)
_OP_NOTIFY_ENTRY = int32(100)
_OP_NOTIFY_INODE = int32(101)
_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) {
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)
......@@ -410,6 +415,7 @@ func init() {
_OP_BMAP: unsafe.Sizeof(raw.BmapIn{}),
_OP_IOCTL: unsafe.Sizeof(raw.IoctlIn{}),
_OP_POLL: unsafe.Sizeof(raw.PollIn{}),
_OP_FALLOCATE: unsafe.Sizeof(raw.FallocateIn{}),
} {
operationHandlers[op].InputSize = sz
}
......@@ -483,6 +489,7 @@ func init() {
_OP_NOTIFY_ENTRY: "NOTIFY_ENTRY",
_OP_NOTIFY_INODE: "NOTIFY_INODE",
_OP_NOTIFY_DELETE: "NOTIFY_DELETE",
_OP_FALLOCATE: "FALLOCATE",
} {
operationHandlers[op].Name = v
}
......@@ -521,6 +528,7 @@ func init() {
_OP_STATFS: doStatFs,
_OP_IOCTL: doIoctl,
_OP_DESTROY: doDestroy,
_OP_FALLOCATE: doFallocate,
} {
operationHandlers[op].Func = v
}
......@@ -565,6 +573,7 @@ func init() {
_OP_MKDIR: func(ptr unsafe.Pointer) interface{} { return (*raw.MkdirIn)(ptr) },
_OP_RELEASE: 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
}
......
......@@ -640,3 +640,23 @@ func (n *pathInode) Utimens(file File, atime *time.Time, mtime *time.Time, conte
}
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