---
name: "open_tree_attr"
section: "2"
platform: "linux"
package: "man-pages"
version: "6.19-1"
release: "Arch Linux 2026-11-01"
platforms: ["linux"]
url: "https://new.carta.tech/open_tree"
---

# open\_tree\_attr(2)

open path or create detached mount object and attach to fd

Part of [open\_tree(2)](/open_tree/2.md).

## NAME

open\_tree - open path or create detached mount object and attach to fd

## LIBRARY

Standard C library (*libc*, *-lc*)

## SYNOPSIS

```
#define _GNU_SOURCE         /* See feature_test_macros(7) */
#include <fcntl.h>          /* Definition of AT_* constants */
#include <sys/mount.h>
```

**int open\_tree(int** *dirfd***, const char \****path***, unsigned int** *flags***);**

**#include \<sys/syscall.h\>**    /\* Definition of **SYS\_\*** constants \*/

**int syscall(SYS\_open\_tree\_attr,**             **int** *dirfd***, const char \****path***, unsigned int** *flags***,**             **struct mount\_attr \*\_Nullable** *attr***, size\_t** *size***);**

*Note*: glibc provides no wrapper for **open\_tree\_attr**(), necessitating the use of [**syscall**(2)](/syscall/2.md).

## DESCRIPTION

The **open\_tree**() system call is part of the suite of file-descriptor-based mount facilities in Linux.

- •

  If *flags* contains **OPEN\_TREE\_CLONE**, **open\_tree**() creates a detached mount object which consists of a bind-mount of the path specified by the *path*. A new file descriptor associated with the detached mount object is then returned. The mount object is equivalent to a bind-mount that would be created by [**mount**(2)](/mount/2.md) called with **MS\_BIND**, except that it is tied to a file descriptor and is not mounted onto the filesystem.

-

  As with file descriptors returned from [**fsmount**(2)](/fsmount/2.md), the resultant file descriptor can then be used with [**move\_mount**(2)](/move_mount/2.md), [**mount\_setattr**(2)](/mount_setattr/2.md), or other such system calls to do further mount operations.

-

  This mount object will be unmounted and destroyed when the file descriptor is closed if it was not otherwise attached to a mount point by calling [**move\_mount**(2)](/move_mount/2.md). This implicit unmount operation is lazy—akin to calling [**umount2**(2)](/umount2/2.md) with **MNT\_DETACH**; thus, any existing open references to files from the mount object will continue to work, and the mount object will only be completely destroyed once it ceases to be busy.

- •

  If *flags* does not contain **OPEN\_TREE\_CLONE**, **open\_tree**() returns a file descriptor that is exactly equivalent to one produced by [**openat**(2)](/openat/2.md) when called with the same *dirfd* and *path*.

In either case, the resultant file descriptor acts the same as one produced by [**open**(2)](/open/2.md) with **O\_PATH**, meaning it can also be used as a *dirfd* argument to "\*at()" system calls. However, unlike [**open**(2)](/open/2.md) called with **O\_PATH**, automounts will by default be triggered by **open\_tree**() unless **AT\_NO\_AUTOMOUNT** is included in *flags*.

As with "\*at()" system calls, **open\_tree**() uses the *dirfd* argument in conjunction with the *path* argument to determine the path to operate on, as follows:

- •

  If the pathname given in *path* is absolute, then *dirfd* is ignored.

- •

  If the pathname given in *path* is relative and *dirfd* is the special value **AT\_FDCWD**, then *path* is interpreted relative to the current working directory of the calling process (like [**open**(2)](/open/2.md)).

- •

  If the pathname given in *path* is relative, then it is interpreted relative to the directory referred to by the file descriptor *dirfd* (rather than relative to the current working directory of the calling process, as is done by [**open**(2)](/open/2.md) for a relative pathname). In this case, *dirfd* must be a directory that was opened for reading (**O\_RDONLY**) or using the **O\_PATH** flag.

- •

  If *path* is an empty string, and *flags* contains **AT\_EMPTY\_PATH**, then the file descriptor *dirfd* is operated on directly. In this case, *dirfd* may refer to any type of file, not just a directory.

See [**openat**(2)](/openat/2.md) for an explanation of why the *dirfd* argument is useful.

