gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/sentry/fsimpl/erofs/regular_file.go (about) 1 // Copyright 2023 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 erofs 16 17 import ( 18 "io" 19 "sync" 20 21 "gvisor.dev/gvisor/pkg/abi/linux" 22 "gvisor.dev/gvisor/pkg/context" 23 "gvisor.dev/gvisor/pkg/erofs" 24 "gvisor.dev/gvisor/pkg/errors/linuxerr" 25 "gvisor.dev/gvisor/pkg/hostarch" 26 "gvisor.dev/gvisor/pkg/safemem" 27 "gvisor.dev/gvisor/pkg/sentry/memmap" 28 "gvisor.dev/gvisor/pkg/sentry/vfs" 29 "gvisor.dev/gvisor/pkg/usermem" 30 ) 31 32 // +stateify savable 33 type regularFileFD struct { 34 fileDescription 35 36 // offMu protects off. 37 offMu sync.Mutex `state:"nosave"` 38 39 // off is the file offset. 40 // +checklocks:offMu 41 off int64 42 } 43 44 // PRead implements vfs.FileDescriptionImpl.PRead. 45 func (fd *regularFileFD) PRead(ctx context.Context, dst usermem.IOSequence, offset int64, opts vfs.ReadOptions) (int64, error) { 46 if offset < 0 { 47 return 0, linuxerr.EINVAL 48 } 49 50 // Check that flags are supported. 51 // 52 // TODO(gvisor.dev/issue/2601): Support select preadv2 flags. 53 if opts.Flags&^linux.RWF_HIPRI != 0 { 54 return 0, linuxerr.EOPNOTSUPP 55 } 56 57 if dst.NumBytes() == 0 { 58 return 0, nil 59 } 60 61 data, err := fd.inode().Data() 62 if err != nil { 63 return 0, err 64 } 65 r := ®ularFileReader{ 66 data: data, 67 off: uint64(offset), 68 } 69 return dst.CopyOutFrom(ctx, r) 70 } 71 72 type regularFileReader struct { 73 data safemem.BlockSeq 74 off uint64 75 } 76 77 // ReadToBlocks implements safemem.Reader.ReadToBlocks. 78 func (r *regularFileReader) ReadToBlocks(dsts safemem.BlockSeq) (uint64, error) { 79 if r.off >= r.data.NumBytes() { 80 return 0, io.EOF 81 } 82 cp, err := safemem.CopySeq(dsts, r.data.DropFirst(int(r.off))) 83 r.off += cp 84 return cp, err 85 } 86 87 // Read implements vfs.FileDescriptionImpl.Read. 88 func (fd *regularFileFD) Read(ctx context.Context, dst usermem.IOSequence, opts vfs.ReadOptions) (int64, error) { 89 fd.offMu.Lock() 90 n, err := fd.PRead(ctx, dst, fd.off, opts) 91 fd.off += n 92 fd.offMu.Unlock() 93 return n, err 94 } 95 96 // PWrite implements vfs.FileDescriptionImpl.PWrite. 97 func (fd *regularFileFD) PWrite(ctx context.Context, src usermem.IOSequence, offset int64, opts vfs.WriteOptions) (int64, error) { 98 return 0, linuxerr.EROFS 99 } 100 101 // Write implements vfs.FileDescriptionImpl.Write. 102 func (fd *regularFileFD) Write(ctx context.Context, src usermem.IOSequence, opts vfs.WriteOptions) (int64, error) { 103 return 0, linuxerr.EROFS 104 } 105 106 // Seek implements vfs.FileDescriptionImpl.Seek. 107 func (fd *regularFileFD) Seek(ctx context.Context, offset int64, whence int32) (int64, error) { 108 fd.offMu.Lock() 109 defer fd.offMu.Unlock() 110 switch whence { 111 case linux.SEEK_SET: 112 // use offset as specified 113 case linux.SEEK_CUR: 114 offset += fd.off 115 case linux.SEEK_END: 116 offset += int64(fd.inode().Size()) 117 default: 118 return 0, linuxerr.EINVAL 119 } 120 if offset < 0 { 121 return 0, linuxerr.EINVAL 122 } 123 fd.off = offset 124 return offset, nil 125 } 126 127 // ConfigureMMap implements vfs.FileDescriptionImpl.ConfigureMMap. 128 func (fd *regularFileFD) ConfigureMMap(ctx context.Context, opts *memmap.MMapOpts) error { 129 return vfs.GenericConfigureMMap(&fd.vfsfd, fd.inode(), opts) 130 } 131 132 // AddMapping implements memmap.Mappable.AddMapping. 133 func (i *inode) AddMapping(ctx context.Context, ms memmap.MappingSpace, ar hostarch.AddrRange, offset uint64, writable bool) error { 134 i.mapsMu.Lock() 135 i.mappings.AddMapping(ms, ar, offset, writable) 136 i.mapsMu.Unlock() 137 return nil 138 } 139 140 // RemoveMapping implements memmap.Mappable.RemoveMapping. 141 func (i *inode) RemoveMapping(ctx context.Context, ms memmap.MappingSpace, ar hostarch.AddrRange, offset uint64, writable bool) { 142 i.mapsMu.Lock() 143 i.mappings.RemoveMapping(ms, ar, offset, writable) 144 i.mapsMu.Unlock() 145 } 146 147 // CopyMapping implements memmap.Mappable.CopyMapping. 148 func (i *inode) CopyMapping(ctx context.Context, ms memmap.MappingSpace, srcAR, dstAR hostarch.AddrRange, offset uint64, writable bool) error { 149 i.AddMapping(ctx, ms, dstAR, offset, writable) 150 return nil 151 } 152 153 // Translate implements memmap.Mappable.Translate. 154 func (i *inode) Translate(ctx context.Context, required, optional memmap.MappableRange, at hostarch.AccessType) ([]memmap.Translation, error) { 155 pgend, _ := hostarch.PageRoundUp(i.Size()) 156 if required.End > pgend { 157 if required.Start >= pgend { 158 return nil, &memmap.BusError{io.EOF} 159 } 160 required.End = pgend 161 } 162 if optional.End > pgend { 163 optional.End = pgend 164 } 165 if at.Write { 166 return nil, &memmap.BusError{linuxerr.EROFS} 167 } 168 offset, err := i.DataOffset() 169 if err != nil { 170 return nil, &memmap.BusError{err} 171 } 172 mr := optional 173 return []memmap.Translation{ 174 { 175 Source: mr, 176 File: &i.fs.mf, 177 Offset: mr.Start + offset, 178 Perms: at, 179 }, 180 }, nil 181 } 182 183 // InvalidateUnsavable implements memmap.Mappable.InvalidateUnsavable. 184 func (i *inode) InvalidateUnsavable(ctx context.Context) error { 185 i.mapsMu.Lock() 186 i.mappings.InvalidateAll(memmap.InvalidateOpts{}) 187 i.mapsMu.Unlock() 188 return nil 189 } 190 191 // +stateify savable 192 type imageMemmapFile struct { 193 memmap.NoBufferedIOFallback 194 195 image *erofs.Image 196 } 197 198 // IncRef implements memmap.File.IncRef. 199 func (mf *imageMemmapFile) IncRef(fr memmap.FileRange, memCgID uint32) {} 200 201 // DecRef implements memmap.File.DecRef. 202 func (mf *imageMemmapFile) DecRef(fr memmap.FileRange) {} 203 204 // MapInternal implements memmap.File.MapInternal. 205 func (mf *imageMemmapFile) MapInternal(fr memmap.FileRange, at hostarch.AccessType) (safemem.BlockSeq, error) { 206 if at.Write { 207 return safemem.BlockSeq{}, &memmap.BusError{linuxerr.EROFS} 208 } 209 bytes, err := mf.image.BytesAt(fr.Start, fr.Length()) 210 if err != nil { 211 return safemem.BlockSeq{}, &memmap.BusError{err} 212 } 213 return safemem.BlockSeqOf(safemem.BlockFromSafeSlice(bytes)), nil 214 } 215 216 // FD implements memmap.File.FD. 217 func (mf *imageMemmapFile) FD() int { 218 return mf.image.FD() 219 }