137 lines
4.2 KiB
Go
137 lines
4.2 KiB
Go
// Copyright 2019 Google LLC
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package fsutil
|
|
|
|
import (
|
|
"sync"
|
|
|
|
"gvisor.googlesource.com/gvisor/pkg/sentry/context"
|
|
"gvisor.googlesource.com/gvisor/pkg/sentry/memmap"
|
|
"gvisor.googlesource.com/gvisor/pkg/sentry/platform"
|
|
"gvisor.googlesource.com/gvisor/pkg/sentry/safemem"
|
|
"gvisor.googlesource.com/gvisor/pkg/sentry/usermem"
|
|
)
|
|
|
|
// HostMappable implements memmap.Mappable and platform.File over an arbitrary
|
|
// host file descriptor.
|
|
//
|
|
// +stateify savable
|
|
type HostMappable struct {
|
|
hostFileMapper *HostFileMapper
|
|
|
|
mu sync.Mutex `state:"nosave"`
|
|
|
|
// fd is the file descriptor to the host. Protected by mu.
|
|
fd int `state:"nosave"`
|
|
|
|
// mappings tracks mappings of the cached file object into
|
|
// memmap.MappingSpaces so it can invalidated upon save. Protected by mu.
|
|
mappings memmap.MappingSet
|
|
}
|
|
|
|
// NewHostMappable creates a new mappable that maps directly to host FD.
|
|
func NewHostMappable() *HostMappable {
|
|
return &HostMappable{
|
|
hostFileMapper: NewHostFileMapper(),
|
|
fd: -1,
|
|
}
|
|
}
|
|
|
|
func (h *HostMappable) getFD() int {
|
|
h.mu.Lock()
|
|
defer h.mu.Unlock()
|
|
if h.fd < 0 {
|
|
panic("HostMappable FD isn't set")
|
|
}
|
|
return h.fd
|
|
}
|
|
|
|
// UpdateFD sets the host FD iff FD hasn't been set before or if there are
|
|
// no mappings.
|
|
func (h *HostMappable) UpdateFD(fd int) {
|
|
h.mu.Lock()
|
|
defer h.mu.Unlock()
|
|
h.fd = fd
|
|
}
|
|
|
|
// AddMapping implements memmap.Mappable.AddMapping.
|
|
func (h *HostMappable) AddMapping(ctx context.Context, ms memmap.MappingSpace, ar usermem.AddrRange, offset uint64, writable bool) error {
|
|
// Hot path. Avoid defers.
|
|
h.mu.Lock()
|
|
mapped := h.mappings.AddMapping(ms, ar, offset, writable)
|
|
for _, r := range mapped {
|
|
h.hostFileMapper.IncRefOn(r)
|
|
}
|
|
h.mu.Unlock()
|
|
return nil
|
|
}
|
|
|
|
// RemoveMapping implements memmap.Mappable.RemoveMapping.
|
|
func (h *HostMappable) RemoveMapping(ctx context.Context, ms memmap.MappingSpace, ar usermem.AddrRange, offset uint64, writable bool) {
|
|
// Hot path. Avoid defers.
|
|
h.mu.Lock()
|
|
unmapped := h.mappings.RemoveMapping(ms, ar, offset, writable)
|
|
for _, r := range unmapped {
|
|
h.hostFileMapper.DecRefOn(r)
|
|
}
|
|
h.mu.Unlock()
|
|
}
|
|
|
|
// CopyMapping implements memmap.Mappable.CopyMapping.
|
|
func (h *HostMappable) CopyMapping(ctx context.Context, ms memmap.MappingSpace, srcAR, dstAR usermem.AddrRange, offset uint64, writable bool) error {
|
|
return h.AddMapping(ctx, ms, dstAR, offset, writable)
|
|
}
|
|
|
|
// Translate implements memmap.Mappable.Translate.
|
|
func (h *HostMappable) Translate(ctx context.Context, required, optional memmap.MappableRange, at usermem.AccessType) ([]memmap.Translation, error) {
|
|
return []memmap.Translation{
|
|
{
|
|
Source: optional,
|
|
File: h,
|
|
Offset: optional.Start,
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
// InvalidateUnsavable implements memmap.Mappable.InvalidateUnsavable.
|
|
func (h *HostMappable) InvalidateUnsavable(ctx context.Context) error {
|
|
h.mu.Lock()
|
|
h.mappings.InvalidateAll(memmap.InvalidateOpts{})
|
|
h.mu.Unlock()
|
|
return nil
|
|
}
|
|
|
|
// MapInto implements platform.File.MapInto.
|
|
func (h *HostMappable) MapInto(as platform.AddressSpace, addr usermem.Addr, fr platform.FileRange, at usermem.AccessType, precommit bool) error {
|
|
return as.MapFile(addr, h.getFD(), fr, at, precommit)
|
|
}
|
|
|
|
// MapInternal implements platform.File.MapInternal.
|
|
func (h *HostMappable) MapInternal(fr platform.FileRange, at usermem.AccessType) (safemem.BlockSeq, error) {
|
|
return h.hostFileMapper.MapInternal(fr, h.getFD(), at.Write)
|
|
}
|
|
|
|
// IncRef implements platform.File.IncRef.
|
|
func (h *HostMappable) IncRef(fr platform.FileRange) {
|
|
mr := memmap.MappableRange{Start: fr.Start, End: fr.End}
|
|
h.hostFileMapper.IncRefOn(mr)
|
|
}
|
|
|
|
// DecRef implements platform.File.DecRef.
|
|
func (h *HostMappable) DecRef(fr platform.FileRange) {
|
|
mr := memmap.MappableRange{Start: fr.Start, End: fr.End}
|
|
h.hostFileMapper.DecRefOn(mr)
|
|
}
|