github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fs/inode_overlay.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 20 "github.com/SagerNet/gvisor/pkg/abi/linux" 21 "github.com/SagerNet/gvisor/pkg/context" 22 "github.com/SagerNet/gvisor/pkg/errors/linuxerr" 23 "github.com/SagerNet/gvisor/pkg/log" 24 "github.com/SagerNet/gvisor/pkg/sentry/socket/unix/transport" 25 "github.com/SagerNet/gvisor/pkg/syserror" 26 ) 27 28 func overlayHasWhiteout(ctx context.Context, parent *Inode, name string) bool { 29 s, err := parent.GetXattr(ctx, XattrOverlayWhiteout(name), 1) 30 return err == nil && s == "y" 31 } 32 33 func overlayCreateWhiteout(ctx context.Context, parent *Inode, name string) error { 34 return parent.InodeOperations.SetXattr(ctx, parent, XattrOverlayWhiteout(name), "y", 0 /* flags */) 35 } 36 37 func overlayWriteOut(ctx context.Context, o *overlayEntry) error { 38 // Hot path. Avoid defers. 39 var err error 40 o.copyMu.RLock() 41 if o.upper != nil { 42 err = o.upper.InodeOperations.WriteOut(ctx, o.upper) 43 } 44 o.copyMu.RUnlock() 45 return err 46 } 47 48 // overlayLookup performs a lookup in parent. 49 // 50 // If name exists, it returns true if the Dirent is in the upper, false if the 51 // Dirent is in the lower. 52 func overlayLookup(ctx context.Context, parent *overlayEntry, inode *Inode, name string) (*Dirent, bool, error) { 53 // Hot path. Avoid defers. 54 parent.copyMu.RLock() 55 56 // Assert that there is at least one upper or lower entry. 57 if parent.upper == nil && parent.lower == nil { 58 parent.copyMu.RUnlock() 59 panic("invalid overlayEntry, needs at least one Inode") 60 } 61 62 var upperInode *Inode 63 var lowerInode *Inode 64 65 // We must remember whether the upper fs returned a negative dirent, 66 // because it is only safe to return one if the upper did. 67 var negativeUpperChild bool 68 69 // Does the parent directory exist in the upper file system? 70 if parent.upper != nil { 71 // First check if a file object exists in the upper file system. 72 // A file could have been created over a whiteout, so we need to 73 // check if something exists in the upper file system first. 74 child, err := parent.upper.Lookup(ctx, name) 75 if err != nil && !linuxerr.Equals(linuxerr.ENOENT, err) { 76 // We encountered an error that an overlay cannot handle, 77 // we must propagate it to the caller. 78 parent.copyMu.RUnlock() 79 return nil, false, err 80 } 81 if child != nil { 82 if child.IsNegative() { 83 negativeUpperChild = true 84 } else { 85 upperInode = child.Inode 86 upperInode.IncRef() 87 } 88 child.DecRef(ctx) 89 } 90 91 // Are we done? 92 if overlayHasWhiteout(ctx, parent.upper, name) { 93 if upperInode == nil { 94 parent.copyMu.RUnlock() 95 if negativeUpperChild { 96 // If the upper fs returnd a negative 97 // Dirent, then the upper is OK with 98 // that negative Dirent being cached in 99 // the Dirent tree, so we can return 100 // one from the overlay. 101 return NewNegativeDirent(name), false, nil 102 } 103 // Upper fs is not OK with a negative Dirent 104 // being cached in the Dirent tree, so don't 105 // return one. 106 return nil, false, syserror.ENOENT 107 } 108 entry, err := newOverlayEntry(ctx, upperInode, nil, false) 109 if err != nil { 110 // Don't leak resources. 111 upperInode.DecRef(ctx) 112 parent.copyMu.RUnlock() 113 return nil, false, err 114 } 115 d, err := NewDirent(ctx, newOverlayInode(ctx, entry, inode.MountSource), name), nil 116 parent.copyMu.RUnlock() 117 return d, true, err 118 } 119 } 120 121 // Check the lower file system. We do this unconditionally (even for 122 // non-directories) because we may need to use stable attributes from 123 // the lower filesystem (e.g. device number, inode number) that were 124 // visible before a copy up. 125 if parent.lower != nil { 126 // Check the lower file system. 127 child, err := parent.lower.Lookup(ctx, name) 128 // Same song and dance as above. 129 if err != nil && !linuxerr.Equals(linuxerr.ENOENT, err) { 130 // Don't leak resources. 131 if upperInode != nil { 132 upperInode.DecRef(ctx) 133 } 134 parent.copyMu.RUnlock() 135 return nil, false, err 136 } 137 if child != nil { 138 if !child.IsNegative() { 139 if upperInode == nil { 140 // If nothing was in the upper, use what we found in the lower. 141 lowerInode = child.Inode 142 lowerInode.IncRef() 143 } else { 144 // If we have something from the upper, we can only use it if the types 145 // match. 146 // NOTE(b/112312863): Allow SpecialDirectories and Directories to merge. 147 // This is needed to allow submounts in /proc and /sys. 148 if upperInode.StableAttr.Type == child.Inode.StableAttr.Type || 149 (IsDir(upperInode.StableAttr) && IsDir(child.Inode.StableAttr)) { 150 lowerInode = child.Inode 151 lowerInode.IncRef() 152 } 153 } 154 } 155 child.DecRef(ctx) 156 } 157 } 158 159 // Was all of this for naught? 160 if upperInode == nil && lowerInode == nil { 161 parent.copyMu.RUnlock() 162 // We can only return a negative dirent if the upper returned 163 // one as well. See comments above regarding negativeUpperChild 164 // for more info. 165 if negativeUpperChild { 166 return NewNegativeDirent(name), false, nil 167 } 168 return nil, false, syserror.ENOENT 169 } 170 171 // Did we find a lower Inode? Remember this because we may decide we don't 172 // actually need the lower Inode (see below). 173 lowerExists := lowerInode != nil 174 175 // If we found something in the upper filesystem and the lower filesystem, 176 // use the stable attributes from the lower filesystem. If we don't do this, 177 // then it may appear that the file was magically recreated across copy up. 178 if upperInode != nil && lowerInode != nil { 179 // Steal attributes. 180 upperInode.StableAttr = lowerInode.StableAttr 181 182 // For non-directories, the lower filesystem resource is strictly 183 // unnecessary because we don't need to copy-up and we will always 184 // operate (e.g. read/write) on the upper Inode. 185 if !IsDir(upperInode.StableAttr) { 186 lowerInode.DecRef(ctx) 187 lowerInode = nil 188 } 189 } 190 191 // Phew, finally done. 192 entry, err := newOverlayEntry(ctx, upperInode, lowerInode, lowerExists) 193 if err != nil { 194 // Well, not quite, we failed at the last moment, how depressing. 195 // Be sure not to leak resources. 196 if upperInode != nil { 197 upperInode.DecRef(ctx) 198 } 199 if lowerInode != nil { 200 lowerInode.DecRef(ctx) 201 } 202 parent.copyMu.RUnlock() 203 return nil, false, err 204 } 205 d, err := NewDirent(ctx, newOverlayInode(ctx, entry, inode.MountSource), name), nil 206 parent.copyMu.RUnlock() 207 return d, upperInode != nil, err 208 } 209 210 func overlayCreate(ctx context.Context, o *overlayEntry, parent *Dirent, name string, flags FileFlags, perm FilePermissions) (*File, error) { 211 // Sanity check. 212 if parent.Inode.overlay == nil { 213 panic(fmt.Sprintf("overlayCreate called with non-overlay parent inode (parent InodeOperations type is %T)", parent.Inode.InodeOperations)) 214 } 215 216 // Dirent.Create takes renameMu if the Inode is an overlay Inode. 217 if err := copyUpLockedForRename(ctx, parent); err != nil { 218 return nil, err 219 } 220 221 upperFile, err := o.upper.InodeOperations.Create(ctx, o.upper, name, flags, perm) 222 if err != nil { 223 return nil, err 224 } 225 226 // We've added to the directory so we must drop the cache. 227 o.markDirectoryDirty() 228 229 // Take another reference on the upper file's inode, which will be 230 // owned by the overlay entry. 231 upperFile.Dirent.Inode.IncRef() 232 entry, err := newOverlayEntry(ctx, upperFile.Dirent.Inode, nil, false) 233 if err != nil { 234 werr := fmt.Errorf("newOverlayEntry failed: %v", err) 235 cleanupUpper(ctx, o.upper, name, werr) 236 return nil, err 237 } 238 239 // NOTE(b/71766861): Replace the Dirent with a transient Dirent, since 240 // we are about to create the real Dirent: an overlay Dirent. 241 // 242 // This ensures the *fs.File returned from overlayCreate is in the same 243 // state as the *fs.File returned by overlayGetFile, where the upper 244 // file has a transient Dirent. 245 // 246 // This is necessary for Save/Restore, as otherwise the upper Dirent 247 // (which has no path as it is unparented and never reachable by the 248 // user) will clobber the real path for the underlying Inode. 249 upperFile.Dirent.Inode.IncRef() 250 upperDirent := NewTransientDirent(upperFile.Dirent.Inode) 251 upperFile.Dirent.DecRef(ctx) 252 upperFile.Dirent = upperDirent 253 254 // Create the overlay inode and dirent. We need this to construct the 255 // overlay file. 256 overlayInode := newOverlayInode(ctx, entry, parent.Inode.MountSource) 257 // d will own the inode reference. 258 overlayDirent := NewDirent(ctx, overlayInode, name) 259 // The overlay file created below with NewFile will take a reference on 260 // the overlayDirent, and it should be the only thing holding a 261 // reference at the time of creation, so we must drop this reference. 262 defer overlayDirent.DecRef(ctx) 263 264 // Create a new overlay file that wraps the upper file. 265 flags.Pread = upperFile.Flags().Pread 266 flags.Pwrite = upperFile.Flags().Pwrite 267 overlayFile := NewFile(ctx, overlayDirent, flags, &overlayFileOperations{upper: upperFile}) 268 269 return overlayFile, nil 270 } 271 272 func overlayCreateDirectory(ctx context.Context, o *overlayEntry, parent *Dirent, name string, perm FilePermissions) error { 273 // Dirent.CreateDirectory takes renameMu if the Inode is an overlay 274 // Inode. 275 if err := copyUpLockedForRename(ctx, parent); err != nil { 276 return err 277 } 278 if err := o.upper.InodeOperations.CreateDirectory(ctx, o.upper, name, perm); err != nil { 279 return err 280 } 281 // We've added to the directory so we must drop the cache. 282 o.markDirectoryDirty() 283 return nil 284 } 285 286 func overlayCreateLink(ctx context.Context, o *overlayEntry, parent *Dirent, oldname string, newname string) error { 287 // Dirent.CreateLink takes renameMu if the Inode is an overlay Inode. 288 if err := copyUpLockedForRename(ctx, parent); err != nil { 289 return err 290 } 291 if err := o.upper.InodeOperations.CreateLink(ctx, o.upper, oldname, newname); err != nil { 292 return err 293 } 294 // We've added to the directory so we must drop the cache. 295 o.markDirectoryDirty() 296 return nil 297 } 298 299 func overlayCreateHardLink(ctx context.Context, o *overlayEntry, parent *Dirent, target *Dirent, name string) error { 300 // Dirent.CreateHardLink takes renameMu if the Inode is an overlay 301 // Inode. 302 if err := copyUpLockedForRename(ctx, parent); err != nil { 303 return err 304 } 305 if err := copyUpLockedForRename(ctx, target); err != nil { 306 return err 307 } 308 if err := o.upper.InodeOperations.CreateHardLink(ctx, o.upper, target.Inode.overlay.upper, name); err != nil { 309 return err 310 } 311 // We've added to the directory so we must drop the cache. 312 o.markDirectoryDirty() 313 return nil 314 } 315 316 func overlayCreateFifo(ctx context.Context, o *overlayEntry, parent *Dirent, name string, perm FilePermissions) error { 317 // Dirent.CreateFifo takes renameMu if the Inode is an overlay Inode. 318 if err := copyUpLockedForRename(ctx, parent); err != nil { 319 return err 320 } 321 if err := o.upper.InodeOperations.CreateFifo(ctx, o.upper, name, perm); err != nil { 322 return err 323 } 324 // We've added to the directory so we must drop the cache. 325 o.markDirectoryDirty() 326 return nil 327 } 328 329 func overlayRemove(ctx context.Context, o *overlayEntry, parent *Dirent, child *Dirent) error { 330 // Dirent.Remove and Dirent.RemoveDirectory take renameMu if the Inode 331 // is an overlay Inode. 332 if err := copyUpLockedForRename(ctx, parent); err != nil { 333 return err 334 } 335 child.Inode.overlay.copyMu.RLock() 336 defer child.Inode.overlay.copyMu.RUnlock() 337 if child.Inode.StableAttr.Type == Directory { 338 // RemoveDirectory requires that the directory is empty. 339 ser := &CollectEntriesSerializer{} 340 dirCtx := &DirCtx{ 341 Serializer: ser, 342 } 343 if _, err := overlayIterateDirLocked(ctx, child.Inode.overlay, child, dirCtx, 0); err != nil { 344 return err 345 } 346 if ser.Written() != 0 { 347 return linuxerr.ENOTEMPTY 348 } 349 } 350 if child.Inode.overlay.upper != nil { 351 if child.Inode.StableAttr.Type == Directory { 352 if err := o.upper.InodeOperations.RemoveDirectory(ctx, o.upper, child.name); err != nil { 353 return err 354 } 355 } else { 356 if err := o.upper.InodeOperations.Remove(ctx, o.upper, child.name); err != nil { 357 return err 358 } 359 } 360 } 361 if child.Inode.overlay.lowerExists { 362 if err := overlayCreateWhiteout(ctx, o.upper, child.name); err != nil { 363 return err 364 } 365 } 366 // We've removed from the directory so we must drop the cache. 367 o.markDirectoryDirty() 368 return nil 369 } 370 371 func overlayRename(ctx context.Context, o *overlayEntry, oldParent *Dirent, renamed *Dirent, newParent *Dirent, newName string, replacement bool) error { 372 // To be able to copy these up below, they have to be part of an 373 // overlay file system. 374 // 375 // Maybe some day we can allow the more complicated case of 376 // non-overlay X overlay renames, but that's not necessary right now. 377 if renamed.Inode.overlay == nil || newParent.Inode.overlay == nil || oldParent.Inode.overlay == nil { 378 return linuxerr.EXDEV 379 } 380 381 if replacement { 382 // Check here if the file to be replaced exists and is a 383 // non-empty directory. If we copy up first, we may end up 384 // copying the directory but none of its children, so the 385 // directory will appear empty in the upper fs, which will then 386 // allow the rename to proceed when it should return ENOTEMPTY. 387 // 388 // NOTE(b/111808347): Ideally, we'd just pass in the replaced 389 // Dirent from Rename, but we must drop the reference on 390 // replaced before we make the rename call, so Rename can't 391 // pass the Dirent to the Inode without significantly 392 // complicating the API. Thus we look it up again here. 393 // 394 // For the same reason we can't use defer here. 395 replaced, inUpper, err := overlayLookup(ctx, newParent.Inode.overlay, newParent.Inode, newName) 396 // If err == ENOENT or a negative Dirent is returned, then 397 // newName has been removed out from under us. That's fine; 398 // filesystems where that can happen must handle stale 399 // 'replaced'. 400 if err != nil && !linuxerr.Equals(linuxerr.ENOENT, err) { 401 return err 402 } 403 if err == nil { 404 if !inUpper { 405 // newName doesn't exist in 406 // newParent.Inode.overlay.upper, thus from 407 // that Inode's perspective this won't be a 408 // replacing rename. 409 replacement = false 410 } 411 412 if !replaced.IsNegative() && IsDir(replaced.Inode.StableAttr) { 413 children, err := readdirOne(ctx, replaced) 414 if err != nil { 415 replaced.DecRef(ctx) 416 return err 417 } 418 419 // readdirOne ensures that "." and ".." are not 420 // included among the returned children, so we don't 421 // need to bother checking for them. 422 if len(children) > 0 { 423 replaced.DecRef(ctx) 424 return linuxerr.ENOTEMPTY 425 } 426 } 427 428 replaced.DecRef(ctx) 429 } 430 } 431 432 if err := copyUpLockedForRename(ctx, renamed); err != nil { 433 return err 434 } 435 if err := copyUpLockedForRename(ctx, newParent); err != nil { 436 return err 437 } 438 oldName := renamed.name 439 if err := o.upper.InodeOperations.Rename(ctx, renamed.Inode.overlay.upper, oldParent.Inode.overlay.upper, oldName, newParent.Inode.overlay.upper, newName, replacement); err != nil { 440 return err 441 } 442 if renamed.Inode.overlay.lowerExists { 443 if err := overlayCreateWhiteout(ctx, oldParent.Inode.overlay.upper, oldName); err != nil { 444 return err 445 } 446 } 447 // We've changed the directory so we must drop the cache. 448 oldParent.Inode.overlay.markDirectoryDirty() 449 return nil 450 } 451 452 func overlayBind(ctx context.Context, o *overlayEntry, parent *Dirent, name string, data transport.BoundEndpoint, perm FilePermissions) (*Dirent, error) { 453 if err := copyUpLockedForRename(ctx, parent); err != nil { 454 return nil, err 455 } 456 457 o.copyMu.RLock() 458 defer o.copyMu.RUnlock() 459 460 d, err := o.upper.InodeOperations.Bind(ctx, o.upper, name, data, perm) 461 if err != nil { 462 return nil, err 463 } 464 465 // We've added to the directory so we must drop the cache. 466 o.markDirectoryDirty() 467 468 // Grab the inode and drop the dirent, we don't need it. 469 inode := d.Inode 470 inode.IncRef() 471 d.DecRef(ctx) 472 473 // Create a new overlay entry and dirent for the socket. 474 entry, err := newOverlayEntry(ctx, inode, nil, false) 475 if err != nil { 476 inode.DecRef(ctx) 477 return nil, err 478 } 479 // Use the parent's MountSource, since that corresponds to the overlay, 480 // and not the upper filesystem. 481 return NewDirent(ctx, newOverlayInode(ctx, entry, parent.Inode.MountSource), name), nil 482 } 483 484 func overlayBoundEndpoint(o *overlayEntry, path string) transport.BoundEndpoint { 485 o.copyMu.RLock() 486 defer o.copyMu.RUnlock() 487 488 if o.upper != nil { 489 return o.upper.InodeOperations.BoundEndpoint(o.upper, path) 490 } 491 492 return o.lower.BoundEndpoint(path) 493 } 494 495 func overlayGetFile(ctx context.Context, o *overlayEntry, d *Dirent, flags FileFlags) (*File, error) { 496 // Hot path. Avoid defers. 497 if flags.Write { 498 if err := copyUp(ctx, d); err != nil { 499 return nil, err 500 } 501 } 502 503 o.copyMu.RLock() 504 505 if o.upper != nil { 506 upper, err := overlayFile(ctx, o.upper, flags) 507 if err != nil { 508 o.copyMu.RUnlock() 509 return nil, err 510 } 511 flags.Pread = upper.Flags().Pread 512 flags.Pwrite = upper.Flags().Pwrite 513 f, err := NewFile(ctx, d, flags, &overlayFileOperations{upper: upper}), nil 514 o.copyMu.RUnlock() 515 return f, err 516 } 517 518 lower, err := overlayFile(ctx, o.lower, flags) 519 if err != nil { 520 o.copyMu.RUnlock() 521 return nil, err 522 } 523 flags.Pread = lower.Flags().Pread 524 flags.Pwrite = lower.Flags().Pwrite 525 o.copyMu.RUnlock() 526 return NewFile(ctx, d, flags, &overlayFileOperations{lower: lower}), nil 527 } 528 529 func overlayUnstableAttr(ctx context.Context, o *overlayEntry) (UnstableAttr, error) { 530 // Hot path. Avoid defers. 531 var ( 532 attr UnstableAttr 533 err error 534 ) 535 o.copyMu.RLock() 536 if o.upper != nil { 537 attr, err = o.upper.UnstableAttr(ctx) 538 } else { 539 attr, err = o.lower.UnstableAttr(ctx) 540 } 541 o.copyMu.RUnlock() 542 return attr, err 543 } 544 545 func overlayGetXattr(ctx context.Context, o *overlayEntry, name string, size uint64) (string, error) { 546 // Hot path. This is how the overlay checks for whiteout files. 547 // Avoid defers. 548 var ( 549 s string 550 err error 551 ) 552 553 // Don't forward the value of the extended attribute if it would 554 // unexpectedly change the behavior of a wrapping overlay layer. 555 if isXattrOverlay(name) { 556 return "", linuxerr.ENODATA 557 } 558 559 o.copyMu.RLock() 560 if o.upper != nil { 561 s, err = o.upper.GetXattr(ctx, name, size) 562 } else { 563 s, err = o.lower.GetXattr(ctx, name, size) 564 } 565 o.copyMu.RUnlock() 566 return s, err 567 } 568 569 func overlaySetXattr(ctx context.Context, o *overlayEntry, d *Dirent, name, value string, flags uint32) error { 570 // Don't allow changes to overlay xattrs through a setxattr syscall. 571 if isXattrOverlay(name) { 572 return linuxerr.EPERM 573 } 574 575 if err := copyUp(ctx, d); err != nil { 576 return err 577 } 578 return o.upper.SetXattr(ctx, d, name, value, flags) 579 } 580 581 func overlayListXattr(ctx context.Context, o *overlayEntry, size uint64) (map[string]struct{}, error) { 582 o.copyMu.RLock() 583 defer o.copyMu.RUnlock() 584 var names map[string]struct{} 585 var err error 586 if o.upper != nil { 587 names, err = o.upper.ListXattr(ctx, size) 588 } else { 589 names, err = o.lower.ListXattr(ctx, size) 590 } 591 for name := range names { 592 // Same as overlayGetXattr, we shouldn't forward along 593 // overlay attributes. 594 if isXattrOverlay(name) { 595 delete(names, name) 596 } 597 } 598 return names, err 599 } 600 601 func overlayRemoveXattr(ctx context.Context, o *overlayEntry, d *Dirent, name string) error { 602 // Don't allow changes to overlay xattrs through a removexattr syscall. 603 if isXattrOverlay(name) { 604 return linuxerr.EPERM 605 } 606 607 if err := copyUp(ctx, d); err != nil { 608 return err 609 } 610 return o.upper.RemoveXattr(ctx, d, name) 611 } 612 613 func overlayCheck(ctx context.Context, o *overlayEntry, p PermMask) error { 614 o.copyMu.RLock() 615 // Hot path. Avoid defers. 616 var err error 617 if o.upper != nil { 618 err = o.upper.check(ctx, p) 619 } else { 620 err = o.lower.check(ctx, p) 621 } 622 o.copyMu.RUnlock() 623 return err 624 } 625 626 func overlaySetPermissions(ctx context.Context, o *overlayEntry, d *Dirent, f FilePermissions) bool { 627 if err := copyUp(ctx, d); err != nil { 628 return false 629 } 630 return o.upper.InodeOperations.SetPermissions(ctx, o.upper, f) 631 } 632 633 func overlaySetOwner(ctx context.Context, o *overlayEntry, d *Dirent, owner FileOwner) error { 634 if err := copyUp(ctx, d); err != nil { 635 return err 636 } 637 return o.upper.InodeOperations.SetOwner(ctx, o.upper, owner) 638 } 639 640 func overlaySetTimestamps(ctx context.Context, o *overlayEntry, d *Dirent, ts TimeSpec) error { 641 if err := copyUp(ctx, d); err != nil { 642 return err 643 } 644 return o.upper.InodeOperations.SetTimestamps(ctx, o.upper, ts) 645 } 646 647 func overlayTruncate(ctx context.Context, o *overlayEntry, d *Dirent, size int64) error { 648 if err := copyUp(ctx, d); err != nil { 649 return err 650 } 651 return o.upper.InodeOperations.Truncate(ctx, o.upper, size) 652 } 653 654 func overlayAllocate(ctx context.Context, o *overlayEntry, d *Dirent, offset, length int64) error { 655 if err := copyUp(ctx, d); err != nil { 656 return err 657 } 658 return o.upper.InodeOperations.Allocate(ctx, o.upper, offset, length) 659 } 660 661 func overlayReadlink(ctx context.Context, o *overlayEntry) (string, error) { 662 o.copyMu.RLock() 663 defer o.copyMu.RUnlock() 664 if o.upper != nil { 665 return o.upper.Readlink(ctx) 666 } 667 return o.lower.Readlink(ctx) 668 } 669 670 func overlayGetlink(ctx context.Context, o *overlayEntry) (*Dirent, error) { 671 var dirent *Dirent 672 var err error 673 674 o.copyMu.RLock() 675 defer o.copyMu.RUnlock() 676 677 if o.upper != nil { 678 dirent, err = o.upper.Getlink(ctx) 679 } else { 680 dirent, err = o.lower.Getlink(ctx) 681 } 682 if dirent != nil { 683 // This dirent is likely bogus (its Inode likely doesn't contain 684 // the right overlayEntry). So we're forced to drop it on the 685 // ground and claim that jumping around the filesystem like this 686 // is not supported. 687 name, _ := dirent.FullName(nil) 688 dirent.DecRef(ctx) 689 690 // Claim that the path is not accessible. 691 err = linuxerr.EACCES 692 log.Warningf("Getlink not supported in overlay for %q", name) 693 } 694 return nil, err 695 } 696 697 func overlayStatFS(ctx context.Context, o *overlayEntry) (Info, error) { 698 o.copyMu.RLock() 699 defer o.copyMu.RUnlock() 700 701 var i Info 702 var err error 703 if o.upper != nil { 704 i, err = o.upper.StatFS(ctx) 705 } else { 706 i, err = o.lower.StatFS(ctx) 707 } 708 if err != nil { 709 return Info{}, err 710 } 711 712 i.Type = linux.OVERLAYFS_SUPER_MAGIC 713 714 return i, nil 715 } 716 717 // NewTestOverlayDir returns an overlay Inode for tests. 718 // 719 // If `revalidate` is true, then the upper filesystem will require 720 // revalidation. 721 func NewTestOverlayDir(ctx context.Context, upper, lower *Inode, revalidate bool) *Inode { 722 fs := &overlayFilesystem{} 723 var upperMsrc *MountSource 724 if revalidate { 725 upperMsrc = NewRevalidatingMountSource(ctx, fs, MountSourceFlags{}) 726 } else { 727 upperMsrc = NewNonCachingMountSource(ctx, fs, MountSourceFlags{}) 728 } 729 msrc := NewMountSource(ctx, &overlayMountSourceOperations{ 730 upper: upperMsrc, 731 lower: NewNonCachingMountSource(ctx, fs, MountSourceFlags{}), 732 }, fs, MountSourceFlags{}) 733 overlay := &overlayEntry{ 734 upper: upper, 735 lower: lower, 736 } 737 return newOverlayInode(ctx, overlay, msrc) 738 } 739 740 // TestHasUpperFS returns true if i is an overlay Inode and it has a pointer 741 // to an Inode on an upper filesystem. 742 func (i *Inode) TestHasUpperFS() bool { 743 return i.overlay != nil && i.overlay.upper != nil 744 } 745 746 // TestHasLowerFS returns true if i is an overlay Inode and it has a pointer 747 // to an Inode on a lower filesystem. 748 func (i *Inode) TestHasLowerFS() bool { 749 return i.overlay != nil && i.overlay.lower != nil 750 }