*flags* can be used to control aspects of the path lookup and properties of the returned file descriptor. A value for *flags* is constructed by bitwise ORing zero or more of the following constants:

- **AT\_EMPTY\_PATH**

  If *path* is an empty string, operate on the file referred to by *dirfd* (which may have been obtained from [**open**(2)](/open/2.md), [**fsmount**(2)](/fsmount/2.md), or from another **open\_tree**() call). In this case, *dirfd* may refer to any type of file, not just a directory. If *dirfd* is **AT\_FDCWD**, **open\_tree**() will operate on the current working directory of the calling process. This flag is Linux-specific; define **\_GNU\_SOURCE** to obtain its definition.

- **AT\_NO\_AUTOMOUNT**

  Do not automount the terminal ("basename") component of *path* if it is a directory that is an automount point. This allows you to create a handle to the automount point itself, rather than the location it would mount. This flag has no effect if the mount point has already been mounted over. This flag is Linux-specific; define **\_GNU\_SOURCE** to obtain its definition.

- **AT\_SYMLINK\_NOFOLLOW**

  If *path* is a symbolic link, do not dereference it; instead, create either a handle to the link itself or a bind-mount of it. The resultant file descriptor is indistinguishable from one produced by [**openat**(2)](/openat/2.md) with **O\_PATH**\|**O\_NOFOLLLOW**.

- **OPEN\_TREE\_CLOEXEC**

  Set the close-on-exec (**FD\_CLOEXEC**) flag on the new file descriptor. See the description of the **O\_CLOEXEC** flag in [**open**(2)](/open/2.md) for reasons why this may be useful.

- **OPEN\_TREE\_CLONE**

  Rather than creating an [**openat**(2)](/openat/2.md)-style **O\_PATH** file descriptor, create a bind-mount of *path* (akin to *mount --bind*) as a detached mount object. In order to do this operation, the calling process must have the **CAP\_SYS\_ADMIN** capability.

- **AT\_RECURSIVE**

  Create a recursive bind-mount of the path (akin to *mount --rbind*) as a detached mount object. This flag is only permitted in conjunction with **OPEN\_TREE\_CLONE**.

### open\_tree\_attr()

The **open\_tree\_attr**() system call operates in exactly the same way as **open\_tree**(), except for the differences described here.

After performing the same operation as with **open\_tree**(), **open\_tree\_attr**() will apply the mount attribute changes described in *attr* to the file descriptor before it is returned. (See [**mount\_attr**(2type)](/mount_attr/2type.md) for a description of the *mount\_attr* structure. As described in [**mount\_setattr**(2)](/mount_setattr/2.md), *size* must be set to *sizeof(struct mount\_attr)* in order to support future extensions.) If *attr* is NULL, or has *attr.attr\_clr*, *attr.attr\_set*, and *attr.propagation* all set to zero, then **open\_tree\_attr**() has identical behavior to **open\_tree**().

The application of *attr* to the resultant file descriptor has identical semantics to [**mount\_setattr**(2)](/mount_setattr/2.md), except for the following extensions and general caveats:

- •

  Unlike [**mount\_setattr**(2)](/mount_setattr/2.md) called with a regular **OPEN\_TREE\_CLONE** detached mount object from **open\_tree**(), **open\_tree\_attr**() can specify a different setting for **MOUNT\_ATTR\_IDMAP** to the original mount object cloned with **OPEN\_TREE\_CLONE**.

-

  Adding **MOUNT\_ATTR\_IDMAP** to *attr.attr\_clr* will disable ID-mapping for the new mount object; adding **MOUNT\_ATTR\_IDMAP** to *attr.attr\_set* will configure the mount object to have the ID-mapping defined by the user namespace referenced by the file descriptor *attr.userns\_fd*. (The semantics of which are identical to when [**mount\_setattr**(2)](/mount_setattr/2.md) is used to configure **MOUNT\_ATTR\_IDMAP**.)

-

  Changing or removing the mapping of an ID-mapped mount is only permitted if a new detached mount object is being created with *flags* including **OPEN\_TREE\_CLONE**.

