github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fs/gofer/handles.go (about) 1 // Copyright 2018 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 "io" 19 20 "github.com/SagerNet/gvisor/pkg/context" 21 "github.com/SagerNet/gvisor/pkg/fd" 22 "github.com/SagerNet/gvisor/pkg/log" 23 "github.com/SagerNet/gvisor/pkg/p9" 24 "github.com/SagerNet/gvisor/pkg/refs" 25 "github.com/SagerNet/gvisor/pkg/safemem" 26 "github.com/SagerNet/gvisor/pkg/secio" 27 "github.com/SagerNet/gvisor/pkg/sentry/fs" 28 ) 29 30 // handles are the open handles of a gofer file. They are reference counted to 31 // support open handle sharing between files for read only filesystems. 32 // 33 // If Host != nil then it will be used exclusively over File. 34 type handles struct { 35 refs.AtomicRefCount 36 37 // File is a p9.File handle. Must not be nil. 38 File contextFile 39 40 // Host is an *fd.FD handle. May be nil. 41 Host *fd.FD 42 43 // isHostBorrowed tells whether 'Host' is owned or borrowed. If owned, it's 44 // closed on destruction, otherwise it's released. 45 isHostBorrowed bool 46 } 47 48 // DecRef drops a reference on handles. 49 func (h *handles) DecRef() { 50 ctx := context.Background() 51 h.DecRefWithDestructor(ctx, func(context.Context) { 52 if h.Host != nil { 53 if h.isHostBorrowed { 54 h.Host.Release() 55 } else { 56 if err := h.Host.Close(); err != nil { 57 log.Warningf("error closing host file: %v", err) 58 } 59 } 60 } 61 if err := h.File.close(ctx); err != nil { 62 log.Warningf("error closing p9 file: %v", err) 63 } 64 }) 65 } 66 67 func newHandles(ctx context.Context, client *p9.Client, file contextFile, flags fs.FileFlags) (*handles, error) { 68 _, newFile, err := file.walk(ctx, nil) 69 if err != nil { 70 return nil, err 71 } 72 73 var p9flags p9.OpenFlags 74 switch { 75 case flags.Read && flags.Write: 76 p9flags = p9.ReadWrite 77 case flags.Read && !flags.Write: 78 p9flags = p9.ReadOnly 79 case !flags.Read && flags.Write: 80 p9flags = p9.WriteOnly 81 default: 82 panic("impossible fs.FileFlags") 83 } 84 if flags.Truncate && p9.VersionSupportsOpenTruncateFlag(client.Version()) { 85 p9flags |= p9.OpenTruncate 86 } 87 88 hostFile, _, _, err := newFile.open(ctx, p9flags) 89 if err != nil { 90 newFile.close(ctx) 91 return nil, err 92 } 93 h := handles{ 94 File: newFile, 95 Host: hostFile, 96 } 97 h.EnableLeakCheck("gofer.handles") 98 return &h, nil 99 } 100 101 type handleReadWriter struct { 102 ctx context.Context 103 h *handles 104 off int64 105 } 106 107 func (h *handles) readWriterAt(ctx context.Context, offset int64) *handleReadWriter { 108 return &handleReadWriter{ctx, h, offset} 109 } 110 111 // ReadToBlocks implements safemem.Reader.ReadToBlocks. 112 func (rw *handleReadWriter) ReadToBlocks(dsts safemem.BlockSeq) (uint64, error) { 113 var r io.Reader 114 if rw.h.Host != nil { 115 r = secio.NewOffsetReader(rw.h.Host, rw.off) 116 } else { 117 r = &p9.ReadWriterFile{File: rw.h.File.file, Offset: uint64(rw.off)} 118 } 119 120 rw.ctx.UninterruptibleSleepStart(false) 121 defer rw.ctx.UninterruptibleSleepFinish(false) 122 n, err := safemem.FromIOReader{r}.ReadToBlocks(dsts) 123 rw.off += int64(n) 124 return n, err 125 } 126 127 // WriteFromBlocks implements safemem.Writer.WriteFromBlocks. 128 func (rw *handleReadWriter) WriteFromBlocks(srcs safemem.BlockSeq) (uint64, error) { 129 var w io.Writer 130 if rw.h.Host != nil { 131 w = secio.NewOffsetWriter(rw.h.Host, rw.off) 132 } else { 133 w = &p9.ReadWriterFile{File: rw.h.File.file, Offset: uint64(rw.off)} 134 } 135 136 rw.ctx.UninterruptibleSleepStart(false) 137 defer rw.ctx.UninterruptibleSleepFinish(false) 138 n, err := safemem.FromIOWriter{w}.WriteFromBlocks(srcs) 139 rw.off += int64(n) 140 return n, err 141 }