136 lines
4.8 KiB
Go
136 lines
4.8 KiB
Go
// Copyright 2019 The gVisor Authors.
|
|
//
|
|
// 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 vfs implements a virtual filesystem layer.
|
|
//
|
|
// Lock order:
|
|
//
|
|
// Filesystem implementation locks
|
|
// VirtualFilesystem.mountMu
|
|
// VirtualFilesystem.fsTypesMu
|
|
package vfs
|
|
|
|
import (
|
|
"sync"
|
|
)
|
|
|
|
// A VirtualFilesystem (VFS for short) combines Filesystems in trees of Mounts.
|
|
//
|
|
// There is no analogue to the VirtualFilesystem type in Linux, as the
|
|
// equivalent state in Linux is global.
|
|
type VirtualFilesystem struct {
|
|
// mountMu serializes mount mutations.
|
|
//
|
|
// mountMu is analogous to Linux's namespace_sem.
|
|
mountMu sync.RWMutex
|
|
|
|
// mounts maps (mount parent, mount point) pairs to mounts. (Since mounts
|
|
// are uniquely namespaced, including mount parent in the key correctly
|
|
// handles both bind mounts and mount namespaces; Linux does the same.)
|
|
// Synchronization between mutators and readers is provided by mounts.seq;
|
|
// synchronization between mutators is provided by mountMu.
|
|
//
|
|
// mounts is used to follow mount points during path traversal. We use a
|
|
// single table rather than per-Dentry tables to reduce size (and therefore
|
|
// cache footprint) for the vast majority of Dentries that are not mount
|
|
// points.
|
|
//
|
|
// mounts is analogous to Linux's mount_hashtable.
|
|
mounts mountTable
|
|
|
|
// mountpoints maps mount points to mounts at those points in all
|
|
// namespaces. mountpoints is protected by mountMu.
|
|
//
|
|
// mountpoints is used to find mounts that must be unmounted due to
|
|
// removal of a mount point Dentry from another mount namespace. ("A file
|
|
// or directory that is a mount point in one namespace that is not a mount
|
|
// point in another namespace, may be renamed, unlinked, or removed
|
|
// (rmdir(2)) in the mount namespace in which it is not a mount point
|
|
// (subject to the usual permission checks)." - mount_namespaces(7))
|
|
//
|
|
// mountpoints is analogous to Linux's mountpoint_hashtable.
|
|
mountpoints map[*Dentry]map[*Mount]struct{}
|
|
|
|
// fsTypes contains all FilesystemTypes that are usable in the
|
|
// VirtualFilesystem. fsTypes is protected by fsTypesMu.
|
|
fsTypesMu sync.RWMutex
|
|
fsTypes map[string]FilesystemType
|
|
}
|
|
|
|
// New returns a new VirtualFilesystem with no mounts or FilesystemTypes.
|
|
func New() *VirtualFilesystem {
|
|
vfs := &VirtualFilesystem{
|
|
mountpoints: make(map[*Dentry]map[*Mount]struct{}),
|
|
fsTypes: make(map[string]FilesystemType),
|
|
}
|
|
vfs.mounts.Init()
|
|
return vfs
|
|
}
|
|
|
|
// A VirtualDentry represents a node in a VFS tree, by combining a Dentry
|
|
// (which represents a node in a Filesystem's tree) and a Mount (which
|
|
// represents the Filesystem's position in a VFS mount tree).
|
|
//
|
|
// VirtualDentry's semantics are similar to that of a Go interface object
|
|
// representing a pointer: it is a copyable value type that represents
|
|
// references to another entity. The zero value of VirtualDentry is an "empty
|
|
// VirtualDentry", directly analogous to a nil interface object.
|
|
// VirtualDentry.Ok() checks that a VirtualDentry is not zero-valued; unless
|
|
// otherwise specified, all other VirtualDentry methods require
|
|
// VirtualDentry.Ok() == true.
|
|
//
|
|
// Mounts and Dentries are reference-counted, requiring that users call
|
|
// VirtualDentry.{Inc,Dec}Ref() as appropriate. We often colloquially refer to
|
|
// references on the Mount and Dentry referred to by a VirtualDentry as
|
|
// references on the VirtualDentry itself. Unless otherwise specified, all
|
|
// VirtualDentry methods require that a reference is held on the VirtualDentry.
|
|
//
|
|
// VirtualDentry is analogous to Linux's struct path.
|
|
type VirtualDentry struct {
|
|
mount *Mount
|
|
dentry *Dentry
|
|
}
|
|
|
|
// Ok returns true if vd is not empty. It does not require that a reference is
|
|
// held.
|
|
func (vd VirtualDentry) Ok() bool {
|
|
return vd.mount != nil
|
|
}
|
|
|
|
// IncRef increments the reference counts on the Mount and Dentry represented
|
|
// by vd.
|
|
func (vd VirtualDentry) IncRef() {
|
|
vd.mount.incRef()
|
|
vd.dentry.incRef(vd.mount.fs)
|
|
}
|
|
|
|
// DecRef decrements the reference counts on the Mount and Dentry represented
|
|
// by vd.
|
|
func (vd VirtualDentry) DecRef() {
|
|
vd.dentry.decRef(vd.mount.fs)
|
|
vd.mount.decRef()
|
|
}
|
|
|
|
// Mount returns the Mount associated with vd. It does not take a reference on
|
|
// the returned Mount.
|
|
func (vd VirtualDentry) Mount() *Mount {
|
|
return vd.mount
|
|
}
|
|
|
|
// Dentry returns the Dentry associated with vd. It does not take a reference
|
|
// on the returned Dentry.
|
|
func (vd VirtualDentry) Dentry() *Dentry {
|
|
return vd.dentry
|
|
}
|