- •

  If *flags* contains **AT\_RECURSIVE**, then the attributes described in *attr* are applied recursively (just as when [**mount\_setattr**(2)](/mount_setattr/2.md) is called with **AT\_RECURSIVE**). However, this applies in addition to the **open\_tree**()-specific behavior regarding **AT\_RECURSIVE**, and thus *flags* must also contain **OPEN\_TREE\_CLONE**.

Note that if *flags* does not contain **OPEN\_TREE\_CLONE**, **open\_tree\_attr**() will attempt to modify the mount attributes of the mount object attached at the path described by *dirfd* and *path*. As with [**mount\_setattr**(2)](/mount_setattr/2.md), if said path is not a mount point, **open\_tree\_attr**() will return an error.

## RETURN VALUE

On success, a new file descriptor is returned. On error, -1 is returned, and *errno* is set to indicate the error.

## ERRORS

- **EACCES**

  Search permission is denied for one of the directories in the path prefix of *path*. (See also [**path\_resolution**(7)](/path_resolution/7.md).)

- **EBADF**

  *path* is relative but *dirfd* is neither **AT\_FDCWD** nor a valid file descriptor.

- **EFAULT**

  *path* is NULL or a pointer to a location outside the calling process's accessible address space.

- **EINVAL**

  Invalid flag specified in *flags*.

- **ELOOP**

  Too many symbolic links encountered when resolving *path*.

- **EMFILE**

  The calling process has too many open files to create more.

- **ENAMETOOLONG**

  *path* is longer than **PATH\_MAX**.

- **ENFILE**

  The system has too many open files to create more.

- **ENOENT**

  A component of *path* does not exist, or is a dangling symbolic link.

- **ENOENT**

  *path* is an empty string, but **AT\_EMPTY\_PATH** is not specified in *flags*.

- **ENOTDIR**

  A component of the path prefix of *path* is not a directory, or *path* is relative and *dirfd* is a file descriptor referring to a file other than a directory.

- **ENOSPC**

  The "anonymous" mount namespace necessary to contain the **OPEN\_TREE\_CLONE** detached bind-mount mount object could not be allocated, as doing so would exceed the configured per-user limit on the number of mount namespaces in the current user namespace. (See also [**namespaces**(7)](/namespaces/7.md).)

- **ENOMEM**

  The kernel could not allocate sufficient memory to complete the operation.

- **EPERM**

  *flags* contains **OPEN\_TREE\_CLONE** but the calling process does not have the required **CAP\_SYS\_ADMIN** capability.

## STANDARDS

Linux.

## HISTORY

- **open\_tree**()

  Linux 5.2, glibc 2.36.

- **open\_tree\_attr**()

  Linux 6.15.

## NOTES

### Mount propagation

The bind-mount mount objects created by **open\_tree**() with **OPEN\_TREE\_CLONE** are not associated with the mount namespace of the calling process. Instead, each mount object is placed in a newly allocated "anonymous" mount namespace associated with the calling process.

One of the side-effects of this is that (unlike bind-mounts created with [**mount**(2)](/mount/2.md)), mount propagation (as described in [**mount\_namespaces**(7)](/mount_namespaces/7.md)) will not be applied to bind-mounts created by **open\_tree**() until the bind-mount is attached with [**move\_mount**(2)](/move_mount/2.md), at which point the mount object will be associated with the mount namespace where it was attached and mount propagation will resume. Note that any mount propagation events that occurred before the mount object was attached will *not* be propagated to the mount object, even after it is attached.

## EXAMPLES

The following examples show how **open\_tree**() can be used in place of more traditional [**mount**(2)](/mount/2.md) calls with **MS\_BIND**.

```
int srcfd = open_tree(AT_FDCWD, "/var", OPEN_TREE_CLONE);
move_mount(srcfd, "", AT_FDCWD, "/mnt", MOVE_MOUNT_F_EMPTY_PATH);
```

First, a detached bind-mount mount object of */var* is created and associated with the file descriptor *srcfd*. Then, the mount object is attached to */mnt* using [**move\_mount**(2)](/move_mount/2.md) with **MOVE\_MOUNT\_F\_EMPTY\_PATH** to request that the detached mount object associated with the file descriptor *srcfd* be moved (and thus attached) to */mnt*.

