github.com/scaleoutsean/fusego@v0.0.0-20220224074057-4a6429e46bb8/fuseutil/file_system.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 fuseutil 16 17 import ( 18 "context" 19 "io" 20 "sync" 21 22 "github.com/scaleoutsean/fusego" 23 "github.com/scaleoutsean/fusego/fuseops" 24 ) 25 26 // An interface with a method for each op type in the fuseops package. This can 27 // be used in conjunction with NewFileSystemServer to avoid writing a "dispatch 28 // loop" that switches on op types, instead receiving typed method calls 29 // directly. 30 // 31 // The FileSystem implementation should not call Connection.Reply, instead 32 // returning the error with which the caller should respond. 33 // 34 // See NotImplementedFileSystem for a convenient way to embed default 35 // implementations for methods you don't care about. 36 type FileSystem interface { 37 StatFS(context.Context, *fuseops.StatFSOp) error 38 LookUpInode(context.Context, *fuseops.LookUpInodeOp) error 39 GetInodeAttributes(context.Context, *fuseops.GetInodeAttributesOp) error 40 SetInodeAttributes(context.Context, *fuseops.SetInodeAttributesOp) error 41 ForgetInode(context.Context, *fuseops.ForgetInodeOp) error 42 MkDir(context.Context, *fuseops.MkDirOp) error 43 MkNode(context.Context, *fuseops.MkNodeOp) error 44 CreateFile(context.Context, *fuseops.CreateFileOp) error 45 CreateLink(context.Context, *fuseops.CreateLinkOp) error 46 CreateSymlink(context.Context, *fuseops.CreateSymlinkOp) error 47 Rename(context.Context, *fuseops.RenameOp) error 48 RmDir(context.Context, *fuseops.RmDirOp) error 49 Unlink(context.Context, *fuseops.UnlinkOp) error 50 OpenDir(context.Context, *fuseops.OpenDirOp) error 51 ReadDir(context.Context, *fuseops.ReadDirOp) error 52 ReleaseDirHandle(context.Context, *fuseops.ReleaseDirHandleOp) error 53 OpenFile(context.Context, *fuseops.OpenFileOp) error 54 ReadFile(context.Context, *fuseops.ReadFileOp) error 55 WriteFile(context.Context, *fuseops.WriteFileOp) error 56 SyncFile(context.Context, *fuseops.SyncFileOp) error 57 FlushFile(context.Context, *fuseops.FlushFileOp) error 58 ReleaseFileHandle(context.Context, *fuseops.ReleaseFileHandleOp) error 59 ReadSymlink(context.Context, *fuseops.ReadSymlinkOp) error 60 RemoveXattr(context.Context, *fuseops.RemoveXattrOp) error 61 GetXattr(context.Context, *fuseops.GetXattrOp) error 62 ListXattr(context.Context, *fuseops.ListXattrOp) error 63 SetXattr(context.Context, *fuseops.SetXattrOp) error 64 Fallocate(context.Context, *fuseops.FallocateOp) error 65 66 // Regard all inodes (including the root inode) as having their lookup counts 67 // decremented to zero, and clean up any resources associated with the file 68 // system. No further calls to the file system will be made. 69 Destroy() 70 } 71 72 // Create a fuse.Server that handles ops by calling the associated FileSystem 73 // method.Respond with the resulting error. Unsupported ops are responded to 74 // directly with ENOSYS. 75 // 76 // Each call to a FileSystem method (except ForgetInode) is made on 77 // its own goroutine, and is free to block. ForgetInode may be called 78 // synchronously, and should not depend on calls to other methods 79 // being received concurrently. 80 // 81 // (It is safe to naively process ops concurrently because the kernel 82 // guarantees to serialize operations that the user expects to happen in order, 83 // cf. http://goo.gl/jnkHPO, fuse-devel thread "Fuse guarantees on concurrent 84 // requests"). 85 func NewFileSystemServer(fs FileSystem) fuse.Server { 86 return &fileSystemServer{ 87 fs: fs, 88 } 89 } 90 91 type fileSystemServer struct { 92 fs FileSystem 93 opsInFlight sync.WaitGroup 94 } 95 96 func (s *fileSystemServer) ServeOps(c *fuse.Connection) { 97 // When we are done, we clean up by waiting for all in-flight ops then 98 // destroying the file system. 99 defer func() { 100 s.opsInFlight.Wait() 101 s.fs.Destroy() 102 }() 103 104 for { 105 ctx, op, err := c.ReadOp() 106 if err == io.EOF { 107 break 108 } 109 110 if err != nil { 111 panic(err) 112 } 113 114 s.opsInFlight.Add(1) 115 if _, ok := op.(*fuseops.ForgetInodeOp); ok { 116 // Special case: call in this goroutine for 117 // forget inode ops, which may come in a 118 // flurry from the kernel and are generally 119 // cheap for the file system to handle 120 s.handleOp(c, ctx, op) 121 } else { 122 go s.handleOp(c, ctx, op) 123 } 124 } 125 } 126 127 func (s *fileSystemServer) handleOp( 128 c *fuse.Connection, 129 ctx context.Context, 130 op interface{}) { 131 defer s.opsInFlight.Done() 132 133 // Dispatch to the appropriate method. 134 var err error 135 switch typed := op.(type) { 136 default: 137 err = fuse.ENOSYS 138 139 case *fuseops.StatFSOp: 140 err = s.fs.StatFS(ctx, typed) 141 142 case *fuseops.LookUpInodeOp: 143 err = s.fs.LookUpInode(ctx, typed) 144 145 case *fuseops.GetInodeAttributesOp: 146 err = s.fs.GetInodeAttributes(ctx, typed) 147 148 case *fuseops.SetInodeAttributesOp: 149 err = s.fs.SetInodeAttributes(ctx, typed) 150 151 case *fuseops.ForgetInodeOp: 152 err = s.fs.ForgetInode(ctx, typed) 153 154 case *fuseops.MkDirOp: 155 err = s.fs.MkDir(ctx, typed) 156 157 case *fuseops.MkNodeOp: 158 err = s.fs.MkNode(ctx, typed) 159 160 case *fuseops.CreateFileOp: 161 err = s.fs.CreateFile(ctx, typed) 162 163 case *fuseops.CreateLinkOp: 164 err = s.fs.CreateLink(ctx, typed) 165 166 case *fuseops.CreateSymlinkOp: 167 err = s.fs.CreateSymlink(ctx, typed) 168 169 case *fuseops.RenameOp: 170 err = s.fs.Rename(ctx, typed) 171 172 case *fuseops.RmDirOp: 173 err = s.fs.RmDir(ctx, typed) 174 175 case *fuseops.UnlinkOp: 176 err = s.fs.Unlink(ctx, typed) 177 178 case *fuseops.OpenDirOp: 179 err = s.fs.OpenDir(ctx, typed) 180 181 case *fuseops.ReadDirOp: 182 err = s.fs.ReadDir(ctx, typed) 183 184 case *fuseops.ReleaseDirHandleOp: 185 err = s.fs.ReleaseDirHandle(ctx, typed) 186 187 case *fuseops.OpenFileOp: 188 err = s.fs.OpenFile(ctx, typed) 189 190 case *fuseops.ReadFileOp: 191 err = s.fs.ReadFile(ctx, typed) 192 193 case *fuseops.WriteFileOp: 194 err = s.fs.WriteFile(ctx, typed) 195 196 case *fuseops.SyncFileOp: 197 err = s.fs.SyncFile(ctx, typed) 198 199 case *fuseops.FlushFileOp: 200 err = s.fs.FlushFile(ctx, typed) 201 202 case *fuseops.ReleaseFileHandleOp: 203 err = s.fs.ReleaseFileHandle(ctx, typed) 204 205 case *fuseops.ReadSymlinkOp: 206 err = s.fs.ReadSymlink(ctx, typed) 207 208 case *fuseops.RemoveXattrOp: 209 err = s.fs.RemoveXattr(ctx, typed) 210 211 case *fuseops.GetXattrOp: 212 err = s.fs.GetXattr(ctx, typed) 213 214 case *fuseops.ListXattrOp: 215 err = s.fs.ListXattr(ctx, typed) 216 217 case *fuseops.SetXattrOp: 218 err = s.fs.SetXattr(ctx, typed) 219 220 case *fuseops.FallocateOp: 221 err = s.fs.Fallocate(ctx, typed) 222 } 223 224 c.Reply(ctx, err) 225 }