github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fs/filesystems.go (about) 1 // Copyright 2018 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 fs 16 17 import ( 18 "fmt" 19 "sort" 20 "strings" 21 22 "github.com/SagerNet/gvisor/pkg/context" 23 "github.com/SagerNet/gvisor/pkg/sync" 24 ) 25 26 // FilesystemFlags matches include/linux/fs.h:file_system_type.fs_flags. 27 type FilesystemFlags int 28 29 const ( 30 // FilesystemRequiresDev indicates that the file system requires a device name 31 // on mount. It is used to construct the output of /proc/filesystems. 32 FilesystemRequiresDev FilesystemFlags = 1 33 34 // Currently other flags are not used, but can be pulled in from 35 // include/linux/fs.h:file_system_type as needed. 36 ) 37 38 // Filesystem is a mountable file system. 39 type Filesystem interface { 40 // Name is the unique identifier of the file system. It corresponds to the 41 // filesystemtype argument of sys_mount and will appear in the output of 42 // /proc/filesystems. 43 Name() string 44 45 // Flags indicate common properties of the file system. 46 Flags() FilesystemFlags 47 48 // Mount generates a mountable Inode backed by device and configured 49 // using file system independent flags and file system dependent 50 // data options. 51 // 52 // Mount may return arbitrary errors. They do not need syserr translations. 53 Mount(ctx context.Context, device string, flags MountSourceFlags, data string, dataObj interface{}) (*Inode, error) 54 55 // AllowUserMount determines whether mount(2) is allowed to mount a 56 // file system of this type. 57 AllowUserMount() bool 58 59 // AllowUserList determines whether this filesystem is listed in 60 // /proc/filesystems 61 AllowUserList() bool 62 } 63 64 // filesystems is the global set of registered file systems. It does not need 65 // to be saved. Packages registering and unregistering file systems must do so 66 // before calling save/restore methods. 67 var filesystems = struct { 68 // mu protects registered below. 69 mu sync.Mutex 70 71 // registered is a set of registered Filesystems. 72 registered map[string]Filesystem 73 }{ 74 registered: make(map[string]Filesystem), 75 } 76 77 // RegisterFilesystem registers a new file system that is visible to mount and 78 // the /proc/filesystems list. Packages implementing Filesystem should call 79 // RegisterFilesystem in init(). 80 func RegisterFilesystem(f Filesystem) { 81 filesystems.mu.Lock() 82 defer filesystems.mu.Unlock() 83 84 if _, ok := filesystems.registered[f.Name()]; ok { 85 panic(fmt.Sprintf("filesystem already registered at %q", f.Name())) 86 } 87 filesystems.registered[f.Name()] = f 88 } 89 90 // FindFilesystem returns a Filesystem registered at name or (nil, false) if name 91 // is not a file system type that can be found in /proc/filesystems. 92 func FindFilesystem(name string) (Filesystem, bool) { 93 filesystems.mu.Lock() 94 defer filesystems.mu.Unlock() 95 96 f, ok := filesystems.registered[name] 97 return f, ok 98 } 99 100 // GetFilesystems returns the set of registered filesystems in a consistent order. 101 func GetFilesystems() []Filesystem { 102 filesystems.mu.Lock() 103 defer filesystems.mu.Unlock() 104 105 var ss []Filesystem 106 for _, s := range filesystems.registered { 107 ss = append(ss, s) 108 } 109 sort.Slice(ss, func(i, j int) bool { return ss[i].Name() < ss[j].Name() }) 110 return ss 111 } 112 113 // MountSourceFlags represents all mount option flags as a struct. 114 // 115 // +stateify savable 116 type MountSourceFlags struct { 117 // ReadOnly corresponds to mount(2)'s "MS_RDONLY" and indicates that 118 // the filesystem should be mounted read-only. 119 ReadOnly bool 120 121 // NoAtime corresponds to mount(2)'s "MS_NOATIME" and indicates that 122 // the filesystem should not update access time in-place. 123 NoAtime bool 124 125 // ForcePageCache causes all filesystem I/O operations to use the page 126 // cache, even when the platform supports direct mapped I/O. This 127 // doesn't correspond to any Linux mount options. 128 ForcePageCache bool 129 130 // NoExec corresponds to mount(2)'s "MS_NOEXEC" and indicates that 131 // binaries from this file system can't be executed. 132 NoExec bool 133 } 134 135 // GenericMountSourceOptions splits a string containing comma separated tokens of the 136 // format 'key=value' or 'key' into a map of keys and values. For example: 137 // 138 // data = "key0=value0,key1,key2=value2" -> map{'key0':'value0','key1':'','key2':'value2'} 139 // 140 // If data contains duplicate keys, then the last token wins. 141 func GenericMountSourceOptions(data string) map[string]string { 142 options := make(map[string]string) 143 if len(data) == 0 { 144 // Don't return a nil map, callers might not be expecting that. 145 return options 146 } 147 148 // Parse options and skip empty ones. 149 for _, opt := range strings.Split(data, ",") { 150 if len(opt) > 0 { 151 res := strings.SplitN(opt, "=", 2) 152 if len(res) == 2 { 153 options[res[0]] = res[1] 154 } else { 155 options[opt] = "" 156 } 157 } 158 } 159 return options 160 }