github.com/metacubex/gvisor@v0.0.0-20240320004321-933faba989ec/pkg/sentry/fsimpl/gofer/handle.go (about) 1 // Copyright 2019 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package gofer 16 17 import ( 18 "golang.org/x/sys/unix" 19 "github.com/metacubex/gvisor/pkg/context" 20 "github.com/metacubex/gvisor/pkg/lisafs" 21 "github.com/metacubex/gvisor/pkg/safemem" 22 "github.com/metacubex/gvisor/pkg/sentry/hostfd" 23 "github.com/metacubex/gvisor/pkg/sync" 24 ) 25 26 var noHandle = handle{ 27 fdLisa: lisafs.ClientFD{}, // zero value is fine. 28 fd: -1, 29 } 30 31 // handle represents a remote "open file descriptor", consisting of an opened 32 // lisafs FD and optionally a host file descriptor. 33 // 34 // These are explicitly not savable. 35 type handle struct { 36 fdLisa lisafs.ClientFD 37 fd int32 // -1 if unavailable 38 } 39 40 func (h *handle) close(ctx context.Context) { 41 if h.fdLisa.Ok() { 42 h.fdLisa.Close(ctx, true /* flush */) 43 } 44 if h.fd >= 0 { 45 unix.Close(int(h.fd)) 46 h.fd = -1 47 } 48 } 49 50 func (h *handle) readToBlocksAt(ctx context.Context, dsts safemem.BlockSeq, offset uint64) (uint64, error) { 51 if dsts.IsEmpty() { 52 return 0, nil 53 } 54 if h.fd >= 0 { 55 ctx.UninterruptibleSleepStart(false) 56 n, err := hostfd.Preadv2(h.fd, dsts, int64(offset), 0 /* flags */) 57 ctx.UninterruptibleSleepFinish(false) 58 return n, err 59 } 60 rw := getHandleReadWriter(ctx, h, int64(offset)) 61 defer putHandleReadWriter(rw) 62 return safemem.FromIOReader{rw}.ReadToBlocks(dsts) 63 } 64 65 func (h *handle) writeFromBlocksAt(ctx context.Context, srcs safemem.BlockSeq, offset uint64) (uint64, error) { 66 if srcs.IsEmpty() { 67 return 0, nil 68 } 69 if h.fd >= 0 { 70 ctx.UninterruptibleSleepStart(false) 71 n, err := hostfd.Pwritev2(h.fd, srcs, int64(offset), 0 /* flags */) 72 ctx.UninterruptibleSleepFinish(false) 73 return n, err 74 } 75 rw := getHandleReadWriter(ctx, h, int64(offset)) 76 defer putHandleReadWriter(rw) 77 return safemem.FromIOWriter{rw}.WriteFromBlocks(srcs) 78 } 79 80 func (h *handle) allocate(ctx context.Context, mode, offset, length uint64) error { 81 if h.fdLisa.Ok() { 82 return h.fdLisa.Allocate(ctx, mode, offset, length) 83 } 84 if h.fd >= 0 { 85 return unix.Fallocate(int(h.fd), uint32(mode), int64(offset), int64(length)) 86 } 87 return nil 88 } 89 90 func (h *handle) sync(ctx context.Context) error { 91 // If we have a host FD, fsyncing it is likely to be faster than an fsync 92 // RPC. 93 if h.fd >= 0 { 94 ctx.UninterruptibleSleepStart(false) 95 err := unix.Fsync(int(h.fd)) 96 ctx.UninterruptibleSleepFinish(false) 97 return err 98 } 99 if h.fdLisa.Ok() { 100 return h.fdLisa.Sync(ctx) 101 } 102 return nil 103 } 104 105 type handleReadWriter struct { 106 ctx context.Context 107 h handle 108 off uint64 109 } 110 111 var handleReadWriterPool = sync.Pool{ 112 New: func() any { 113 return &handleReadWriter{} 114 }, 115 } 116 117 func getHandleReadWriter(ctx context.Context, h *handle, offset int64) *handleReadWriter { 118 rw := handleReadWriterPool.Get().(*handleReadWriter) 119 rw.ctx = ctx 120 rw.h = *h 121 rw.off = uint64(offset) 122 return rw 123 } 124 125 func putHandleReadWriter(rw *handleReadWriter) { 126 rw.ctx = nil 127 rw.h = noHandle 128 handleReadWriterPool.Put(rw) 129 } 130 131 // Read implements io.Reader.Read. 132 func (rw *handleReadWriter) Read(dst []byte) (int, error) { 133 n, err := rw.h.fdLisa.Read(rw.ctx, dst, rw.off) 134 rw.off += n 135 return int(n), err 136 } 137 138 // Write implements io.Writer.Write. 139 func (rw *handleReadWriter) Write(src []byte) (int, error) { 140 n, err := rw.h.fdLisa.Write(rw.ctx, src, rw.off) 141 rw.off += n 142 return int(n), err 143 } 144 145 // ReadToBlocks implements safemem.Reader.ReadToBlocks. 146 func (rw *handleReadWriter) ReadToBlocks(dsts safemem.BlockSeq) (uint64, error) { 147 n, err := rw.h.readToBlocksAt(rw.ctx, dsts, rw.off) 148 rw.off += n 149 return n, err 150 } 151 152 // WriteFromBlocks implements safemem.Writer.WriteFromBlocks. 153 func (rw *handleReadWriter) WriteFromBlocks(srcs safemem.BlockSeq) (uint64, error) { 154 n, err := rw.h.writeFromBlocksAt(rw.ctx, srcs, rw.off) 155 rw.off += n 156 return n, err 157 }