Report filesystem-specific mount options.
PiperOrigin-RevId: 362406813
This commit is contained in:
parent
a82bd04e2a
commit
c5667022b6
|
@ -137,6 +137,11 @@ func (fs *filesystem) Release(ctx context.Context) {
|
|||
fs.Filesystem.Release(ctx)
|
||||
}
|
||||
|
||||
// MountOptions implements vfs.FilesystemImpl.MountOptions.
|
||||
func (fs *filesystem) MountOptions() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// rootInode is the root directory inode for the devpts mounts.
|
||||
//
|
||||
// +stateify savable
|
||||
|
|
|
@ -548,3 +548,8 @@ func (fs *filesystem) PrependPath(ctx context.Context, vfsroot, vd vfs.VirtualDe
|
|||
defer fs.mu.RUnlock()
|
||||
return genericPrependPath(vfsroot, vd.Mount(), vd.Dentry().Impl().(*dentry), b)
|
||||
}
|
||||
|
||||
// MountOptions implements vfs.FilesystemImpl.MountOptions.
|
||||
func (fs *filesystem) MountOptions() string {
|
||||
return ""
|
||||
}
|
||||
|
|
|
@ -47,6 +47,9 @@ type FilesystemType struct{}
|
|||
|
||||
// +stateify savable
|
||||
type filesystemOptions struct {
|
||||
// mopts contains the raw, unparsed mount options passed to this filesystem.
|
||||
mopts string
|
||||
|
||||
// userID specifies the numeric uid of the mount owner.
|
||||
// This option should not be specified by the filesystem owner.
|
||||
// It is set by libfuse (or, if libfuse is not used, must be set
|
||||
|
@ -108,7 +111,7 @@ func (fsType FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.Virt
|
|||
return nil, nil, err
|
||||
}
|
||||
|
||||
var fsopts filesystemOptions
|
||||
fsopts := filesystemOptions{mopts: opts.Data}
|
||||
mopts := vfs.GenericParseMountOptions(opts.Data)
|
||||
deviceDescriptorStr, ok := mopts["fd"]
|
||||
if !ok {
|
||||
|
@ -260,6 +263,11 @@ func (fs *filesystem) Release(ctx context.Context) {
|
|||
fs.Filesystem.Release(ctx)
|
||||
}
|
||||
|
||||
// MountOptions implements vfs.FilesystemImpl.MountOptions.
|
||||
func (fs *filesystem) MountOptions() string {
|
||||
return fs.opts.mopts
|
||||
}
|
||||
|
||||
// inode implements kernfs.Inode.
|
||||
//
|
||||
// +stateify savable
|
||||
|
|
|
@ -15,7 +15,9 @@
|
|||
package gofer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
|
@ -1608,3 +1610,58 @@ func (fs *filesystem) PrependPath(ctx context.Context, vfsroot, vd vfs.VirtualDe
|
|||
defer fs.renameMu.RUnlock()
|
||||
return genericPrependPath(vfsroot, vd.Mount(), vd.Dentry().Impl().(*dentry), b)
|
||||
}
|
||||
|
||||
type mopt struct {
|
||||
key string
|
||||
value interface{}
|
||||
}
|
||||
|
||||
func (m mopt) String() string {
|
||||
if m.value == nil {
|
||||
return fmt.Sprintf("%s", m.key)
|
||||
}
|
||||
return fmt.Sprintf("%s=%v", m.key, m.value)
|
||||
}
|
||||
|
||||
// MountOptions implements vfs.FilesystemImpl.MountOptions.
|
||||
func (fs *filesystem) MountOptions() string {
|
||||
optsKV := []mopt{
|
||||
{moptTransport, transportModeFD}, // Only valid value, currently.
|
||||
{moptReadFD, fs.opts.fd}, // Currently, read and write FD are the same.
|
||||
{moptWriteFD, fs.opts.fd}, // Currently, read and write FD are the same.
|
||||
{moptAname, fs.opts.aname},
|
||||
{moptDfltUID, fs.opts.dfltuid},
|
||||
{moptDfltGID, fs.opts.dfltgid},
|
||||
{moptMsize, fs.opts.msize},
|
||||
{moptVersion, fs.opts.version},
|
||||
{moptDentryCacheLimit, fs.opts.maxCachedDentries},
|
||||
}
|
||||
|
||||
switch fs.opts.interop {
|
||||
case InteropModeExclusive:
|
||||
optsKV = append(optsKV, mopt{moptCache, cacheFSCache})
|
||||
case InteropModeWritethrough:
|
||||
optsKV = append(optsKV, mopt{moptCache, cacheFSCacheWritethrough})
|
||||
case InteropModeShared:
|
||||
if fs.opts.regularFilesUseSpecialFileFD {
|
||||
optsKV = append(optsKV, mopt{moptCache, cacheNone})
|
||||
} else {
|
||||
optsKV = append(optsKV, mopt{moptCache, cacheRemoteRevalidating})
|
||||
}
|
||||
}
|
||||
if fs.opts.forcePageCache {
|
||||
optsKV = append(optsKV, mopt{moptForcePageCache, nil})
|
||||
}
|
||||
if fs.opts.limitHostFDTranslation {
|
||||
optsKV = append(optsKV, mopt{moptLimitHostFDTranslation, nil})
|
||||
}
|
||||
if fs.opts.overlayfsStaleRead {
|
||||
optsKV = append(optsKV, mopt{moptOverlayfsStaleRead, nil})
|
||||
}
|
||||
|
||||
opts := make([]string, 0, len(optsKV))
|
||||
for _, opt := range optsKV {
|
||||
opts = append(opts, opt.String())
|
||||
}
|
||||
return strings.Join(opts, ",")
|
||||
}
|
||||
|
|
|
@ -66,6 +66,34 @@ import (
|
|||
// Name is the default filesystem name.
|
||||
const Name = "9p"
|
||||
|
||||
// Mount option names for goferfs.
|
||||
const (
|
||||
moptTransport = "trans"
|
||||
moptReadFD = "rfdno"
|
||||
moptWriteFD = "wfdno"
|
||||
moptAname = "aname"
|
||||
moptDfltUID = "dfltuid"
|
||||
moptDfltGID = "dfltgid"
|
||||
moptMsize = "msize"
|
||||
moptVersion = "version"
|
||||
moptDentryCacheLimit = "dentry_cache_limit"
|
||||
moptCache = "cache"
|
||||
moptForcePageCache = "force_page_cache"
|
||||
moptLimitHostFDTranslation = "limit_host_fd_translation"
|
||||
moptOverlayfsStaleRead = "overlayfs_stale_read"
|
||||
)
|
||||
|
||||
// Valid values for the "cache" mount option.
|
||||
const (
|
||||
cacheNone = "none"
|
||||
cacheFSCache = "fscache"
|
||||
cacheFSCacheWritethrough = "fscache_writethrough"
|
||||
cacheRemoteRevalidating = "remote_revalidating"
|
||||
)
|
||||
|
||||
// Valid values for "trans" mount option.
|
||||
const transportModeFD = "fd"
|
||||
|
||||
// FilesystemType implements vfs.FilesystemType.
|
||||
//
|
||||
// +stateify savable
|
||||
|
@ -301,39 +329,39 @@ func (fstype FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.Virt
|
|||
|
||||
// Get the attach name.
|
||||
fsopts.aname = "/"
|
||||
if aname, ok := mopts["aname"]; ok {
|
||||
delete(mopts, "aname")
|
||||
if aname, ok := mopts[moptAname]; ok {
|
||||
delete(mopts, moptAname)
|
||||
fsopts.aname = aname
|
||||
}
|
||||
|
||||
// Parse the cache policy. For historical reasons, this defaults to the
|
||||
// least generally-applicable option, InteropModeExclusive.
|
||||
fsopts.interop = InteropModeExclusive
|
||||
if cache, ok := mopts["cache"]; ok {
|
||||
delete(mopts, "cache")
|
||||
if cache, ok := mopts[moptCache]; ok {
|
||||
delete(mopts, moptCache)
|
||||
switch cache {
|
||||
case "fscache":
|
||||
case cacheFSCache:
|
||||
fsopts.interop = InteropModeExclusive
|
||||
case "fscache_writethrough":
|
||||
case cacheFSCacheWritethrough:
|
||||
fsopts.interop = InteropModeWritethrough
|
||||
case "none":
|
||||
case cacheNone:
|
||||
fsopts.regularFilesUseSpecialFileFD = true
|
||||
fallthrough
|
||||
case "remote_revalidating":
|
||||
case cacheRemoteRevalidating:
|
||||
fsopts.interop = InteropModeShared
|
||||
default:
|
||||
ctx.Warningf("gofer.FilesystemType.GetFilesystem: invalid cache policy: cache=%s", cache)
|
||||
ctx.Warningf("gofer.FilesystemType.GetFilesystem: invalid cache policy: %s=%s", moptCache, cache)
|
||||
return nil, nil, syserror.EINVAL
|
||||
}
|
||||
}
|
||||
|
||||
// Parse the default UID and GID.
|
||||
fsopts.dfltuid = _V9FS_DEFUID
|
||||
if dfltuidstr, ok := mopts["dfltuid"]; ok {
|
||||
delete(mopts, "dfltuid")
|
||||
if dfltuidstr, ok := mopts[moptDfltUID]; ok {
|
||||
delete(mopts, moptDfltUID)
|
||||
dfltuid, err := strconv.ParseUint(dfltuidstr, 10, 32)
|
||||
if err != nil {
|
||||
ctx.Warningf("gofer.FilesystemType.GetFilesystem: invalid default UID: dfltuid=%s", dfltuidstr)
|
||||
ctx.Warningf("gofer.FilesystemType.GetFilesystem: invalid default UID: %s=%s", moptDfltUID, dfltuidstr)
|
||||
return nil, nil, syserror.EINVAL
|
||||
}
|
||||
// In Linux, dfltuid is interpreted as a UID and is converted to a KUID
|
||||
|
@ -342,11 +370,11 @@ func (fstype FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.Virt
|
|||
fsopts.dfltuid = auth.KUID(dfltuid)
|
||||
}
|
||||
fsopts.dfltgid = _V9FS_DEFGID
|
||||
if dfltgidstr, ok := mopts["dfltgid"]; ok {
|
||||
delete(mopts, "dfltgid")
|
||||
if dfltgidstr, ok := mopts[moptDfltGID]; ok {
|
||||
delete(mopts, moptDfltGID)
|
||||
dfltgid, err := strconv.ParseUint(dfltgidstr, 10, 32)
|
||||
if err != nil {
|
||||
ctx.Warningf("gofer.FilesystemType.GetFilesystem: invalid default UID: dfltgid=%s", dfltgidstr)
|
||||
ctx.Warningf("gofer.FilesystemType.GetFilesystem: invalid default UID: %s=%s", moptDfltGID, dfltgidstr)
|
||||
return nil, nil, syserror.EINVAL
|
||||
}
|
||||
fsopts.dfltgid = auth.KGID(dfltgid)
|
||||
|
@ -354,11 +382,11 @@ func (fstype FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.Virt
|
|||
|
||||
// Parse the 9P message size.
|
||||
fsopts.msize = 1024 * 1024 // 1M, tested to give good enough performance up to 64M
|
||||
if msizestr, ok := mopts["msize"]; ok {
|
||||
delete(mopts, "msize")
|
||||
if msizestr, ok := mopts[moptMsize]; ok {
|
||||
delete(mopts, moptMsize)
|
||||
msize, err := strconv.ParseUint(msizestr, 10, 32)
|
||||
if err != nil {
|
||||
ctx.Warningf("gofer.FilesystemType.GetFilesystem: invalid message size: msize=%s", msizestr)
|
||||
ctx.Warningf("gofer.FilesystemType.GetFilesystem: invalid message size: %s=%s", moptMsize, msizestr)
|
||||
return nil, nil, syserror.EINVAL
|
||||
}
|
||||
fsopts.msize = uint32(msize)
|
||||
|
@ -366,34 +394,34 @@ func (fstype FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.Virt
|
|||
|
||||
// Parse the 9P protocol version.
|
||||
fsopts.version = p9.HighestVersionString()
|
||||
if version, ok := mopts["version"]; ok {
|
||||
delete(mopts, "version")
|
||||
if version, ok := mopts[moptVersion]; ok {
|
||||
delete(mopts, moptVersion)
|
||||
fsopts.version = version
|
||||
}
|
||||
|
||||
// Parse the dentry cache limit.
|
||||
fsopts.maxCachedDentries = 1000
|
||||
if str, ok := mopts["dentry_cache_limit"]; ok {
|
||||
delete(mopts, "dentry_cache_limit")
|
||||
if str, ok := mopts[moptDentryCacheLimit]; ok {
|
||||
delete(mopts, moptDentryCacheLimit)
|
||||
maxCachedDentries, err := strconv.ParseUint(str, 10, 64)
|
||||
if err != nil {
|
||||
ctx.Warningf("gofer.FilesystemType.GetFilesystem: invalid dentry cache limit: dentry_cache_limit=%s", str)
|
||||
ctx.Warningf("gofer.FilesystemType.GetFilesystem: invalid dentry cache limit: %s=%s", moptDentryCacheLimit, str)
|
||||
return nil, nil, syserror.EINVAL
|
||||
}
|
||||
fsopts.maxCachedDentries = maxCachedDentries
|
||||
}
|
||||
|
||||
// Handle simple flags.
|
||||
if _, ok := mopts["force_page_cache"]; ok {
|
||||
delete(mopts, "force_page_cache")
|
||||
if _, ok := mopts[moptForcePageCache]; ok {
|
||||
delete(mopts, moptForcePageCache)
|
||||
fsopts.forcePageCache = true
|
||||
}
|
||||
if _, ok := mopts["limit_host_fd_translation"]; ok {
|
||||
delete(mopts, "limit_host_fd_translation")
|
||||
if _, ok := mopts[moptLimitHostFDTranslation]; ok {
|
||||
delete(mopts, moptLimitHostFDTranslation)
|
||||
fsopts.limitHostFDTranslation = true
|
||||
}
|
||||
if _, ok := mopts["overlayfs_stale_read"]; ok {
|
||||
delete(mopts, "overlayfs_stale_read")
|
||||
if _, ok := mopts[moptOverlayfsStaleRead]; ok {
|
||||
delete(mopts, moptOverlayfsStaleRead)
|
||||
fsopts.overlayfsStaleRead = true
|
||||
}
|
||||
// fsopts.regularFilesUseSpecialFileFD can only be enabled by specifying
|
||||
|
@ -469,34 +497,34 @@ func (fstype FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.Virt
|
|||
|
||||
func getFDFromMountOptionsMap(ctx context.Context, mopts map[string]string) (int, error) {
|
||||
// Check that the transport is "fd".
|
||||
trans, ok := mopts["trans"]
|
||||
if !ok || trans != "fd" {
|
||||
ctx.Warningf("gofer.getFDFromMountOptionsMap: transport must be specified as 'trans=fd'")
|
||||
trans, ok := mopts[moptTransport]
|
||||
if !ok || trans != transportModeFD {
|
||||
ctx.Warningf("gofer.getFDFromMountOptionsMap: transport must be specified as '%s=%s'", moptTransport, transportModeFD)
|
||||
return -1, syserror.EINVAL
|
||||
}
|
||||
delete(mopts, "trans")
|
||||
delete(mopts, moptTransport)
|
||||
|
||||
// Check that read and write FDs are provided and identical.
|
||||
rfdstr, ok := mopts["rfdno"]
|
||||
rfdstr, ok := mopts[moptReadFD]
|
||||
if !ok {
|
||||
ctx.Warningf("gofer.getFDFromMountOptionsMap: read FD must be specified as 'rfdno=<file descriptor>'")
|
||||
ctx.Warningf("gofer.getFDFromMountOptionsMap: read FD must be specified as '%s=<file descriptor>'", moptReadFD)
|
||||
return -1, syserror.EINVAL
|
||||
}
|
||||
delete(mopts, "rfdno")
|
||||
delete(mopts, moptReadFD)
|
||||
rfd, err := strconv.Atoi(rfdstr)
|
||||
if err != nil {
|
||||
ctx.Warningf("gofer.getFDFromMountOptionsMap: invalid read FD: rfdno=%s", rfdstr)
|
||||
ctx.Warningf("gofer.getFDFromMountOptionsMap: invalid read FD: %s=%s", moptReadFD, rfdstr)
|
||||
return -1, syserror.EINVAL
|
||||
}
|
||||
wfdstr, ok := mopts["wfdno"]
|
||||
wfdstr, ok := mopts[moptWriteFD]
|
||||
if !ok {
|
||||
ctx.Warningf("gofer.getFDFromMountOptionsMap: write FD must be specified as 'wfdno=<file descriptor>'")
|
||||
ctx.Warningf("gofer.getFDFromMountOptionsMap: write FD must be specified as '%s=<file descriptor>'", moptWriteFD)
|
||||
return -1, syserror.EINVAL
|
||||
}
|
||||
delete(mopts, "wfdno")
|
||||
delete(mopts, moptWriteFD)
|
||||
wfd, err := strconv.Atoi(wfdstr)
|
||||
if err != nil {
|
||||
ctx.Warningf("gofer.getFDFromMountOptionsMap: invalid write FD: wfdno=%s", wfdstr)
|
||||
ctx.Warningf("gofer.getFDFromMountOptionsMap: invalid write FD: %s=%s", moptWriteFD, wfdstr)
|
||||
return -1, syserror.EINVAL
|
||||
}
|
||||
if rfd != wfd {
|
||||
|
|
|
@ -260,6 +260,11 @@ func (fs *filesystem) PrependPath(ctx context.Context, vfsroot, vd vfs.VirtualDe
|
|||
return vfs.PrependPathSyntheticError{}
|
||||
}
|
||||
|
||||
// MountOptions implements vfs.FilesystemImpl.MountOptions.
|
||||
func (fs *filesystem) MountOptions() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// CheckPermissions implements kernfs.Inode.CheckPermissions.
|
||||
func (i *inode) CheckPermissions(ctx context.Context, creds *auth.Credentials, ats vfs.AccessTypes) error {
|
||||
var s unix.Stat_t
|
||||
|
|
|
@ -67,6 +67,11 @@ type filesystem struct {
|
|||
kernfs.Filesystem
|
||||
}
|
||||
|
||||
// MountOptions implements vfs.FilesystemImpl.MountOptions.
|
||||
func (fs *filesystem) MountOptions() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
type file struct {
|
||||
kernfs.DynamicBytesFile
|
||||
content string
|
||||
|
|
|
@ -1764,3 +1764,15 @@ func (fs *filesystem) PrependPath(ctx context.Context, vfsroot, vd vfs.VirtualDe
|
|||
defer fs.renameMu.RUnlock()
|
||||
return genericPrependPath(vfsroot, vd.Mount(), vd.Dentry().Impl().(*dentry), b)
|
||||
}
|
||||
|
||||
// MountOptions implements vfs.FilesystemImpl.MountOptions.
|
||||
func (fs *filesystem) MountOptions() string {
|
||||
// Return the mount options from the topmost layer.
|
||||
var vd vfs.VirtualDentry
|
||||
if fs.opts.UpperRoot.Ok() {
|
||||
vd = fs.opts.UpperRoot
|
||||
} else {
|
||||
vd = fs.opts.LowerRoots[0]
|
||||
}
|
||||
return vd.Mount().Filesystem().Impl().MountOptions()
|
||||
}
|
||||
|
|
|
@ -80,6 +80,11 @@ func (fs *filesystem) PrependPath(ctx context.Context, vfsroot, vd vfs.VirtualDe
|
|||
return vfs.PrependPathSyntheticError{}
|
||||
}
|
||||
|
||||
// MountOptions implements vfs.FilesystemImpl.MountOptions.
|
||||
func (fs *filesystem) MountOptions() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// inode implements kernfs.Inode.
|
||||
//
|
||||
// +stateify savable
|
||||
|
|
|
@ -104,6 +104,11 @@ func (fs *filesystem) Release(ctx context.Context) {
|
|||
fs.Filesystem.Release(ctx)
|
||||
}
|
||||
|
||||
// MountOptions implements vfs.FilesystemImpl.MountOptions.
|
||||
func (fs *filesystem) MountOptions() string {
|
||||
return fmt.Sprintf("dentry_cache_limit=%d", fs.MaxCachedDentries)
|
||||
}
|
||||
|
||||
// dynamicInode is an overfitted interface for common Inodes with
|
||||
// dynamicByteSource types used in procfs.
|
||||
//
|
||||
|
|
|
@ -85,6 +85,11 @@ func (fs *filesystem) PrependPath(ctx context.Context, vfsroot, vd vfs.VirtualDe
|
|||
return vfs.PrependPathSyntheticError{}
|
||||
}
|
||||
|
||||
// MountOptions implements vfs.FilesystemImpl.MountOptions.
|
||||
func (fs *filesystem) MountOptions() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// inode implements kernfs.Inode.
|
||||
//
|
||||
// +stateify savable
|
||||
|
|
|
@ -143,6 +143,11 @@ func (fs *filesystem) Release(ctx context.Context) {
|
|||
fs.Filesystem.Release(ctx)
|
||||
}
|
||||
|
||||
// MountOptions implements vfs.FilesystemImpl.MountOptions.
|
||||
func (fs *filesystem) MountOptions() string {
|
||||
return fmt.Sprintf("dentry_cache_limit=%d", fs.MaxCachedDentries)
|
||||
}
|
||||
|
||||
// dir implements kernfs.Inode.
|
||||
//
|
||||
// +stateify savable
|
||||
|
|
|
@ -898,3 +898,8 @@ func (fs *filesystem) PrependPath(ctx context.Context, vfsroot, vd vfs.VirtualDe
|
|||
d = d.parent
|
||||
}
|
||||
}
|
||||
|
||||
// MountOptions implements vfs.FilesystemImpl.MountOptions.
|
||||
func (fs *filesystem) MountOptions() string {
|
||||
return fs.mopts
|
||||
}
|
||||
|
|
|
@ -70,6 +70,10 @@ type filesystem struct {
|
|||
// devMinor is the filesystem's minor device number. devMinor is immutable.
|
||||
devMinor uint32
|
||||
|
||||
// mopts contains the tmpfs-specific mount options passed to this
|
||||
// filesystem. Immutable.
|
||||
mopts string
|
||||
|
||||
// mu serializes changes to the Dentry tree.
|
||||
mu sync.RWMutex `state:"nosave"`
|
||||
|
||||
|
@ -184,6 +188,7 @@ func (fstype FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.Virt
|
|||
mfp: mfp,
|
||||
clock: clock,
|
||||
devMinor: devMinor,
|
||||
mopts: opts.Data,
|
||||
}
|
||||
fs.vfsfs.Init(vfsObj, newFSType, &fs)
|
||||
|
||||
|
|
|
@ -419,6 +419,11 @@ func (fs *filesystem) Release(ctx context.Context) {
|
|||
fs.lowerMount.DecRef(ctx)
|
||||
}
|
||||
|
||||
// MountOptions implements vfs.FilesystemImpl.MountOptions.
|
||||
func (fs *filesystem) MountOptions() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// dentry implements vfs.DentryImpl.
|
||||
//
|
||||
// +stateify savable
|
||||
|
|
|
@ -291,6 +291,11 @@ func (fs *anonFilesystem) PrependPath(ctx context.Context, vfsroot, vd VirtualDe
|
|||
return PrependPathSyntheticError{}
|
||||
}
|
||||
|
||||
// MountOptions implements FilesystemImpl.MountOptions.
|
||||
func (fs *anonFilesystem) MountOptions() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// IncRef implements DentryImpl.IncRef.
|
||||
func (d *anonDentry) IncRef() {
|
||||
// no-op
|
||||
|
|
|
@ -502,6 +502,15 @@ type FilesystemImpl interface {
|
|||
//
|
||||
// Preconditions: vd.Mount().Filesystem().Impl() == this FilesystemImpl.
|
||||
PrependPath(ctx context.Context, vfsroot, vd VirtualDentry, b *fspath.Builder) error
|
||||
|
||||
// MountOptions returns mount options for the current filesystem. This
|
||||
// should only return options specific to the filesystem (i.e. don't return
|
||||
// "ro", "rw", etc). Options should be returned as a comma-separated string,
|
||||
// similar to the input to the 5th argument to mount.
|
||||
//
|
||||
// If the implementation has no filesystem-specific options, it should
|
||||
// return the empty string.
|
||||
MountOptions() string
|
||||
}
|
||||
|
||||
// PrependPathAtVFSRootError is returned by implementations of
|
||||
|
|
|
@ -959,13 +959,17 @@ func manglePath(p string) string {
|
|||
// superBlockOpts returns the super block options string for the the mount at
|
||||
// the given path.
|
||||
func superBlockOpts(mountPath string, mnt *Mount) string {
|
||||
// gVisor doesn't (yet) have a concept of super block options, so we
|
||||
// use the ro/rw bit from the mount flag.
|
||||
// Compose super block options by combining global mount flags with
|
||||
// FS-specific mount options.
|
||||
opts := "rw"
|
||||
if mnt.ReadOnly() {
|
||||
opts = "ro"
|
||||
}
|
||||
|
||||
if mopts := mnt.fs.Impl().MountOptions(); mopts != "" {
|
||||
opts += "," + mopts
|
||||
}
|
||||
|
||||
// NOTE(b/147673608): If the mount is a cgroup, we also need to include
|
||||
// the cgroup name in the options. For now we just read that from the
|
||||
// path.
|
||||
|
|
|
@ -1601,12 +1601,12 @@ func TestReadonlyRoot(t *testing.T) {
|
|||
}
|
||||
|
||||
// Read mounts to check that root is readonly.
|
||||
out, err := executeCombinedOutput(c, "/bin/sh", "-c", "mount | grep ' / '")
|
||||
out, err := executeCombinedOutput(c, "/bin/sh", "-c", "mount | grep ' / ' | grep -o -e '(.*)'")
|
||||
if err != nil {
|
||||
t.Fatalf("exec failed: %v", err)
|
||||
}
|
||||
t.Logf("root mount: %q", out)
|
||||
if !strings.Contains(string(out), "(ro)") {
|
||||
t.Logf("root mount options: %q", out)
|
||||
if !strings.Contains(string(out), "ro") {
|
||||
t.Errorf("root not mounted readonly: %q", out)
|
||||
}
|
||||
|
||||
|
@ -1659,13 +1659,13 @@ func TestReadonlyMount(t *testing.T) {
|
|||
}
|
||||
|
||||
// Read mounts to check that volume is readonly.
|
||||
cmd := fmt.Sprintf("mount | grep ' %s '", dir)
|
||||
cmd := fmt.Sprintf("mount | grep ' %s ' | grep -o -e '(.*)'", dir)
|
||||
out, err := executeCombinedOutput(c, "/bin/sh", "-c", cmd)
|
||||
if err != nil {
|
||||
t.Fatalf("exec failed, err: %v", err)
|
||||
}
|
||||
t.Logf("mount: %q", out)
|
||||
if !strings.Contains(string(out), "(ro)") {
|
||||
t.Logf("mount options: %q", out)
|
||||
if !strings.Contains(string(out), "ro") {
|
||||
t.Errorf("volume not mounted readonly: %q", out)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue