gvisor/pkg/sentry/fs/fsutil/host_mappable.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)
}