Commit cd915a97 authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

Implement splice to fuse device.

parent ad42d7ab
...@@ -135,7 +135,25 @@ func TestTouch(t *testing.T) { ...@@ -135,7 +135,25 @@ func TestTouch(t *testing.T) {
} }
} }
func (tc *testCase) TestReadThrough(t *testing.T) { func TestReadLarge(t *testing.T) {
ts := NewTestCase(t)
defer ts.Cleanup()
content := make([]byte, 1024*1024)
for i := range content {
content[i] = byte(i)
}
err := ioutil.WriteFile(ts.origFile, []byte(content), 0644)
CheckSuccess(err)
back, err := ioutil.ReadFile(ts.mountFile)
CheckSuccess(err)
if bytes.Compare(content, back) != 0 {
t.Errorf("content comparison failed")
}
}
func TestReadThrough(t *testing.T) {
ts := NewTestCase(t) ts := NewTestCase(t)
defer ts.Cleanup() defer ts.Cleanup()
......
...@@ -10,6 +10,7 @@ import ( ...@@ -10,6 +10,7 @@ import (
"unsafe" "unsafe"
"github.com/hanwen/go-fuse/raw" "github.com/hanwen/go-fuse/raw"
"github.com/hanwen/go-fuse/splice"
) )
const ( const (
...@@ -44,6 +45,7 @@ type MountState struct { ...@@ -44,6 +45,7 @@ type MountState struct {
reqReaders int reqReaders int
outstandingReadBufs int outstandingReadBufs int
canSplice bool
loops sync.WaitGroup loops sync.WaitGroup
} }
...@@ -159,7 +161,7 @@ func (ms *MountState) BufferPoolStats() string { ...@@ -159,7 +161,7 @@ func (ms *MountState) BufferPoolStats() string {
r = len(ms.readPool) + ms.reqReaders r = len(ms.readPool) + ms.reqReaders
ms.reqMu.Unlock() ms.reqMu.Unlock()
s += fmt.Sprintf("read buffers: %d (sz %d )", s += fmt.Sprintf(" read buffers: %d (sz %d )",
r, ms.opts.MaxWrite/PAGESIZE + 1) r, ms.opts.MaxWrite/PAGESIZE + 1)
return s return s
} }
...@@ -359,11 +361,12 @@ func (ms *MountState) write(req *request) Status { ...@@ -359,11 +361,12 @@ func (ms *MountState) write(req *request) Status {
} }
if req.flatData.FdSize > 0 { if req.flatData.FdSize > 0 {
if ms.TrySplice(req) { if err := ms.TrySplice(header, req); err == nil {
return OK return OK
} else { } else {
buf := ms.AllocOut(req, uint32(req.flatData.FdSize)) buf := ms.AllocOut(req, uint32(req.flatData.FdSize))
req.flatData.Read(buf) req.flatData.Read(buf)
header = req.serializeHeader()
} }
} }
...@@ -371,9 +374,38 @@ func (ms *MountState) write(req *request) Status { ...@@ -371,9 +374,38 @@ func (ms *MountState) write(req *request) Status {
return ToStatus(err) return ToStatus(err)
} }
func (ms *MountState) TrySplice(req *request) bool { func (ms *MountState) TrySplice(header []byte, req *request) error {
// TODO - implement. finalSplice, err := splice.Get()
return false if err != nil {
return err
}
defer splice.Done(finalSplice)
total := len(header) + req.flatData.FdSize
if !finalSplice.Grow(total) {
return fmt.Errorf("splice.Grow failed.")
}
_, err = finalSplice.Write(header)
if err != nil {
return err
}
n, err := finalSplice.LoadFromAt(req.flatData.Fd, req.flatData.FdSize, req.flatData.FdOff)
if err != nil {
// TODO - handle EOF.
// TODO - extract the data from splice.
return err
}
if n != req.flatData.FdSize {
return fmt.Errorf("Size mismatch %d %d", n, req.flatData.FdSize)
}
_, err = finalSplice.WriteTo(ms.mountFile.Fd(), total)
if err != nil {
return fmt.Errorf("Splice write %v", err)
}
return nil
} }
func (ms *MountState) writeInodeNotify(entry *raw.NotifyInvalInodeOut) Status { func (ms *MountState) writeInodeNotify(entry *raw.NotifyInvalInodeOut) Status {
......
...@@ -8,6 +8,7 @@ import ( ...@@ -8,6 +8,7 @@ import (
"unsafe" "unsafe"
"github.com/hanwen/go-fuse/raw" "github.com/hanwen/go-fuse/raw"
"github.com/hanwen/go-fuse/splice"
) )
var _ = log.Printf var _ = log.Printf
...@@ -85,6 +86,14 @@ func doInit(state *MountState, req *request) { ...@@ -85,6 +86,14 @@ func doInit(state *MountState, req *request) {
state.kernelSettings = *input state.kernelSettings = *input
state.kernelSettings.Flags = input.Flags & (raw.CAP_ASYNC_READ | raw.CAP_BIG_WRITES | raw.CAP_FILE_OPS) state.kernelSettings.Flags = input.Flags & (raw.CAP_ASYNC_READ | raw.CAP_BIG_WRITES | raw.CAP_FILE_OPS)
if input.Minor >= 13 {
state.canSplice = true
maxW := splice.MaxPipeSize() - 4096
if !splice.Resizable() && state.opts.MaxWrite > maxW {
state.opts.MaxWrite = maxW
}
}
out := &raw.InitOut{ out := &raw.InitOut{
Major: FUSE_KERNEL_VERSION, Major: FUSE_KERNEL_VERSION,
Minor: OUR_MINOR_VERSION, Minor: OUR_MINOR_VERSION,
...@@ -261,10 +270,6 @@ func doRead(state *MountState, req *request) { ...@@ -261,10 +270,6 @@ func doRead(state *MountState, req *request) {
in := (*ReadIn)(req.inData) in := (*ReadIn)(req.inData)
buf := state.AllocOut(req, in.Size) buf := state.AllocOut(req, in.Size)
res := state.fileSystem.Read(req.inHeader, in, buf) res := state.fileSystem.Read(req.inHeader, in, buf)
if res.Ok() {
res.Read(buf)
}
req.flatData = res req.flatData = res
req.status = res.Status req.status = res.Status
} }
......
...@@ -105,7 +105,11 @@ func (r *request) OutputDebug() string { ...@@ -105,7 +105,11 @@ func (r *request) OutputDebug() string {
s := strings.TrimRight(string(r.flatData.Data), "\x00") s := strings.TrimRight(string(r.flatData.Data), "\x00")
flatStr = fmt.Sprintf(" %q", s) flatStr = fmt.Sprintf(" %q", s)
} else { } else {
flatStr = fmt.Sprintf(" %d bytes data\n", r.flatData.Size()) spl := ""
if r.flatData.FdSize > 0 {
spl = " (splice)"
}
flatStr = fmt.Sprintf(" %d bytes data%s\n", r.flatData.Size(), spl)
} }
} }
......
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