From 7d1b6226cdbc4e36aa6f5c4ce8291893999e2bda Mon Sep 17 00:00:00 2001 From: Sandy Xu Date: Wed, 30 Oct 2024 17:41:44 +0800 Subject: [PATCH] trySplice: use one pair instead of two; add move flag to splice --- fuse/splice_linux.go | 45 +++++++++----------------------------------- splice/pair_linux.go | 7 ++++--- 2 files changed, 13 insertions(+), 39 deletions(-) diff --git a/fuse/splice_linux.go b/fuse/splice_linux.go index 70f836a24..bf331301e 100644 --- a/fuse/splice_linux.go +++ b/fuse/splice_linux.go @@ -29,48 +29,25 @@ func (s *Server) setSplice() { // This dance is neccessary because header and payload cannot be split across // two splices and we cannot seek in a pipe buffer. func (ms *Server) trySplice(header []byte, req *request, fdData *readResultFd) error { - var err error - // Get a pair of connected pipes - pair1, err := splice.Get() - if err != nil { - return err - } - defer splice.Done(pair1) - - // Grow buffer pipe to requested size + one extra page - // Without the extra page the kernel will block once the pipe is almost full - pair1Sz := fdData.Size() + os.Getpagesize() - if err := pair1.Grow(pair1Sz); err != nil { - return err - } - - // Read data from file - payloadLen, err := pair1.LoadFromAt(fdData.Fd, fdData.Size(), fdData.Off) - - if err != nil { - // TODO - extract the data from splice. - return err - } - - // Get another pair of connected pipes - pair2, err := splice.Get() + pair, err := splice.Get() if err != nil { return err } - defer splice.Done(pair2) + defer splice.Done(pair) // Grow pipe to header + actually read size + one extra page // Without the extra page the kernel will block once the pipe is almost full + payloadLen := fdData.Size() header = req.serializeHeader(payloadLen) total := len(header) + payloadLen - pair2Sz := total + os.Getpagesize() - if err := pair2.Grow(pair2Sz); err != nil { + // FIXME: use pipes big enough to skip the Grow()? + if err := pair.Grow(total + os.Getpagesize()); err != nil { return err } // Write header into pair2 - n, err := pair2.Write(header) + n, err := pair.Write(header) if err != nil { return err } @@ -79,7 +56,7 @@ func (ms *Server) trySplice(header []byte, req *request, fdData *readResultFd) e } // Write data into pair2 - n, err = pair2.LoadFrom(pair1.ReadFd(), payloadLen) + n, err = pair.LoadFrom(fdData.Fd, payloadLen) if err != nil { return err } @@ -88,10 +65,6 @@ func (ms *Server) trySplice(header []byte, req *request, fdData *readResultFd) e } // Write header + data to /dev/fuse - _, err = pair2.WriteTo(uintptr(ms.mountFd), total) - if err != nil { - return err - } - - return nil + _, err = pair.WriteTo(uintptr(ms.mountFd), total) + return err } diff --git a/splice/pair_linux.go b/splice/pair_linux.go index f8923e307..c14578474 100644 --- a/splice/pair_linux.go +++ b/splice/pair_linux.go @@ -11,6 +11,9 @@ import ( "syscall" ) +const _SPLICE_F_MOVE = 0x1 +const _SPLICE_F_NONBLOCK = 0x2 + func (p *Pair) LoadFromAt(fd uintptr, sz int, off int64) (int, error) { n, err := syscall.Splice(int(fd), &off, p.w, nil, sz, 0) return int(n), err @@ -30,15 +33,13 @@ func (p *Pair) LoadFrom(fd uintptr, sz int) (int, error) { } func (p *Pair) WriteTo(fd uintptr, n int) (int, error) { - m, err := syscall.Splice(p.r, nil, int(fd), nil, int(n), 0) + m, err := syscall.Splice(p.r, nil, int(fd), nil, int(n), _SPLICE_F_MOVE) if err != nil { err = os.NewSyscallError("Splice write", err) } return int(m), err } -const _SPLICE_F_NONBLOCK = 0x2 - func (p *Pair) discard() { _, err := syscall.Splice(p.r, nil, int(devNullFD), nil, int(p.size), _SPLICE_F_NONBLOCK) if err == syscall.EAGAIN {