Repository: containerd/containerd
File: core/mount/mount_linux.go (Go)

Code before:
	commonDir, err := getCommonDirectory(lowerDirs)
	if err != nil {
		return nil, nil, fmt.Errorf("failed to determine common parent: %w", err)
	}

	tempRemountsLocation, err := os.MkdirTemp(tmpDir, "ovl-idmapped")
	if err != nil {
		return nil, nil, fmt.Errorf("failed to create temporary overlay lowerdir mount location: %w", err)
	}
	cleanDir := func() {
		if err := os.Remove(tempRemountsLocation); err != nil {
			log.L.WithError(err).Infof("failed to remove idmapped directory")
		}
	}
	defer func() {
		if retErr != nil {
			cleanDir()
		}
	}()

	// IDMapMount the directory containing all the layers
	if err := IDMapMountWithAttrs(commonDir, tempRemountsLocation, usernsFd, unix.MOUNT_ATTR_RDONLY, 0); err != nil {
		return nil, nil, err
	}
	cleanMount := func() {
		for retry := 0; retry < 5; retry++ {
			err := unix.Unmount(tempRemountsLocation, 0)
			if err != nil {
				time.Sleep(time.Millisecond * 100)
				continue
			}
			return
		}
		log.L.WithError(err).Warnf("failed to unmount idmapped directory %s", tempRemountsLocation)
	}
	defer func() {
		if retErr != nil {
			cleanMount()
		}
	}()

	// Build new lower dir paths through the idmapped directory
	tmpLowerDirs = buildIDMappedPaths(lowerDirs, commonDir, tempRemountsLocation)

	cleanup = func() {
		cleanMount()
		cleanDir()
	}
	return tmpLowerDirs, cleanup, nil
}


Review comment (suggestion):
Its worth noting that we already have [this](https://github.com/containerd/containerd/blob/ef686423b1418a4840dbaef2696010c06f82d246/core/mount/mount_unix.go#L114) function that is getting us out of jail on the tmpmount overlayfs mount (it does retries).

Maybe we switch to that? Thanks for this change, I was going to propose it if I couldn't figure out the source of EBUSY proper, but since we're already doing this for the other mount here I think its appropriate to do now.

Code after:
	if err != nil {
		return nil, nil, fmt.Errorf("failed to determine common parent: %w", err)
	}

	tempRemountsLocation, err := os.MkdirTemp(tmpDir, "ovl-idmapped")
	if err != nil {
		return nil, nil, fmt.Errorf("failed to create temporary overlay lowerdir mount location: %w", err)
	}
	cleanDir := func() {
		if err := os.Remove(tempRemountsLocation); err != nil {
			log.L.WithError(err).Infof("failed to remove idmapped directory")
		}
	}
	defer func() {
		if retErr != nil {
			cleanDir()
		}
	}()

	// IDMapMount the directory containing all the layers
	if err := IDMapMountWithAttrs(commonDir, tempRemountsLocation, usernsFd, unix.MOUNT_ATTR_RDONLY, 0); err != nil {
		return nil, nil, err
	}
	cleanMount := func() {
		// Use the Unmount helper that does retries because there can be easily an open fd
		// to the idmapped directory and when containerd forks to create a userns fd (maybe
		// for another container), it will make the mount busy for a few ms.
		err := Unmount(tempRemountsLocation, 0)
		if err != nil {
			log.L.WithError(err).Warnf("failed to unmount idmapped directory %s: %v", tempRemountsLocation, err)
		}
	}
	defer func() {
		if retErr != nil {
			cleanMount()
		}
	}()

	// Build new lower dir paths through the idmapped directory
	tmpLowerDirs := buildIDMappedPaths(lowerDirs, commonDir, tempRemountsLocation)

	cleanup := func() {
		cleanMount()
		cleanDir()
	}
	return tmpLowerDirs, cleanup, nil
}

// getCommonDirectory finds the common directory among the lowerDirs passed in.
// "/" and "." are considered invalid common directories and are treated as error
func getCommonDirectory(lowerDirs []string) (string, error) {