github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/sentry/fsimpl/gofer/filesystem.go (about) 1 // Copyright 2019 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 gofer 16 17 import ( 18 "fmt" 19 "math" 20 "strings" 21 "sync" 22 23 "golang.org/x/sys/unix" 24 "github.com/nicocha30/gvisor-ligolo/pkg/abi/linux" 25 "github.com/nicocha30/gvisor-ligolo/pkg/atomicbitops" 26 "github.com/nicocha30/gvisor-ligolo/pkg/context" 27 "github.com/nicocha30/gvisor-ligolo/pkg/errors/linuxerr" 28 "github.com/nicocha30/gvisor-ligolo/pkg/fspath" 29 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/fsimpl/host" 30 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/fsmetric" 31 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/kernel" 32 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/kernel/auth" 33 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/kernel/pipe" 34 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/socket/unix/transport" 35 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/vfs" 36 ) 37 38 // Sync implements vfs.FilesystemImpl.Sync. 39 func (fs *filesystem) Sync(ctx context.Context) error { 40 // Snapshot current syncable dentries and special file FDs. 41 fs.syncMu.Lock() 42 ds := make([]*dentry, 0, fs.syncableDentries.Len()) 43 for elem := fs.syncableDentries.Front(); elem != nil; elem = elem.Next() { 44 ds = append(ds, elem.d) 45 } 46 sffds := make([]*specialFileFD, 0, fs.specialFileFDs.Len()) 47 for sffd := fs.specialFileFDs.Front(); sffd != nil; sffd = sffd.Next() { 48 sffds = append(sffds, sffd) 49 } 50 fs.syncMu.Unlock() 51 52 // Return the first error we encounter, but sync everything we can 53 // regardless. 54 var retErr error 55 56 // Note that lisafs is capable of batching FSync RPCs. However, we can not 57 // batch all the FDIDs to be synced from ds and sffds. Because the error 58 // handling varies based on file type. FSync errors are only considered for 59 // regular file FDIDs that were opened for writing. We could do individual 60 // RPCs for such FDIDs and batch the rest, but it increases code complexity 61 // substantially. We could implement it in the future if need be. 62 63 // Sync syncable dentries. 64 for _, d := range ds { 65 if err := d.syncCachedFile(ctx, true /* forFilesystemSync */); err != nil { 66 ctx.Infof("gofer.filesystem.Sync: dentry.syncCachedFile failed: %v", err) 67 if retErr == nil { 68 retErr = err 69 } 70 } 71 } 72 73 // Sync special files, which may be writable but do not use dentry shared 74 // handles (so they won't be synced by the above). 75 for _, sffd := range sffds { 76 if err := sffd.sync(ctx, true /* forFilesystemSync */); err != nil { 77 ctx.Infof("gofer.filesystem.Sync: specialFileFD.sync failed: %v", err) 78 if retErr == nil { 79 retErr = err 80 } 81 } 82 } 83 84 return retErr 85 } 86 87 // MaxFilenameLen is the maximum length of a filename. This is dictated by 9P's 88 // encoding of strings, which uses 2 bytes for the length prefix. 89 const MaxFilenameLen = (1 << 16) - 1 90 91 // dentrySlicePool is a pool of *[]*dentry used to store dentries for which 92 // dentry.checkCachingLocked() must be called. The pool holds pointers to 93 // slices because Go lacks generics, so sync.Pool operates on any, so 94 // every call to (what should be) sync.Pool<[]*dentry>.Put() allocates a copy 95 // of the slice header on the heap. 96 var dentrySlicePool = sync.Pool{ 97 New: func() any { 98 ds := make([]*dentry, 0, 4) // arbitrary non-zero initial capacity 99 return &ds 100 }, 101 } 102 103 func appendDentry(ds *[]*dentry, d *dentry) *[]*dentry { 104 if ds == nil { 105 ds = dentrySlicePool.Get().(*[]*dentry) 106 } 107 *ds = append(*ds, d) 108 return ds 109 } 110 111 // Precondition: !parent.isSynthetic() && !child.isSynthetic(). 112 func appendNewChildDentry(ds **[]*dentry, parent *dentry, child *dentry) { 113 // The new child was added to parent and took a ref on the parent (hence 114 // parent can be removed from cache). A new child has 0 refs for now. So 115 // checkCachingLocked() should be called on both. Call it first on the parent 116 // as it may create space in the cache for child to be inserted - hence 117 // avoiding a cache eviction. 118 *ds = appendDentry(*ds, parent) 119 *ds = appendDentry(*ds, child) 120 } 121 122 // Preconditions: ds != nil. 123 func putDentrySlice(ds *[]*dentry) { 124 // Allow dentries to be GC'd. 125 for i := range *ds { 126 (*ds)[i] = nil 127 } 128 *ds = (*ds)[:0] 129 dentrySlicePool.Put(ds) 130 } 131 132 // renameMuRUnlockAndCheckCaching calls fs.renameMu.RUnlock(), then calls 133 // dentry.checkCachingLocked on all dentries in *dsp with fs.renameMu locked 134 // for writing. 135 // 136 // dsp is a pointer-to-pointer since defer evaluates its arguments immediately, 137 // but dentry slices are allocated lazily, and it's much easier to say "defer 138 // fs.renameMuRUnlockAndCheckCaching(&ds)" than "defer func() { 139 // fs.renameMuRUnlockAndCheckCaching(ds) }()" to work around this. 140 // +checklocksreleaseread:fs.renameMu 141 func (fs *filesystem) renameMuRUnlockAndCheckCaching(ctx context.Context, dsp **[]*dentry) { 142 fs.renameMu.RUnlock() 143 if *dsp == nil { 144 return 145 } 146 ds := **dsp 147 for _, d := range ds { 148 d.checkCachingLocked(ctx, false /* renameMuWriteLocked */) 149 } 150 putDentrySlice(*dsp) 151 } 152 153 // +checklocksrelease:fs.renameMu 154 func (fs *filesystem) renameMuUnlockAndCheckCaching(ctx context.Context, ds **[]*dentry) { 155 if *ds == nil { 156 fs.renameMu.Unlock() 157 return 158 } 159 for _, d := range **ds { 160 d.checkCachingLocked(ctx, true /* renameMuWriteLocked */) 161 } 162 fs.renameMu.Unlock() 163 putDentrySlice(*ds) 164 } 165 166 // stepLocked resolves rp.Component() to an existing file, starting from the 167 // given directory. 168 // 169 // Dentries which may become cached as a result of the traversal are appended 170 // to *ds. 171 // 172 // Preconditions: 173 // - fs.renameMu must be locked. 174 // - d.opMu must be locked for reading. 175 // - !rp.Done(). 176 // - If !d.cachedMetadataAuthoritative(), then d and all children that are 177 // part of rp must have been revalidated. 178 // 179 // +checklocksread:d.opMu 180 func (fs *filesystem) stepLocked(ctx context.Context, rp resolvingPath, d *dentry, mayFollowSymlinks bool, ds **[]*dentry) (*dentry, bool, error) { 181 if !d.isDir() { 182 return nil, false, linuxerr.ENOTDIR 183 } 184 if err := d.checkPermissions(rp.Credentials(), vfs.MayExec); err != nil { 185 return nil, false, err 186 } 187 name := rp.Component() 188 if name == "." { 189 rp.Advance() 190 return d, false, nil 191 } 192 if name == ".." { 193 if isRoot, err := rp.CheckRoot(ctx, &d.vfsd); err != nil { 194 return nil, false, err 195 } else if isRoot || d.parent == nil { 196 rp.Advance() 197 return d, false, nil 198 } 199 if err := rp.CheckMount(ctx, &d.parent.vfsd); err != nil { 200 return nil, false, err 201 } 202 rp.Advance() 203 return d.parent, false, nil 204 } 205 child, err := fs.getChildAndWalkPathLocked(ctx, d, rp, ds) 206 if err != nil { 207 return nil, false, err 208 } 209 if err := rp.CheckMount(ctx, &child.vfsd); err != nil { 210 return nil, false, err 211 } 212 if child.isSymlink() && mayFollowSymlinks && rp.ShouldFollowSymlink() { 213 target, err := child.readlink(ctx, rp.Mount()) 214 if err != nil { 215 return nil, false, err 216 } 217 followedSymlink, err := rp.HandleSymlink(target) 218 return d, followedSymlink, err 219 } 220 rp.Advance() 221 return child, false, nil 222 } 223 224 // getChildLocked returns a dentry representing the child of parent with the 225 // given name. Returns ENOENT if the child doesn't exist. 226 // 227 // Preconditions: 228 // - fs.renameMu must be locked. 229 // - parent.opMu must be locked. 230 // - parent.isDir(). 231 // - name is not "." or "..". 232 // - parent and the dentry at name have been revalidated. 233 // 234 // +checklocks:parent.opMu 235 func (fs *filesystem) getChildLocked(ctx context.Context, parent *dentry, name string, ds **[]*dentry) (*dentry, error) { 236 if child, err := parent.getCachedChildLocked(name); child != nil || err != nil { 237 return child, err 238 } 239 // We don't need to check for race here because parent.opMu is held for 240 // writing. 241 return fs.getRemoteChildLocked(ctx, parent, name, false /* checkForRace */, ds) 242 } 243 244 // getRemoteChildLocked is similar to getChildLocked, with the additional 245 // precondition that the child identified by name does not exist in cache. 246 // 247 // If checkForRace argument is true, then this method will check to see if the 248 // call has raced with another getRemoteChild call, and will handle the race if 249 // so. 250 // 251 // Preconditions: 252 // - If checkForRace is false, then parent.opMu must be held for writing. 253 // - Otherwise, parent.opMu must be held for reading. 254 // 255 // Postcondition: The returned dentry is already cached appropriately. 256 // 257 // +checklocksread:parent.opMu 258 func (fs *filesystem) getRemoteChildLocked(ctx context.Context, parent *dentry, name string, checkForRace bool, ds **[]*dentry) (*dentry, error) { 259 child, err := parent.getRemoteChild(ctx, name) 260 // Cache the result appropriately in the dentry tree. 261 if err != nil { 262 if linuxerr.Equals(linuxerr.ENOENT, err) { 263 parent.childrenMu.Lock() 264 defer parent.childrenMu.Unlock() 265 parent.cacheNegativeLookupLocked(name) 266 } 267 return nil, err 268 } 269 270 parent.childrenMu.Lock() 271 defer parent.childrenMu.Unlock() 272 273 if checkForRace { 274 // See if we raced with anoter getRemoteChild call that added 275 // to the cache. 276 if cachedChild, ok := parent.children[name]; ok && cachedChild != nil { 277 // We raced. Destroy our child and return the cached 278 // one. This child has no handles, no data, and has not 279 // been cached, so destruction is quick and painless. 280 child.destroyDisconnected(ctx) 281 282 // All good. Return the cached child. 283 return cachedChild, nil 284 } 285 // No race, continue with the child we got. 286 } 287 parent.cacheNewChildLocked(child, name) 288 appendNewChildDentry(ds, parent, child) 289 return child, nil 290 } 291 292 // getChildAndWalkPathLocked is the same as getChildLocked, except that it 293 // may prefetch the entire path represented by rp. 294 // 295 // +checklocksread:parent.opMu 296 func (fs *filesystem) getChildAndWalkPathLocked(ctx context.Context, parent *dentry, rp resolvingPath, ds **[]*dentry) (*dentry, error) { 297 if child, err := parent.getCachedChildLocked(rp.Component()); child != nil || err != nil { 298 return child, err 299 } 300 // dentry.getRemoteChildAndWalkPathLocked already handles dentry caching. 301 return parent.getRemoteChildAndWalkPathLocked(ctx, rp, ds) 302 } 303 304 // getCachedChildLocked returns a child dentry if it was cached earlier. If no 305 // cached child dentry exists, (nil, nil) is returned. 306 // 307 // Preconditions: 308 // - fs.renameMu must be locked. 309 // - d.opMu must be locked for reading. 310 // - d.isDir(). 311 // - name is not "." or "..". 312 // - d and the dentry at name have been revalidated. 313 // 314 // +checklocksread:d.opMu 315 func (d *dentry) getCachedChildLocked(name string) (*dentry, error) { 316 if len(name) > MaxFilenameLen { 317 return nil, linuxerr.ENAMETOOLONG 318 } 319 d.childrenMu.Lock() 320 defer d.childrenMu.Unlock() 321 if child, ok := d.children[name]; ok || d.isSynthetic() { 322 if child == nil { 323 return nil, linuxerr.ENOENT 324 } 325 return child, nil 326 } 327 328 if d.childrenSet != nil { 329 // Is the child even there? Don't make RPC if not. 330 if _, ok := d.childrenSet[name]; !ok { 331 return nil, linuxerr.ENOENT 332 } 333 } 334 return nil, nil 335 } 336 337 // walkParentDirLocked resolves all but the last path component of rp to an 338 // existing directory, starting from the given directory (which is usually 339 // rp.Start().Impl().(*dentry)). It does not check that the returned directory 340 // is searchable by the provider of rp. 341 // 342 // Preconditions: 343 // - fs.renameMu must be locked. 344 // - !rp.Done(). 345 // - If !d.cachedMetadataAuthoritative(), then d's cached metadata must be up 346 // to date. 347 func (fs *filesystem) walkParentDirLocked(ctx context.Context, vfsRP *vfs.ResolvingPath, d *dentry, ds **[]*dentry) (*dentry, error) { 348 rp := resolvingPathParent(vfsRP) 349 if err := fs.revalidatePath(ctx, rp, d, ds); err != nil { 350 return nil, err 351 } 352 for !rp.done() { 353 d.opMu.RLock() 354 next, followedSymlink, err := fs.stepLocked(ctx, rp, d, true /* mayFollowSymlinks */, ds) 355 d.opMu.RUnlock() 356 if err != nil { 357 return nil, err 358 } 359 d = next 360 if followedSymlink { 361 if err := fs.revalidatePath(ctx, rp, d, ds); err != nil { 362 return nil, err 363 } 364 } 365 } 366 if !d.isDir() { 367 return nil, linuxerr.ENOTDIR 368 } 369 return d, nil 370 } 371 372 // resolveLocked resolves rp to an existing file. 373 // 374 // Preconditions: fs.renameMu must be locked. 375 func (fs *filesystem) resolveLocked(ctx context.Context, vfsRP *vfs.ResolvingPath, ds **[]*dentry) (*dentry, error) { 376 rp := resolvingPathFull(vfsRP) 377 d := rp.Start().Impl().(*dentry) 378 if err := fs.revalidatePath(ctx, rp, d, ds); err != nil { 379 return nil, err 380 } 381 for !rp.done() { 382 d.opMu.RLock() 383 next, followedSymlink, err := fs.stepLocked(ctx, rp, d, true /* mayFollowSymlinks */, ds) 384 d.opMu.RUnlock() 385 if err != nil { 386 return nil, err 387 } 388 d = next 389 if followedSymlink { 390 if err := fs.revalidatePath(ctx, rp, d, ds); err != nil { 391 return nil, err 392 } 393 } 394 } 395 if rp.MustBeDir() && !d.isDir() { 396 return nil, linuxerr.ENOTDIR 397 } 398 return d, nil 399 } 400 401 // doCreateAt checks that creating a file at rp is permitted, then invokes 402 // createInRemoteDir (if the parent directory is a real remote directory) or 403 // createInSyntheticDir (if the parent directory is synthetic) to do so. 404 // 405 // Preconditions: 406 // - !rp.Done(). 407 // - For the final path component in rp, !rp.ShouldFollowSymlink(). 408 func (fs *filesystem) doCreateAt(ctx context.Context, rp *vfs.ResolvingPath, dir bool, createInRemoteDir func(parent *dentry, name string, ds **[]*dentry) (*dentry, error), createInSyntheticDir func(parent *dentry, name string) (*dentry, error)) error { 409 var ds *[]*dentry 410 fs.renameMu.RLock() 411 defer fs.renameMuRUnlockAndCheckCaching(ctx, &ds) 412 start := rp.Start().Impl().(*dentry) 413 parent, err := fs.walkParentDirLocked(ctx, rp, start, &ds) 414 if err != nil { 415 return err 416 } 417 418 // Order of checks is important. First check if parent directory can be 419 // executed, then check for existence, and lastly check if mount is writable. 420 if err := parent.checkPermissions(rp.Credentials(), vfs.MayExec); err != nil { 421 return err 422 } 423 name := rp.Component() 424 if name == "." || name == ".." { 425 return linuxerr.EEXIST 426 } 427 if parent.isDeleted() { 428 return linuxerr.ENOENT 429 } 430 if err := fs.revalidateOne(ctx, rp.VirtualFilesystem(), parent, name, &ds); err != nil { 431 return err 432 } 433 434 parent.opMu.Lock() 435 defer parent.opMu.Unlock() 436 437 if len(name) > MaxFilenameLen { 438 return linuxerr.ENAMETOOLONG 439 } 440 // Check for existence only if caching information is available. Otherwise, 441 // don't check for existence just yet. We will check for existence if the 442 // checks for writability fail below. Existence check is done by the creation 443 // RPCs themselves. 444 parent.childrenMu.Lock() 445 if child, ok := parent.children[name]; ok && child != nil { 446 parent.childrenMu.Unlock() 447 return linuxerr.EEXIST 448 } 449 if parent.childrenSet != nil { 450 if _, ok := parent.childrenSet[name]; ok { 451 parent.childrenMu.Unlock() 452 return linuxerr.EEXIST 453 } 454 } 455 parent.childrenMu.Unlock() 456 checkExistence := func() error { 457 if child, err := fs.getChildLocked(ctx, parent, name, &ds); err != nil && !linuxerr.Equals(linuxerr.ENOENT, err) { 458 return err 459 } else if child != nil { 460 return linuxerr.EEXIST 461 } 462 return nil 463 } 464 465 mnt := rp.Mount() 466 if err := mnt.CheckBeginWrite(); err != nil { 467 // Existence check takes precedence. 468 if existenceErr := checkExistence(); existenceErr != nil { 469 return existenceErr 470 } 471 return err 472 } 473 defer mnt.EndWrite() 474 475 if err := parent.checkPermissions(rp.Credentials(), vfs.MayWrite); err != nil { 476 // Existence check takes precedence. 477 if existenceErr := checkExistence(); existenceErr != nil { 478 return existenceErr 479 } 480 return err 481 } 482 if !dir && rp.MustBeDir() { 483 return linuxerr.ENOENT 484 } 485 if parent.isSynthetic() { 486 if createInSyntheticDir == nil { 487 return linuxerr.EPERM 488 } 489 child, err := createInSyntheticDir(parent, name) 490 if err != nil { 491 return err 492 } 493 parent.childrenMu.Lock() 494 parent.cacheNewChildLocked(child, name) 495 parent.syntheticChildren++ 496 parent.clearDirentsLocked() 497 parent.childrenMu.Unlock() 498 parent.touchCMtime() 499 ev := linux.IN_CREATE 500 if dir { 501 ev |= linux.IN_ISDIR 502 } 503 parent.watches.Notify(ctx, name, uint32(ev), 0, vfs.InodeEvent, false /* unlinked */) 504 return nil 505 } 506 // No cached dentry exists; however, in InteropModeShared there might still be 507 // an existing file at name. Just attempt the file creation RPC anyways. If a 508 // file does exist, the RPC will fail with EEXIST like we would have. 509 child, err := createInRemoteDir(parent, name, &ds) 510 if err != nil { 511 return err 512 } 513 parent.childrenMu.Lock() 514 parent.cacheNewChildLocked(child, name) 515 if child.isSynthetic() { 516 parent.syntheticChildren++ 517 ds = appendDentry(ds, parent) 518 } else { 519 appendNewChildDentry(&ds, parent, child) 520 } 521 if fs.opts.interop != InteropModeShared { 522 if child, ok := parent.children[name]; ok && child == nil { 523 // Delete the now-stale negative dentry. 524 delete(parent.children, name) 525 parent.negativeChildren-- 526 } 527 parent.clearDirentsLocked() 528 parent.touchCMtime() 529 } 530 parent.childrenMu.Unlock() 531 ev := linux.IN_CREATE 532 if dir { 533 ev |= linux.IN_ISDIR 534 } 535 parent.watches.Notify(ctx, name, uint32(ev), 0, vfs.InodeEvent, false /* unlinked */) 536 return nil 537 } 538 539 // Preconditions: !rp.Done(). 540 func (fs *filesystem) unlinkAt(ctx context.Context, rp *vfs.ResolvingPath, dir bool) error { 541 var ds *[]*dentry 542 fs.renameMu.RLock() 543 defer fs.renameMuRUnlockAndCheckCaching(ctx, &ds) 544 start := rp.Start().Impl().(*dentry) 545 parent, err := fs.walkParentDirLocked(ctx, rp, start, &ds) 546 if err != nil { 547 return err 548 } 549 if err := parent.checkPermissions(rp.Credentials(), vfs.MayWrite|vfs.MayExec); err != nil { 550 return err 551 } 552 if err := rp.Mount().CheckBeginWrite(); err != nil { 553 return err 554 } 555 defer rp.Mount().EndWrite() 556 557 name := rp.Component() 558 if dir { 559 if name == "." { 560 return linuxerr.EINVAL 561 } 562 if name == ".." { 563 return linuxerr.ENOTEMPTY 564 } 565 } else { 566 if name == "." || name == ".." { 567 return linuxerr.EISDIR 568 } 569 } 570 571 vfsObj := rp.VirtualFilesystem() 572 if err := fs.revalidateOne(ctx, vfsObj, parent, rp.Component(), &ds); err != nil { 573 return err 574 } 575 576 mntns := vfs.MountNamespaceFromContext(ctx) 577 defer mntns.DecRef(ctx) 578 579 parent.opMu.Lock() 580 defer parent.opMu.Unlock() 581 582 parent.childrenMu.Lock() 583 if parent.childrenSet != nil { 584 if _, ok := parent.childrenSet[name]; !ok { 585 parent.childrenMu.Unlock() 586 return linuxerr.ENOENT 587 } 588 } 589 parent.childrenMu.Unlock() 590 591 // Load child if sticky bit is set because we need to determine whether 592 // deletion is allowed. 593 var child *dentry 594 if parent.mode.Load()&linux.ModeSticky == 0 { 595 var ok bool 596 parent.childrenMu.Lock() 597 child, ok = parent.children[name] 598 parent.childrenMu.Unlock() 599 if ok && child == nil { 600 // Hit a negative cached entry, child doesn't exist. 601 return linuxerr.ENOENT 602 } 603 } else { 604 child, _, err = fs.stepLocked(ctx, resolvingPathFull(rp), parent, false /* mayFollowSymlinks */, &ds) 605 if err != nil { 606 return err 607 } 608 if err := parent.mayDelete(rp.Credentials(), child); err != nil { 609 return err 610 } 611 } 612 613 // If a child dentry exists, prepare to delete it. This should fail if it is 614 // a mount point. We detect mount points by speculatively calling 615 // PrepareDeleteDentry, which fails if child is a mount point. 616 // 617 // Also note that if child is nil, then it can't be a mount point. 618 if child != nil { 619 // Hold child.childrenMu so we can check child.children and 620 // child.syntheticChildren. We don't access these fields until a bit later, 621 // but locking child.childrenMu after calling vfs.PrepareDeleteDentry() would 622 // create an inconsistent lock ordering between dentry.childrenMu and 623 // vfs.Dentry.mu (in the VFS lock order, it would make dentry.childrenMu both "a 624 // FilesystemImpl lock" and "a lock acquired by a FilesystemImpl between 625 // PrepareDeleteDentry and CommitDeleteDentry). To avoid this, lock 626 // child.childrenMu before calling PrepareDeleteDentry. 627 child.childrenMu.Lock() 628 defer child.childrenMu.Unlock() 629 if err := vfsObj.PrepareDeleteDentry(mntns, &child.vfsd); err != nil { 630 return err 631 } 632 } 633 flags := uint32(0) 634 // If a dentry exists, use it for best-effort checks on its deletability. 635 if dir { 636 if child != nil { 637 // child must be an empty directory. 638 if child.syntheticChildren != 0 { // +checklocksforce: child.childrenMu is held if child != nil. 639 // This is definitely not an empty directory, irrespective of 640 // fs.opts.interop. 641 vfsObj.AbortDeleteDentry(&child.vfsd) // +checklocksforce: PrepareDeleteDentry called if child != nil. 642 return linuxerr.ENOTEMPTY 643 } 644 // If InteropModeShared is in effect and the first call to 645 // PrepareDeleteDentry above succeeded, then child wasn't 646 // revalidated (so we can't expect its file type to be correct) and 647 // individually revalidating its children (to confirm that they 648 // still exist) would be a waste of time. 649 if child.cachedMetadataAuthoritative() { 650 if !child.isDir() { 651 vfsObj.AbortDeleteDentry(&child.vfsd) // +checklocksforce: see above. 652 return linuxerr.ENOTDIR 653 } 654 for _, grandchild := range child.children { // +checklocksforce: child.childrenMu is held if child != nil. 655 if grandchild != nil { 656 vfsObj.AbortDeleteDentry(&child.vfsd) // +checklocksforce: see above. 657 return linuxerr.ENOTEMPTY 658 } 659 } 660 } 661 } 662 flags = linux.AT_REMOVEDIR 663 } else { 664 // child must be a non-directory file. 665 if child != nil && child.isDir() { 666 vfsObj.AbortDeleteDentry(&child.vfsd) // +checklocksforce: see above. 667 return linuxerr.EISDIR 668 } 669 if rp.MustBeDir() { 670 if child != nil { 671 vfsObj.AbortDeleteDentry(&child.vfsd) // +checklocksforce: see above. 672 } 673 return linuxerr.ENOTDIR 674 } 675 } 676 if parent.isSynthetic() { 677 if child == nil { 678 return linuxerr.ENOENT 679 } 680 } else if child == nil || !child.isSynthetic() { 681 if err := parent.unlink(ctx, name, flags); err != nil { 682 if child != nil { 683 vfsObj.AbortDeleteDentry(&child.vfsd) // +checklocksforce: see above. 684 } 685 return err 686 } 687 } 688 689 // Generate inotify events for rmdir or unlink. 690 if dir { 691 parent.watches.Notify(ctx, name, linux.IN_DELETE|linux.IN_ISDIR, 0, vfs.InodeEvent, true /* unlinked */) 692 } else { 693 var cw *vfs.Watches 694 if child != nil { 695 cw = &child.watches 696 } 697 vfs.InotifyRemoveChild(ctx, cw, &parent.watches, name) 698 } 699 700 parent.childrenMu.Lock() 701 defer parent.childrenMu.Unlock() 702 703 if child != nil { 704 vfsObj.CommitDeleteDentry(ctx, &child.vfsd) // +checklocksforce: see above. 705 child.setDeleted() 706 if child.isSynthetic() { 707 parent.syntheticChildren-- 708 child.decRefNoCaching() 709 } 710 ds = appendDentry(ds, child) 711 } 712 parent.cacheNegativeLookupLocked(name) 713 if parent.cachedMetadataAuthoritative() { 714 parent.clearDirentsLocked() 715 parent.touchCMtime() 716 if dir { 717 parent.decLinks() 718 } 719 } 720 return nil 721 } 722 723 // AccessAt implements vfs.Filesystem.Impl.AccessAt. 724 func (fs *filesystem) AccessAt(ctx context.Context, rp *vfs.ResolvingPath, creds *auth.Credentials, ats vfs.AccessTypes) error { 725 var ds *[]*dentry 726 fs.renameMu.RLock() 727 defer fs.renameMuRUnlockAndCheckCaching(ctx, &ds) 728 d, err := fs.resolveLocked(ctx, rp, &ds) 729 if err != nil { 730 return err 731 } 732 if err := d.checkPermissions(creds, ats); err != nil { 733 return err 734 } 735 if ats.MayWrite() && rp.Mount().ReadOnly() { 736 return linuxerr.EROFS 737 } 738 return nil 739 } 740 741 // GetDentryAt implements vfs.FilesystemImpl.GetDentryAt. 742 func (fs *filesystem) GetDentryAt(ctx context.Context, rp *vfs.ResolvingPath, opts vfs.GetDentryOptions) (*vfs.Dentry, error) { 743 var ds *[]*dentry 744 fs.renameMu.RLock() 745 defer fs.renameMuRUnlockAndCheckCaching(ctx, &ds) 746 d, err := fs.resolveLocked(ctx, rp, &ds) 747 if err != nil { 748 return nil, err 749 } 750 if opts.CheckSearchable { 751 if !d.isDir() { 752 return nil, linuxerr.ENOTDIR 753 } 754 if err := d.checkPermissions(rp.Credentials(), vfs.MayExec); err != nil { 755 return nil, err 756 } 757 } 758 d.IncRef() 759 // Call d.checkCachingLocked() so it can be removed from the cache if needed. 760 ds = appendDentry(ds, d) 761 return &d.vfsd, nil 762 } 763 764 // GetParentDentryAt implements vfs.FilesystemImpl.GetParentDentryAt. 765 func (fs *filesystem) GetParentDentryAt(ctx context.Context, rp *vfs.ResolvingPath) (*vfs.Dentry, error) { 766 var ds *[]*dentry 767 fs.renameMu.RLock() 768 defer fs.renameMuRUnlockAndCheckCaching(ctx, &ds) 769 start := rp.Start().Impl().(*dentry) 770 d, err := fs.walkParentDirLocked(ctx, rp, start, &ds) 771 if err != nil { 772 return nil, err 773 } 774 d.IncRef() 775 // Call d.checkCachingLocked() so it can be removed from the cache if needed. 776 ds = appendDentry(ds, d) 777 return &d.vfsd, nil 778 } 779 780 // LinkAt implements vfs.FilesystemImpl.LinkAt. 781 func (fs *filesystem) LinkAt(ctx context.Context, rp *vfs.ResolvingPath, vd vfs.VirtualDentry) error { 782 err := fs.doCreateAt(ctx, rp, false /* dir */, func(parent *dentry, name string, ds **[]*dentry) (*dentry, error) { 783 if rp.Mount() != vd.Mount() { 784 return nil, linuxerr.EXDEV 785 } 786 d := vd.Dentry().Impl().(*dentry) 787 if d.isDir() { 788 return nil, linuxerr.EPERM 789 } 790 gid := auth.KGID(d.gid.Load()) 791 uid := auth.KUID(d.uid.Load()) 792 mode := linux.FileMode(d.mode.Load()) 793 if err := vfs.MayLink(rp.Credentials(), mode, uid, gid); err != nil { 794 return nil, err 795 } 796 if d.nlink.Load() == 0 { 797 return nil, linuxerr.ENOENT 798 } 799 if d.nlink.Load() == math.MaxUint32 { 800 return nil, linuxerr.EMLINK 801 } 802 return parent.link(ctx, d, name) 803 }, nil) 804 805 if err == nil { 806 // Success! 807 vd.Dentry().Impl().(*dentry).incLinks() 808 } 809 return err 810 } 811 812 // MkdirAt implements vfs.FilesystemImpl.MkdirAt. 813 func (fs *filesystem) MkdirAt(ctx context.Context, rp *vfs.ResolvingPath, opts vfs.MkdirOptions) error { 814 creds := rp.Credentials() 815 return fs.doCreateAt(ctx, rp, true /* dir */, func(parent *dentry, name string, ds **[]*dentry) (*dentry, error) { 816 // If the parent is a setgid directory, use the parent's GID 817 // rather than the caller's and enable setgid. 818 kgid := creds.EffectiveKGID 819 mode := opts.Mode 820 if parent.mode.Load()&linux.S_ISGID != 0 { 821 kgid = auth.KGID(parent.gid.Load()) 822 mode |= linux.S_ISGID 823 } 824 825 child, err := parent.mkdir(ctx, name, mode, creds.EffectiveKUID, kgid) 826 if err == nil { 827 if fs.opts.interop != InteropModeShared { 828 parent.incLinks() 829 } 830 return child, nil 831 } 832 833 if !opts.ForSyntheticMountpoint || linuxerr.Equals(linuxerr.EEXIST, err) { 834 return nil, err 835 } 836 ctx.Infof("Failed to create remote directory %q: %v; falling back to synthetic directory", name, err) 837 child = fs.newSyntheticDentry(&createSyntheticOpts{ 838 name: name, 839 mode: linux.S_IFDIR | opts.Mode, 840 kuid: creds.EffectiveKUID, 841 kgid: creds.EffectiveKGID, 842 }) 843 if fs.opts.interop != InteropModeShared { 844 parent.incLinks() 845 } 846 return child, nil 847 }, func(parent *dentry, name string) (*dentry, error) { 848 if !opts.ForSyntheticMountpoint { 849 // Can't create non-synthetic files in synthetic directories. 850 return nil, linuxerr.EPERM 851 } 852 child := fs.newSyntheticDentry(&createSyntheticOpts{ 853 name: name, 854 mode: linux.S_IFDIR | opts.Mode, 855 kuid: creds.EffectiveKUID, 856 kgid: creds.EffectiveKGID, 857 }) 858 parent.incLinks() 859 return child, nil 860 }) 861 } 862 863 // MknodAt implements vfs.FilesystemImpl.MknodAt. 864 func (fs *filesystem) MknodAt(ctx context.Context, rp *vfs.ResolvingPath, opts vfs.MknodOptions) error { 865 return fs.doCreateAt(ctx, rp, false /* dir */, func(parent *dentry, name string, ds **[]*dentry) (*dentry, error) { 866 creds := rp.Credentials() 867 if child, err := parent.mknod(ctx, name, creds, &opts); err == nil { 868 return child, nil 869 } else if !linuxerr.Equals(linuxerr.EPERM, err) { 870 return nil, err 871 } 872 873 // EPERM means that gofer does not allow creating a socket or pipe. Fallback 874 // to creating a synthetic one, i.e. one that is kept entirely in memory. 875 876 // Check that we're not overriding an existing file with a synthetic one. 877 _, _, err := fs.stepLocked(ctx, resolvingPathFull(rp), parent, false /* mayFollowSymlinks */, ds) // +checklocksforce: parent.opMu taken by doCreateAt. 878 switch { 879 case err == nil: 880 // Step succeeded, another file exists. 881 return nil, linuxerr.EEXIST 882 case !linuxerr.Equals(linuxerr.ENOENT, err): 883 // Schrödinger. File/Cat may or may not exist. 884 return nil, err 885 } 886 887 switch opts.Mode.FileType() { 888 case linux.S_IFSOCK: 889 return fs.newSyntheticDentry(&createSyntheticOpts{ 890 name: name, 891 mode: opts.Mode, 892 kuid: creds.EffectiveKUID, 893 kgid: creds.EffectiveKGID, 894 endpoint: opts.Endpoint, 895 }), nil 896 case linux.S_IFIFO: 897 return fs.newSyntheticDentry(&createSyntheticOpts{ 898 name: name, 899 mode: opts.Mode, 900 kuid: creds.EffectiveKUID, 901 kgid: creds.EffectiveKGID, 902 pipe: pipe.NewVFSPipe(true /* isNamed */, pipe.DefaultPipeSize), 903 }), nil 904 } 905 // Retain error from gofer if synthetic file cannot be created internally. 906 return nil, linuxerr.EPERM 907 }, nil) 908 } 909 910 // OpenAt implements vfs.FilesystemImpl.OpenAt. 911 func (fs *filesystem) OpenAt(ctx context.Context, rp *vfs.ResolvingPath, opts vfs.OpenOptions) (*vfs.FileDescription, error) { 912 // Reject O_TMPFILE, which is not supported; supporting it correctly in the 913 // presence of other remote filesystem users requires remote filesystem 914 // support, and it isn't clear that there's any way to implement this in 915 // 9P. 916 if opts.Flags&linux.O_TMPFILE != 0 { 917 return nil, linuxerr.EOPNOTSUPP 918 } 919 mayCreate := opts.Flags&linux.O_CREAT != 0 920 mustCreate := opts.Flags&(linux.O_CREAT|linux.O_EXCL) == (linux.O_CREAT | linux.O_EXCL) 921 922 var ds *[]*dentry 923 fs.renameMu.RLock() 924 unlocked := false 925 unlock := func() { 926 if !unlocked { 927 fs.renameMuRUnlockAndCheckCaching(ctx, &ds) 928 unlocked = true 929 } 930 } 931 defer unlock() 932 933 start := rp.Start().Impl().(*dentry) 934 if rp.Done() { 935 // Reject attempts to open mount root directory with O_CREAT. 936 if mayCreate && rp.MustBeDir() { 937 return nil, linuxerr.EISDIR 938 } 939 if mustCreate { 940 return nil, linuxerr.EEXIST 941 } 942 if !start.cachedMetadataAuthoritative() { 943 // Refresh dentry's attributes before opening. 944 if err := start.updateMetadata(ctx); err != nil { 945 return nil, err 946 } 947 } 948 start.IncRef() 949 defer start.DecRef(ctx) 950 unlock() 951 // start is intentionally not added to ds (which would remove it from the 952 // cache) because doing so regresses performance in practice. 953 return start.open(ctx, rp, &opts) 954 } 955 956 afterTrailingSymlink: 957 parent, err := fs.walkParentDirLocked(ctx, rp, start, &ds) 958 if err != nil { 959 return nil, err 960 } 961 // Check for search permission in the parent directory. 962 if err := parent.checkPermissions(rp.Credentials(), vfs.MayExec); err != nil { 963 return nil, err 964 } 965 // Reject attempts to open directories with O_CREAT. 966 if mayCreate && rp.MustBeDir() { 967 return nil, linuxerr.EISDIR 968 } 969 if err := fs.revalidateOne(ctx, rp.VirtualFilesystem(), parent, rp.Component(), &ds); err != nil { 970 return nil, err 971 } 972 // Determine whether or not we need to create a file. 973 // NOTE(b/263297063): Don't hold opMu for writing here, to avoid 974 // serializing OpenAt calls in the same directory in the common case 975 // that the file exists. 976 parent.opMu.RLock() 977 child, followedSymlink, err := fs.stepLocked(ctx, resolvingPathFull(rp), parent, true /* mayFollowSymlinks */, &ds) 978 parent.opMu.RUnlock() 979 if followedSymlink { 980 if mustCreate { 981 // EEXIST must be returned if an existing symlink is opened with O_EXCL. 982 return nil, linuxerr.EEXIST 983 } 984 if err != nil { 985 // If followedSymlink && err != nil, then this symlink resolution error 986 // must be handled by the VFS layer. 987 return nil, err 988 } 989 start = parent 990 goto afterTrailingSymlink 991 } 992 if linuxerr.Equals(linuxerr.ENOENT, err) && mayCreate { 993 if parent.isSynthetic() { 994 return nil, linuxerr.EPERM 995 } 996 997 // Take opMu for writing, but note that the file may have been 998 // created by another goroutine since we checked for existence 999 // a few lines ago. We must handle that case. 1000 parent.opMu.Lock() 1001 fd, createErr := parent.createAndOpenChildLocked(ctx, rp, &opts, &ds) 1002 if !linuxerr.Equals(linuxerr.EEXIST, createErr) { 1003 // Either the creation was a success, or we got an 1004 // unexpected error. Either way we can return here. 1005 parent.opMu.Unlock() 1006 return fd, createErr 1007 } 1008 1009 // We raced, and now the file exists. 1010 if mustCreate { 1011 parent.opMu.Unlock() 1012 return nil, linuxerr.EEXIST 1013 } 1014 1015 // Step to the file again. Since we still hold opMu for 1016 // writing, there can't be a race here. 1017 child, _, err = fs.stepLocked(ctx, resolvingPathFull(rp), parent, false /* mayFollowSymlinks */, &ds) 1018 parent.opMu.Unlock() 1019 } 1020 if err != nil { 1021 return nil, err 1022 } 1023 if mustCreate { 1024 return nil, linuxerr.EEXIST 1025 } 1026 if rp.MustBeDir() && !child.isDir() { 1027 return nil, linuxerr.ENOTDIR 1028 } 1029 child.IncRef() 1030 defer child.DecRef(ctx) 1031 unlock() 1032 // child is intentionally not added to ds (which would remove it from the 1033 // cache) because doing so regresses performance in practice. 1034 return child.open(ctx, rp, &opts) 1035 } 1036 1037 // Preconditions: The caller must hold no locks (since opening pipes may block 1038 // indefinitely). 1039 func (d *dentry) open(ctx context.Context, rp *vfs.ResolvingPath, opts *vfs.OpenOptions) (*vfs.FileDescription, error) { 1040 ats := vfs.AccessTypesForOpenFlags(opts) 1041 if err := d.checkPermissions(rp.Credentials(), ats); err != nil { 1042 return nil, err 1043 } 1044 1045 if !d.isSynthetic() { 1046 // renameMu is locked here because it is required by d.openHandle(), which 1047 // is called by d.ensureSharedHandle() and d.openSpecialFile() below. It is 1048 // also required by d.connect() which is called by 1049 // d.openSocketByConnecting(). Note that opening non-synthetic pipes may 1050 // block, renameMu is unlocked separately in d.openSpecialFile() for pipes. 1051 d.fs.renameMu.RLock() 1052 defer d.fs.renameMu.RUnlock() 1053 } 1054 1055 trunc := opts.Flags&linux.O_TRUNC != 0 && d.fileType() == linux.S_IFREG 1056 if trunc { 1057 // Lock metadataMu *while* we open a regular file with O_TRUNC because 1058 // open(2) will change the file size on server. 1059 d.metadataMu.Lock() 1060 defer d.metadataMu.Unlock() 1061 } 1062 1063 var vfd *vfs.FileDescription 1064 var err error 1065 mnt := rp.Mount() 1066 switch d.fileType() { 1067 case linux.S_IFREG: 1068 if !d.fs.opts.regularFilesUseSpecialFileFD { 1069 if err := d.ensureSharedHandle(ctx, ats.MayRead(), ats.MayWrite(), trunc); err != nil { 1070 return nil, err 1071 } 1072 fd, err := newRegularFileFD(mnt, d, opts.Flags) 1073 if err != nil { 1074 return nil, err 1075 } 1076 vfd = &fd.vfsfd 1077 } 1078 case linux.S_IFDIR: 1079 // Can't open directories with O_CREAT. 1080 if opts.Flags&linux.O_CREAT != 0 { 1081 return nil, linuxerr.EISDIR 1082 } 1083 // Can't open directories writably. 1084 if ats&vfs.MayWrite != 0 { 1085 return nil, linuxerr.EISDIR 1086 } 1087 if opts.Flags&linux.O_DIRECT != 0 { 1088 return nil, linuxerr.EINVAL 1089 } 1090 if !d.isSynthetic() { 1091 if err := d.ensureSharedHandle(ctx, ats&vfs.MayRead != 0, false /* write */, false /* trunc */); err != nil { 1092 return nil, err 1093 } 1094 } 1095 fd := &directoryFD{} 1096 fd.LockFD.Init(&d.locks) 1097 if err := fd.vfsfd.Init(fd, opts.Flags, mnt, &d.vfsd, &vfs.FileDescriptionOptions{}); err != nil { 1098 return nil, err 1099 } 1100 if d.readFD.Load() >= 0 { 1101 fsmetric.GoferOpensHost.Increment() 1102 } else { 1103 fsmetric.GoferOpens9P.Increment() 1104 } 1105 return &fd.vfsfd, nil 1106 case linux.S_IFLNK: 1107 // Can't open symlinks without O_PATH, which is handled at the VFS layer. 1108 return nil, linuxerr.ELOOP 1109 case linux.S_IFSOCK: 1110 if d.isSynthetic() { 1111 return nil, linuxerr.ENXIO 1112 } 1113 if d.fs.iopts.OpenSocketsByConnecting { 1114 return d.openSocketByConnecting(ctx, opts) 1115 } 1116 case linux.S_IFIFO: 1117 if d.isSynthetic() { 1118 return d.pipe.Open(ctx, mnt, &d.vfsd, opts.Flags, &d.locks) 1119 } 1120 if d.fs.opts.disableFifoOpen { 1121 return nil, linuxerr.EPERM 1122 } 1123 } 1124 1125 if vfd == nil { 1126 if vfd, err = d.openSpecialFile(ctx, mnt, opts); err != nil { 1127 return nil, err 1128 } 1129 } 1130 1131 if trunc { 1132 // If no errors occured so far then update file size in memory. This 1133 // step is required even if !d.cachedMetadataAuthoritative() because 1134 // d.mappings has to be updated. 1135 // d.metadataMu has already been acquired if trunc == true. 1136 d.updateSizeLocked(0) 1137 1138 if d.cachedMetadataAuthoritative() { 1139 d.touchCMtimeLocked() 1140 } 1141 } 1142 return vfd, err 1143 } 1144 1145 // Precondition: fs.renameMu is locked. 1146 func (d *dentry) openSocketByConnecting(ctx context.Context, opts *vfs.OpenOptions) (*vfs.FileDescription, error) { 1147 if opts.Flags&linux.O_DIRECT != 0 { 1148 return nil, linuxerr.EINVAL 1149 } 1150 // Note that special value of linux.SockType = 0 is interpreted by lisafs 1151 // as "do not care about the socket type". Analogous to p9.AnonymousSocket. 1152 sockFD, err := d.connect(ctx, 0 /* sockType */) 1153 if err != nil { 1154 return nil, err 1155 } 1156 fd, err := host.NewFD(ctx, kernel.KernelFromContext(ctx).HostMount(), sockFD, &host.NewFDOptions{ 1157 HaveFlags: true, 1158 Flags: opts.Flags, 1159 }) 1160 if err != nil { 1161 unix.Close(sockFD) 1162 return nil, err 1163 } 1164 return fd, nil 1165 } 1166 1167 // Preconditions: 1168 // - !d.isSynthetic(). 1169 // - fs.renameMu is locked. It may be released temporarily while pipe blocks. 1170 // - If d is a pipe, no other locks (other than fs.renameMu) should be held. 1171 func (d *dentry) openSpecialFile(ctx context.Context, mnt *vfs.Mount, opts *vfs.OpenOptions) (*vfs.FileDescription, error) { 1172 ats := vfs.AccessTypesForOpenFlags(opts) 1173 if opts.Flags&linux.O_DIRECT != 0 && !d.isRegularFile() { 1174 return nil, linuxerr.EINVAL 1175 } 1176 // We assume that the server silently inserts O_NONBLOCK in the open flags 1177 // for all named pipes (because all existing gofers do this). 1178 // 1179 // NOTE(b/133875563): This makes named pipe opens racy, because the 1180 // mechanisms for translating nonblocking to blocking opens can only detect 1181 // the instantaneous presence of a peer holding the other end of the pipe 1182 // open, not whether the pipe was *previously* opened by a peer that has 1183 // since closed its end. 1184 isBlockingOpenOfNamedPipe := d.fileType() == linux.S_IFIFO && opts.Flags&linux.O_NONBLOCK == 0 1185 retry: 1186 h, err := d.openHandle(ctx, ats.MayRead(), ats.MayWrite(), opts.Flags&linux.O_TRUNC != 0) 1187 if err != nil { 1188 if isBlockingOpenOfNamedPipe && ats == vfs.MayWrite && linuxerr.Equals(linuxerr.ENXIO, err) { 1189 // An attempt to open a named pipe with O_WRONLY|O_NONBLOCK fails 1190 // with ENXIO if opening the same named pipe with O_WRONLY would 1191 // block because there are no readers of the pipe. Release renameMu 1192 // while blocking. 1193 d.fs.renameMu.RUnlock() 1194 err := sleepBetweenNamedPipeOpenChecks(ctx) 1195 d.fs.renameMu.RLock() 1196 if err != nil { 1197 return nil, err 1198 } 1199 goto retry 1200 } 1201 return nil, err 1202 } 1203 if isBlockingOpenOfNamedPipe && ats == vfs.MayRead && h.fd >= 0 { 1204 // Release renameMu while blocking. 1205 d.fs.renameMu.RUnlock() 1206 err := blockUntilNonblockingPipeHasWriter(ctx, h.fd) 1207 d.fs.renameMu.RLock() 1208 if err != nil { 1209 h.close(ctx) 1210 return nil, err 1211 } 1212 } 1213 fd, err := newSpecialFileFD(h, mnt, d, opts.Flags) 1214 if err != nil { 1215 h.close(ctx) 1216 return nil, err 1217 } 1218 return &fd.vfsfd, nil 1219 } 1220 1221 // Preconditions: 1222 // - d.fs.renameMu must be locked. 1223 // - d.opMu must be locked for writing. 1224 // - !d.isSynthetic(). 1225 // 1226 // +checklocks:d.opMu 1227 func (d *dentry) createAndOpenChildLocked(ctx context.Context, rp *vfs.ResolvingPath, opts *vfs.OpenOptions, ds **[]*dentry) (*vfs.FileDescription, error) { 1228 if err := d.checkPermissions(rp.Credentials(), vfs.MayWrite); err != nil { 1229 return nil, err 1230 } 1231 if d.isDeleted() { 1232 return nil, linuxerr.ENOENT 1233 } 1234 mnt := rp.Mount() 1235 if err := mnt.CheckBeginWrite(); err != nil { 1236 return nil, err 1237 } 1238 defer mnt.EndWrite() 1239 1240 creds := rp.Credentials() 1241 name := rp.Component() 1242 // If the parent is a setgid directory, use the parent's GID rather 1243 // than the caller's. 1244 kgid := creds.EffectiveKGID 1245 if d.mode.Load()&linux.S_ISGID != 0 { 1246 kgid = auth.KGID(d.gid.Load()) 1247 } 1248 1249 child, h, err := d.openCreate(ctx, name, opts.Flags&linux.O_ACCMODE, opts.Mode, creds.EffectiveKUID, kgid) 1250 if err != nil { 1251 return nil, err 1252 } 1253 1254 // Incorporate the fid that was opened by lcreate. 1255 useRegularFileFD := child.fileType() == linux.S_IFREG && !d.fs.opts.regularFilesUseSpecialFileFD 1256 if useRegularFileFD { 1257 var readable, writable bool 1258 child.handleMu.Lock() 1259 if vfs.MayReadFileWithOpenFlags(opts.Flags) { 1260 readable = true 1261 if h.fd != -1 { 1262 child.readFD = atomicbitops.FromInt32(h.fd) 1263 child.mmapFD = atomicbitops.FromInt32(h.fd) 1264 } 1265 } 1266 if vfs.MayWriteFileWithOpenFlags(opts.Flags) { 1267 writable = true 1268 child.writeFD = atomicbitops.FromInt32(h.fd) 1269 } 1270 child.updateHandles(ctx, h, readable, writable) 1271 child.handleMu.Unlock() 1272 } 1273 // Insert the dentry into the tree. 1274 d.childrenMu.Lock() 1275 // We have d.opMu for writing, so there can not be a cached child with 1276 // this name. We could not have raced. 1277 d.cacheNewChildLocked(child, name) 1278 appendNewChildDentry(ds, d, child) 1279 if d.cachedMetadataAuthoritative() { 1280 d.touchCMtime() 1281 d.clearDirentsLocked() 1282 } 1283 d.childrenMu.Unlock() 1284 1285 // Finally, construct a file description representing the created file. 1286 var childVFSFD *vfs.FileDescription 1287 if useRegularFileFD { 1288 fd, err := newRegularFileFD(mnt, child, opts.Flags) 1289 if err != nil { 1290 return nil, err 1291 } 1292 childVFSFD = &fd.vfsfd 1293 } else { 1294 fd, err := newSpecialFileFD(h, mnt, child, opts.Flags) 1295 if err != nil { 1296 h.close(ctx) 1297 return nil, err 1298 } 1299 childVFSFD = &fd.vfsfd 1300 } 1301 d.watches.Notify(ctx, name, linux.IN_CREATE, 0, vfs.PathEvent, false /* unlinked */) 1302 return childVFSFD, nil 1303 } 1304 1305 // ReadlinkAt implements vfs.FilesystemImpl.ReadlinkAt. 1306 func (fs *filesystem) ReadlinkAt(ctx context.Context, rp *vfs.ResolvingPath) (string, error) { 1307 var ds *[]*dentry 1308 fs.renameMu.RLock() 1309 defer fs.renameMuRUnlockAndCheckCaching(ctx, &ds) 1310 d, err := fs.resolveLocked(ctx, rp, &ds) 1311 if err != nil { 1312 return "", err 1313 } 1314 if !d.isSymlink() { 1315 return "", linuxerr.EINVAL 1316 } 1317 return d.readlink(ctx, rp.Mount()) 1318 } 1319 1320 // RenameAt implements vfs.FilesystemImpl.RenameAt. 1321 func (fs *filesystem) RenameAt(ctx context.Context, rp *vfs.ResolvingPath, oldParentVD vfs.VirtualDentry, oldName string, opts vfs.RenameOptions) error { 1322 // Resolve newParent first to verify that it's on this Mount. 1323 var ds *[]*dentry 1324 fs.renameMu.Lock() 1325 defer fs.renameMuUnlockAndCheckCaching(ctx, &ds) 1326 newParent, err := fs.walkParentDirLocked(ctx, rp, rp.Start().Impl().(*dentry), &ds) 1327 if err != nil { 1328 return err 1329 } 1330 1331 if opts.Flags&^linux.RENAME_NOREPLACE != 0 { 1332 return linuxerr.EINVAL 1333 } 1334 if fs.opts.interop == InteropModeShared && opts.Flags&linux.RENAME_NOREPLACE != 0 { 1335 // Requires 9P support to synchronize with other remote filesystem 1336 // users. 1337 return linuxerr.EINVAL 1338 } 1339 1340 newName := rp.Component() 1341 if newName == "." || newName == ".." { 1342 if opts.Flags&linux.RENAME_NOREPLACE != 0 { 1343 return linuxerr.EEXIST 1344 } 1345 return linuxerr.EBUSY 1346 } 1347 if len(newName) > MaxFilenameLen { 1348 return linuxerr.ENAMETOOLONG 1349 } 1350 mnt := rp.Mount() 1351 if mnt != oldParentVD.Mount() { 1352 return linuxerr.EXDEV 1353 } 1354 if err := mnt.CheckBeginWrite(); err != nil { 1355 return err 1356 } 1357 defer mnt.EndWrite() 1358 1359 oldParent := oldParentVD.Dentry().Impl().(*dentry) 1360 if !oldParent.cachedMetadataAuthoritative() { 1361 if err := oldParent.updateMetadata(ctx); err != nil { 1362 return err 1363 } 1364 } 1365 creds := rp.Credentials() 1366 if err := oldParent.checkPermissions(creds, vfs.MayWrite|vfs.MayExec); err != nil { 1367 return err 1368 } 1369 1370 vfsObj := rp.VirtualFilesystem() 1371 if err := fs.revalidateOne(ctx, vfsObj, newParent, newName, &ds); err != nil { 1372 return err 1373 } 1374 if err := fs.revalidateOne(ctx, vfsObj, oldParent, oldName, &ds); err != nil { 1375 return err 1376 } 1377 1378 // We need a dentry representing the renamed file since, if it's a 1379 // directory, we need to check for write permission on it. 1380 oldParent.opMu.Lock() 1381 defer oldParent.opMu.Unlock() 1382 renamed, err := fs.getChildLocked(ctx, oldParent, oldName, &ds) 1383 if err != nil { 1384 return err 1385 } 1386 if err := oldParent.mayDelete(creds, renamed); err != nil { 1387 return err 1388 } 1389 if renamed.isDir() { 1390 if renamed == newParent || genericIsAncestorDentry(renamed, newParent) { 1391 return linuxerr.EINVAL 1392 } 1393 if oldParent != newParent { 1394 if err := renamed.checkPermissions(creds, vfs.MayWrite); err != nil { 1395 return err 1396 } 1397 } 1398 } else { 1399 if opts.MustBeDir || rp.MustBeDir() { 1400 return linuxerr.ENOTDIR 1401 } 1402 } 1403 1404 if oldParent != newParent { 1405 if err := newParent.checkPermissions(creds, vfs.MayWrite|vfs.MayExec); err != nil { 1406 return err 1407 } 1408 newParent.opMu.Lock() 1409 defer newParent.opMu.Unlock() 1410 } 1411 if newParent.isDeleted() { 1412 return linuxerr.ENOENT 1413 } 1414 replaced, err := fs.getChildLocked(ctx, newParent, newName, &ds) // +checklocksforce: newParent.opMu taken if newParent != oldParent. 1415 if err != nil && !linuxerr.Equals(linuxerr.ENOENT, err) { 1416 return err 1417 } 1418 var replacedVFSD *vfs.Dentry 1419 if replaced != nil { 1420 if opts.Flags&linux.RENAME_NOREPLACE != 0 { 1421 return linuxerr.EEXIST 1422 } 1423 replacedVFSD = &replaced.vfsd 1424 if replaced.isDir() { 1425 if !renamed.isDir() { 1426 return linuxerr.EISDIR 1427 } 1428 if genericIsAncestorDentry(replaced, renamed) { 1429 return linuxerr.ENOTEMPTY 1430 } 1431 } else { 1432 if rp.MustBeDir() || renamed.isDir() { 1433 return linuxerr.ENOTDIR 1434 } 1435 } 1436 } 1437 1438 if oldParent == newParent && oldName == newName { 1439 return nil 1440 } 1441 mntns := vfs.MountNamespaceFromContext(ctx) 1442 defer mntns.DecRef(ctx) 1443 if err := vfsObj.PrepareRenameDentry(mntns, &renamed.vfsd, replacedVFSD); err != nil { 1444 return err 1445 } 1446 1447 // Update the remote filesystem. 1448 if !renamed.isSynthetic() { 1449 if err := oldParent.rename(ctx, oldName, newParent, newName); err != nil { 1450 vfsObj.AbortRenameDentry(&renamed.vfsd, replacedVFSD) 1451 return err 1452 } 1453 } else if replaced != nil && !replaced.isSynthetic() { 1454 // We are replacing an existing real file with a synthetic one, so we 1455 // need to unlink the former. 1456 flags := uint32(0) 1457 if replaced.isDir() { 1458 flags = linux.AT_REMOVEDIR 1459 } 1460 if err := newParent.unlink(ctx, newName, flags); err != nil { 1461 vfsObj.AbortRenameDentry(&renamed.vfsd, replacedVFSD) 1462 return err 1463 } 1464 } 1465 1466 // Update the dentry tree. 1467 newParent.childrenMu.Lock() 1468 defer newParent.childrenMu.Unlock() 1469 if oldParent != newParent { 1470 oldParent.childrenMu.Lock() 1471 defer oldParent.childrenMu.Unlock() 1472 } 1473 1474 vfsObj.CommitRenameReplaceDentry(ctx, &renamed.vfsd, replacedVFSD) 1475 if replaced != nil { 1476 replaced.setDeleted() 1477 if replaced.isSynthetic() { 1478 newParent.syntheticChildren-- 1479 replaced.decRefNoCaching() 1480 } 1481 ds = appendDentry(ds, replaced) 1482 // Remove the replaced entry from its parent's cache. 1483 delete(newParent.children, newName) 1484 } 1485 oldParent.cacheNegativeLookupLocked(oldName) // +checklocksforce: oldParent.childrenMu is held if oldParent != newParent. 1486 if renamed.isSynthetic() { 1487 oldParent.syntheticChildren-- 1488 newParent.syntheticChildren++ 1489 } 1490 // We have d.opMu for writing, so no need to check for existence of a 1491 // child with the given name. We could not have raced. 1492 newParent.cacheNewChildLocked(renamed, newName) 1493 oldParent.decRefNoCaching() 1494 if oldParent != newParent { 1495 ds = appendDentry(ds, newParent) 1496 ds = appendDentry(ds, oldParent) 1497 } 1498 1499 // Update metadata. 1500 if renamed.cachedMetadataAuthoritative() { 1501 renamed.touchCtime() 1502 } 1503 if oldParent.cachedMetadataAuthoritative() { 1504 oldParent.clearDirentsLocked() 1505 oldParent.touchCMtime() 1506 if renamed.isDir() { 1507 oldParent.decLinks() 1508 } 1509 } 1510 if newParent.cachedMetadataAuthoritative() { 1511 newParent.clearDirentsLocked() 1512 newParent.touchCMtime() 1513 if renamed.isDir() && (replaced == nil || !replaced.isDir()) { 1514 // Increase the link count if we did not replace another directory. 1515 newParent.incLinks() 1516 } 1517 } 1518 vfs.InotifyRename(ctx, &renamed.watches, &oldParent.watches, &newParent.watches, oldName, newName, renamed.isDir()) 1519 return nil 1520 } 1521 1522 // RmdirAt implements vfs.FilesystemImpl.RmdirAt. 1523 func (fs *filesystem) RmdirAt(ctx context.Context, rp *vfs.ResolvingPath) error { 1524 return fs.unlinkAt(ctx, rp, true /* dir */) 1525 } 1526 1527 // SetStatAt implements vfs.FilesystemImpl.SetStatAt. 1528 func (fs *filesystem) SetStatAt(ctx context.Context, rp *vfs.ResolvingPath, opts vfs.SetStatOptions) error { 1529 var ds *[]*dentry 1530 fs.renameMu.RLock() 1531 d, err := fs.resolveLocked(ctx, rp, &ds) 1532 if err != nil { 1533 fs.renameMuRUnlockAndCheckCaching(ctx, &ds) 1534 return err 1535 } 1536 err = d.setStat(ctx, rp.Credentials(), &opts, rp.Mount()) 1537 fs.renameMuRUnlockAndCheckCaching(ctx, &ds) 1538 if err != nil { 1539 return err 1540 } 1541 1542 if ev := vfs.InotifyEventFromStatMask(opts.Stat.Mask); ev != 0 { 1543 d.InotifyWithParent(ctx, ev, 0, vfs.InodeEvent) 1544 } 1545 return nil 1546 } 1547 1548 // StatAt implements vfs.FilesystemImpl.StatAt. 1549 func (fs *filesystem) StatAt(ctx context.Context, rp *vfs.ResolvingPath, opts vfs.StatOptions) (linux.Statx, error) { 1550 var ds *[]*dentry 1551 fs.renameMu.RLock() 1552 defer fs.renameMuRUnlockAndCheckCaching(ctx, &ds) 1553 d, err := fs.resolveLocked(ctx, rp, &ds) 1554 if err != nil { 1555 return linux.Statx{}, err 1556 } 1557 // Since walking updates metadata for all traversed dentries under 1558 // InteropModeShared, including the returned one, we can return cached 1559 // metadata here regardless of fs.opts.interop. 1560 var stat linux.Statx 1561 d.statTo(&stat) 1562 return stat, nil 1563 } 1564 1565 // StatFSAt implements vfs.FilesystemImpl.StatFSAt. 1566 func (fs *filesystem) StatFSAt(ctx context.Context, rp *vfs.ResolvingPath) (linux.Statfs, error) { 1567 var ds *[]*dentry 1568 fs.renameMu.RLock() 1569 defer fs.renameMuRUnlockAndCheckCaching(ctx, &ds) 1570 d, err := fs.resolveLocked(ctx, rp, &ds) 1571 if err != nil { 1572 return linux.Statfs{}, err 1573 } 1574 // If d is synthetic, invoke statfs on the first ancestor of d that isn't. 1575 for d.isSynthetic() { 1576 d = d.parent 1577 } 1578 statfs, err := d.statfs(ctx) 1579 if err != nil { 1580 return linux.Statfs{}, err 1581 } 1582 if statfs.NameLength == 0 || statfs.NameLength > MaxFilenameLen { 1583 statfs.NameLength = MaxFilenameLen 1584 } 1585 // This is primarily for distinguishing a gofer file system in 1586 // tests. Testing is important, so instead of defining 1587 // something completely random, use a standard value. 1588 statfs.Type = linux.V9FS_MAGIC 1589 return statfs, nil 1590 } 1591 1592 // SymlinkAt implements vfs.FilesystemImpl.SymlinkAt. 1593 func (fs *filesystem) SymlinkAt(ctx context.Context, rp *vfs.ResolvingPath, target string) error { 1594 return fs.doCreateAt(ctx, rp, false /* dir */, func(parent *dentry, name string, ds **[]*dentry) (*dentry, error) { 1595 child, err := parent.symlink(ctx, name, target, rp.Credentials()) 1596 if err != nil { 1597 return nil, err 1598 } 1599 if parent.fs.opts.interop != InteropModeShared { 1600 // Cache the symlink target on creation. In practice, this helps avoid a 1601 // lot of ReadLink RPCs. Note that when InteropModeShared is in effect, 1602 // we are forced to make Readlink RPCs. Because in this mode, we use host 1603 // timestamps, not timestamps based on our internal clock. And readlink 1604 // updates the atime on the host. 1605 child.haveTarget = true 1606 child.target = target 1607 } 1608 return child, nil 1609 }, nil) 1610 } 1611 1612 // UnlinkAt implements vfs.FilesystemImpl.UnlinkAt. 1613 func (fs *filesystem) UnlinkAt(ctx context.Context, rp *vfs.ResolvingPath) error { 1614 return fs.unlinkAt(ctx, rp, false /* dir */) 1615 } 1616 1617 // BoundEndpointAt implements vfs.FilesystemImpl.BoundEndpointAt. 1618 func (fs *filesystem) BoundEndpointAt(ctx context.Context, rp *vfs.ResolvingPath, opts vfs.BoundEndpointOptions) (transport.BoundEndpoint, error) { 1619 var ds *[]*dentry 1620 fs.renameMu.RLock() 1621 defer fs.renameMuRUnlockAndCheckCaching(ctx, &ds) 1622 d, err := fs.resolveLocked(ctx, rp, &ds) 1623 if err != nil { 1624 return nil, err 1625 } 1626 if err := d.checkPermissions(rp.Credentials(), vfs.MayWrite); err != nil { 1627 return nil, err 1628 } 1629 if !d.isSocket() { 1630 return nil, linuxerr.ECONNREFUSED 1631 } 1632 if d.endpoint != nil { 1633 return d.endpoint, nil 1634 } 1635 if !d.isSynthetic() { 1636 d.IncRef() 1637 ds = appendDentry(ds, d) 1638 return &endpoint{ 1639 dentry: d, 1640 path: opts.Addr, 1641 }, nil 1642 } 1643 return nil, linuxerr.ECONNREFUSED 1644 } 1645 1646 // ListXattrAt implements vfs.FilesystemImpl.ListXattrAt. 1647 func (fs *filesystem) ListXattrAt(ctx context.Context, rp *vfs.ResolvingPath, size uint64) ([]string, error) { 1648 var ds *[]*dentry 1649 fs.renameMu.RLock() 1650 defer fs.renameMuRUnlockAndCheckCaching(ctx, &ds) 1651 d, err := fs.resolveLocked(ctx, rp, &ds) 1652 if err != nil { 1653 return nil, err 1654 } 1655 return d.listXattr(ctx, size) 1656 } 1657 1658 // GetXattrAt implements vfs.FilesystemImpl.GetXattrAt. 1659 func (fs *filesystem) GetXattrAt(ctx context.Context, rp *vfs.ResolvingPath, opts vfs.GetXattrOptions) (string, error) { 1660 var ds *[]*dentry 1661 fs.renameMu.RLock() 1662 defer fs.renameMuRUnlockAndCheckCaching(ctx, &ds) 1663 d, err := fs.resolveLocked(ctx, rp, &ds) 1664 if err != nil { 1665 return "", err 1666 } 1667 return d.getXattr(ctx, rp.Credentials(), &opts) 1668 } 1669 1670 // SetXattrAt implements vfs.FilesystemImpl.SetXattrAt. 1671 func (fs *filesystem) SetXattrAt(ctx context.Context, rp *vfs.ResolvingPath, opts vfs.SetXattrOptions) error { 1672 var ds *[]*dentry 1673 fs.renameMu.RLock() 1674 d, err := fs.resolveLocked(ctx, rp, &ds) 1675 if err != nil { 1676 fs.renameMuRUnlockAndCheckCaching(ctx, &ds) 1677 return err 1678 } 1679 err = d.setXattr(ctx, rp.Credentials(), &opts) 1680 fs.renameMuRUnlockAndCheckCaching(ctx, &ds) 1681 if err != nil { 1682 return err 1683 } 1684 1685 d.InotifyWithParent(ctx, linux.IN_ATTRIB, 0, vfs.InodeEvent) 1686 return nil 1687 } 1688 1689 // RemoveXattrAt implements vfs.FilesystemImpl.RemoveXattrAt. 1690 func (fs *filesystem) RemoveXattrAt(ctx context.Context, rp *vfs.ResolvingPath, name string) error { 1691 var ds *[]*dentry 1692 fs.renameMu.RLock() 1693 d, err := fs.resolveLocked(ctx, rp, &ds) 1694 if err != nil { 1695 fs.renameMuRUnlockAndCheckCaching(ctx, &ds) 1696 return err 1697 } 1698 err = d.removeXattr(ctx, rp.Credentials(), name) 1699 fs.renameMuRUnlockAndCheckCaching(ctx, &ds) 1700 if err != nil { 1701 return err 1702 } 1703 1704 d.InotifyWithParent(ctx, linux.IN_ATTRIB, 0, vfs.InodeEvent) 1705 return nil 1706 } 1707 1708 // PrependPath implements vfs.FilesystemImpl.PrependPath. 1709 func (fs *filesystem) PrependPath(ctx context.Context, vfsroot, vd vfs.VirtualDentry, b *fspath.Builder) error { 1710 fs.renameMu.RLock() 1711 defer fs.renameMu.RUnlock() 1712 return genericPrependPath(vfsroot, vd.Mount(), vd.Dentry().Impl().(*dentry), b) 1713 } 1714 1715 type mopt struct { 1716 key string 1717 value any 1718 } 1719 1720 func (m mopt) String() string { 1721 if m.value == nil { 1722 return fmt.Sprintf("%s", m.key) 1723 } 1724 return fmt.Sprintf("%s=%v", m.key, m.value) 1725 } 1726 1727 // MountOptions implements vfs.FilesystemImpl.MountOptions. 1728 func (fs *filesystem) MountOptions() string { 1729 optsKV := []mopt{ 1730 {moptTransport, transportModeFD}, // Only valid value, currently. 1731 {moptReadFD, fs.opts.fd}, // Currently, read and write FD are the same. 1732 {moptWriteFD, fs.opts.fd}, // Currently, read and write FD are the same. 1733 {moptAname, fs.opts.aname}, 1734 {moptDfltUID, fs.opts.dfltuid}, 1735 {moptDfltGID, fs.opts.dfltgid}, 1736 } 1737 1738 switch fs.opts.interop { 1739 case InteropModeExclusive: 1740 optsKV = append(optsKV, mopt{moptCache, cacheFSCache}) 1741 case InteropModeWritethrough: 1742 optsKV = append(optsKV, mopt{moptCache, cacheFSCacheWritethrough}) 1743 case InteropModeShared: 1744 optsKV = append(optsKV, mopt{moptCache, cacheRemoteRevalidating}) 1745 } 1746 if fs.opts.regularFilesUseSpecialFileFD { 1747 optsKV = append(optsKV, mopt{moptDisableFileHandleSharing, nil}) 1748 } 1749 if fs.opts.disableFifoOpen { 1750 optsKV = append(optsKV, mopt{moptDisableFifoOpen, nil}) 1751 } 1752 if fs.opts.forcePageCache { 1753 optsKV = append(optsKV, mopt{moptForcePageCache, nil}) 1754 } 1755 if fs.opts.limitHostFDTranslation { 1756 optsKV = append(optsKV, mopt{moptLimitHostFDTranslation, nil}) 1757 } 1758 if fs.opts.overlayfsStaleRead { 1759 optsKV = append(optsKV, mopt{moptOverlayfsStaleRead, nil}) 1760 } 1761 if fs.opts.directfs.enabled { 1762 optsKV = append(optsKV, mopt{moptDirectfs, nil}) 1763 } 1764 1765 opts := make([]string, 0, len(optsKV)) 1766 for _, opt := range optsKV { 1767 opts = append(opts, opt.String()) 1768 } 1769 return strings.Join(opts, ",") 1770 }