github.com/scaleoutsean/fusego@v0.0.0-20220224074057-4a6429e46bb8/mount_config.go (about) 1 // Copyright 2015 Google Inc. All Rights Reserved. 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 fuse 16 17 import ( 18 "context" 19 "fmt" 20 "log" 21 "runtime" 22 "strings" 23 ) 24 25 // Optional configuration accepted by Mount. 26 type MountConfig struct { 27 // The context from which every op read from the connetion by the sever 28 // should inherit. If nil, context.Background() will be used. 29 OpContext context.Context 30 31 // If non-empty, the name of the file system as displayed by e.g. `mount`. 32 // This is important because the `umount` command requires root privileges if 33 // it doesn't agree with /etc/fstab. 34 FSName string 35 36 // Mount the file system in read-only mode. File modes will appear as normal, 37 // but opening a file for writing and metadata operations like chmod, 38 // chtimes, etc. will fail. 39 ReadOnly bool 40 41 // A logger to use for logging errors. All errors are logged, with the 42 // exception of a few blacklisted errors that are expected. If nil, no error 43 // logging is performed. 44 ErrorLogger *log.Logger 45 46 // A logger to use for logging debug information. If nil, no debug logging is 47 // performed. 48 DebugLogger *log.Logger 49 50 // Linux only. OS X always behaves as if writeback caching is disabled. 51 // 52 // By default on Linux we allow the kernel to perform writeback caching 53 // (cf. http://goo.gl/LdZzo1): 54 // 55 // * When the user calls write(2), the kernel sticks the user's data into 56 // its page cache. Only later does it call through to the file system, 57 // potentially after coalescing multiple small user writes. 58 // 59 // * The file system may receive multiple write ops from the kernel 60 // concurrently if there is a lot of page cache data to flush. 61 // 62 // * Write performance may be significantly improved due to the user and 63 // the kernel not waiting for serial round trips to the file system. This 64 // is especially true if the user makes tiny writes. 65 // 66 // * close(2) (and anything else calling f_op->flush) causes all dirty 67 // pages to be written out before it proceeds to send a FlushFileOp 68 // (cf. https://goo.gl/TMrY6X). 69 // 70 // * Similarly, close(2) causes the kernel to send a setattr request 71 // filling in the mtime if any dirty pages were flushed, since the time 72 // at which the pages were written to the file system can't be trusted. 73 // 74 // * close(2) (and anything else calling f_op->flush) writes out all dirty 75 // pages, then sends a setattr request with an appropriate mtime for 76 // those writes if there were any, and only then proceeds to send a 77 // flush. 78 // 79 // Code walk: 80 // 81 // * (https://goo.gl/zTIZQ9) fuse_flush calls write_inode_now before 82 // calling the file system. The latter eventually calls into 83 // __writeback_single_inode. 84 // 85 // * (https://goo.gl/L7Z2w5) __writeback_single_inode calls 86 // do_writepages, which writes out any dirty pages. 87 // 88 // * (https://goo.gl/DOPgla) __writeback_single_inode later calls 89 // write_inode, which calls into the superblock op struct's write_inode 90 // member. For fuse, this is fuse_write_inode 91 // (cf. https://goo.gl/eDSKOX). 92 // 93 // * (https://goo.gl/PbkGA1) fuse_write_inode calls fuse_flush_times. 94 // 95 // * (https://goo.gl/ig8x9V) fuse_flush_times sends a setttr request 96 // for setting the inode's mtime. 97 // 98 // However, this brings along some caveats: 99 // 100 // * The file system must handle SetInodeAttributesOp or close(2) will fail, 101 // due to the call chain into fuse_flush_times listed above. 102 // 103 // * The kernel caches mtime and ctime regardless of whether the file 104 // system tells it to do so, disregarding the result of further getattr 105 // requests (cf. https://goo.gl/3ZZMUw, https://goo.gl/7WtQUp). It 106 // appears this may be true of the file size, too. Writeback caching may 107 // therefore not be suitable for file systems where these attributes can 108 // spontaneously change for reasons the kernel doesn't observe. See 109 // http://goo.gl/V5WQCN for more discussion. 110 // 111 // Setting DisableWritebackCaching disables this behavior. Instead the file 112 // system is called one or more times for each write(2), and the user's 113 // syscall doesn't return until the file system returns. 114 DisableWritebackCaching bool 115 116 // OS X only. 117 // 118 // Normally on OS X we mount with the novncache option 119 // (cf. http://goo.gl/1pTjuk), which disables entry caching in the kernel. 120 // This is because osxfuse does not honor the entry expiration values we 121 // return to it, instead caching potentially forever (cf. 122 // http://goo.gl/8yR0Ie), and it is probably better to fail to cache than to 123 // cache for too long, since the latter is more likely to hide consistency 124 // bugs that are difficult to detect and diagnose. 125 // 126 // This field disables the use of novncache, restoring entry caching. Beware: 127 // the value of ChildInodeEntry.EntryExpiration is ignored by the kernel, and 128 // entries will be cached for an arbitrarily long time. 129 EnableVnodeCaching bool 130 131 // Linux only. 132 // 133 // Linux 4.20 introduced caching symlink targets in the page cache: 134 // https://github.com/torvalds/linux/commit/5571f1e65486be025f73fa6aa30fb03725d362a2 135 // 136 // This is not enabled by default because the old behavior masked a bug: 137 // file systems could return any size in the inode attributes of 138 // symlinks. After enabling caching, the specified size caps the symlink 139 // target. 140 EnableSymlinkCaching bool 141 142 // Linux only. 143 // 144 // Tell the kernel to treat returning -ENOSYS on OpenFile as not needing 145 // OpenFile calls at all (Linux >= 3.16): 146 EnableNoOpenSupport bool 147 148 // Linux only. 149 // 150 // Tell the kernel to treat returning -ENOSYS on OpenDir as not needing 151 // OpenDir calls at all (Linux >= 5.1): 152 EnableNoOpendirSupport bool 153 154 // OS X only. 155 // 156 // The name of the mounted volume, as displayed in the Finder. If empty, a 157 // default name involving the string 'osxfuse' is used. 158 VolumeName string 159 160 // Additional key=value options to pass unadulterated to the underlying mount 161 // command. See `man 8 mount`, the fuse documentation, etc. for 162 // system-specific information. 163 // 164 // For expert use only! May invalidate other guarantees made in the 165 // documentation for this package. 166 Options map[string]string 167 168 // Sets the filesystem type (third field in /etc/mtab). /etc/mtab and 169 // /proc/mounts will show the filesystem type as fuse.<Subtype>. 170 // If not set, /proc/mounts will show the filesystem type as fuse/fuseblk. 171 Subtype string 172 } 173 174 // Create a map containing all of the key=value mount options to be given to 175 // the mount helper. 176 func (c *MountConfig) toMap() (opts map[string]string) { 177 isDarwin := runtime.GOOS == "darwin" 178 opts = make(map[string]string) 179 180 // Enable permissions checking in the kernel. See the comments on 181 // InodeAttributes.Mode. 182 opts["default_permissions"] = "" 183 184 // HACK(jacobsa): Work around what appears to be a bug in systemd v219, as 185 // shipped in Ubuntu 15.04, where it automatically unmounts any file system 186 // that doesn't set an explicit name. 187 // 188 // When Ubuntu contains systemd v220, this workaround should be removed and 189 // the systemd bug reopened if the problem persists. 190 // 191 // Cf. https://github.com/bazil/fuse/issues/89 192 // Cf. https://bugs.freedesktop.org/show_bug.cgi?id=90907 193 fsname := c.FSName 194 if runtime.GOOS == "linux" && fsname == "" { 195 fsname = "some_fuse_file_system" 196 } 197 198 // Special file system name? 199 if fsname != "" { 200 opts["fsname"] = fsname 201 } 202 203 subtype := c.Subtype 204 if subtype != "" { 205 opts["subtype"] = subtype 206 } 207 208 // Read only? 209 if c.ReadOnly { 210 opts["ro"] = "" 211 } 212 213 // Handle OS X options. 214 if isDarwin { 215 if !c.EnableVnodeCaching { 216 opts["novncache"] = "" 217 } 218 219 if c.VolumeName != "" { 220 // Cf. https://github.com/osxfuse/osxfuse/wiki/Mount-options#volname 221 opts["volname"] = c.VolumeName 222 } 223 } 224 225 // OS X: disable the use of "Apple Double" (._foo and .DS_Store) files, which 226 // just add noise to debug output and can have significant cost on 227 // network-based file systems. 228 // 229 // Cf. https://github.com/osxfuse/osxfuse/wiki/Mount-options 230 if isDarwin { 231 opts["noappledouble"] = "" 232 } 233 234 // Last but not least: other user-supplied options. 235 for k, v := range c.Options { 236 opts[k] = v 237 } 238 239 return opts 240 } 241 242 func escapeOptionsKey(s string) (res string) { 243 res = s 244 res = strings.Replace(res, `\`, `\\`, -1) 245 res = strings.Replace(res, `,`, `\,`, -1) 246 return res 247 } 248 249 func mapToOptionsString(opts map[string]string) string { 250 var components []string 251 for k, v := range opts { 252 k = escapeOptionsKey(k) 253 254 component := k 255 if v != "" { 256 component = fmt.Sprintf("%s=%s", k, v) 257 } 258 259 components = append(components, component) 260 } 261 262 return strings.Join(components, ",") 263 } 264 265 // Create an options string suitable for passing to the mount helper. 266 func (c *MountConfig) toOptionsString() string { 267 return mapToOptionsString(c.toMap()) 268 }