The above procedure is functionally equivalent to the following mount operation using [**mount**(2)](/mount/2.md):

```
mount("/var", "/mnt", NULL, MS_BIND, NULL);
```

**OPEN\_TREE\_CLONE** can be combined with **AT\_RECURSIVE** to create recursive detached bind-mount mount objects, which in turn can be attached to mount points to create recursive bind-mounts.

```
int srcfd = open_tree(AT_FDCWD, "/var",
                      OPEN_TREE_CLONE | AT_RECURSIVE);
move_mount(srcfd, "", AT_FDCWD, "/mnt", MOVE_MOUNT_F_EMPTY_PATH);
```

The above procedure is functionally equivalent to the following mount operation using [**mount**(2)](/mount/2.md):

```
mount("/var", "/mnt", NULL, MS_BIND | MS_REC, NULL);
```

One of the primary benefits of using **open\_tree**() and [**move\_mount**(2)](/move_mount/2.md) over the traditional [**mount**(2)](/mount/2.md) is that operating with *dirfd*-style file descriptors is far easier and more intuitive.

```
int srcfd = open_tree(100, "", AT_EMPTY_PATH | OPEN_TREE_CLONE);
move_mount(srcfd, "", 200, "foo", MOVE_MOUNT_F_EMPTY_PATH);
```

The above procedure is roughly equivalent to the following mount operation using [**mount**(2)](/mount/2.md):

```
mount("/proc/self/fd/100",
      "/proc/self/fd/200/foo",
      NULL, MS_BIND, NULL);
```

In addition, you can use the file descriptor returned by **open\_tree**() as the *dirfd* argument to any "\*at()" system calls:

```
int dirfd, fd;
dirfd = open_tree(AT_FDCWD, "/etc", OPEN_TREE_CLONE);
fd = openat(dirfd, "passwd", O_RDONLY);
fchmodat(dirfd, "shadow", 0000, 0);
close(dirfd);
close(fd);
/* The bind-mount is now destroyed */
```

### open\_tree\_attr()

The following is an example of how **open\_tree\_attr**() can be used to take an existing id-mapped mount and construct a new bind-mount mount object with a different **MOUNT\_ATTR\_IDMAP** attribute. The resultant detached mount object can be used like any other mount object returned by **open\_tree**().

```
int nsfd1, nsfd2;
int mntfd1, mntfd2, mntfd3;
struct mount_attr attr;
mntfd1 = open_tree(AT_FDCWD, "/foo", OPEN_TREE_CLONE);
/* Configure the id-mapping of mntfd1 */
nsfd1 = open("/proc/1234/ns/user", O_RDONLY);
memset(&attr, 0, sizeof(attr));
attr.attr_set = MOUNT_ATTR_IDMAP;
attr.userns_fd = nsfd1;
mount_setattr(mntfd1, "", AT_EMPTY_PATH, &attr, sizeof(attr));
/* Create a new copy with a different id-mapping */
nsfd2 = open("/proc/5678/ns/user", O_RDONLY);
memset(&attr, 0, sizeof(attr));
attr.attr_clr = MOUNT_ATTR_IDMAP;
attr.attr_set = MOUNT_ATTR_IDMAP;
attr.userns_fd = nsfd2;
mntfd2 = open_tree_attr(mntfd1, "", OPEN_TREE_CLONE,
                        &attr, sizeof(attr));
/* Create a new copy with the id-mapping cleared */
memset(&attr, 0, sizeof(attr));
attr.attr_clr = MOUNT_ATTR_IDMAP;
mntfd3 = open_tree_attr(mntfd1, "", OPEN_TREE_CLONE,
                        &attr, sizeof(attr));
```

**open\_tree\_attr**() can also be used with attached mount objects; the above example is only intended to be illustrative.

## SEE ALSO

[**fsconfig**(2)](/fsconfig/2.md), [**fsmount**(2)](/fsmount/2.md), [**fsopen**(2)](/fsopen/2.md), [**fspick**(2)](/fspick/2.md), [**mount**(2)](/mount/2.md), [**mount\_setattr**(2)](/mount_setattr/2.md), [**move\_mount**(2)](/move_mount/2.md), [**mount\_namespaces**(7)](/mount_namespaces/7.md)
