fsmount(2)

✨ fsmount(2) ✨ β€” it's giving instantiate mount object from filesystem context πŸ’…

okay bestie, sit down, hydrate, because we're doing a syscall today 🫢 this one lives in the System Calls Manual, and it's lowkey the moment where a whole filesystem finally gets its ✨mount✨ glow-up.


🌸 NAME 🌸

fsmount β€” instantiate mount object from filesystem context

πŸŽ€ LIBRARY πŸŽ€

Standard C library (libc, -lc)

πŸ¦‹ SYNOPSIS πŸ¦‹

#include <sys/mount.h>

int fsmount(int fsfd, unsigned int flags, unsigned int attr_flags);

πŸ’– DESCRIPTION πŸ’–

So fsmount() is part of the whole suite of file-descriptor-based mount facilities in Linux β€” the cool kids' table of mounting, basically. no cap.

fsmount() creates a brand new detached mount object for the root of the new filesystem instance referenced by the filesystem context file descriptor fsfd. Then it hands you back a new file descriptor associated with that detached mount object. ✨

and yeah, to make a mount object with fsmount(), the calling process must have the CAP_SYS_ADMIN capability. it's giving permission slip, bestie. πŸ“

The filesystem context has to have been created with a call to fsopen(2), and then had a filesystem instance instantiated with a call to fsconfig(2) using FSCONFIG_CMD_CREATE or FSCONFIG_CMD_CREATE_EXCL β€” that's the only way to be in the correct state for this operation. (The kernel devs call this the "awaiting-mount" mode, which is so dramatic of them, love that for them.)

And here's the tea β˜• β€” unlike open_tree(2) with OPEN_TREE_CLONE, fsmount() can only be called once in the lifetime of a filesystem context to produce a mount object. one shot. no reruns. periodt.

Same energy as the file descriptors you get from open_tree(2) called with OPEN_TREE_CLONE, the returned file descriptor can then be used with move_mount(2), mount_setattr(2), or other such system calls to do further mount operations. 🧚

If it never got attached to a mount point by calling move_mount(2), this mount object will be unmounted and destroyed when the file descriptor is closed. important!! 😭

⚠️ note that the unmount operation on close(2) is lazy β€” akin to calling umount2(2) with MNT_DETACH. Any existing open references to files from the mount object will keep working, and the mount object will only be completely destroyed once it ceases to be busy. so it's not ghosting you immediately, it's just... taking its time.

The returned file descriptor also acts exactly the same as one produced by open(2) with O_PATH, meaning it can also be used as a dirfd argument to "*at()" system calls. iconic versatility honestly πŸ’…

flags controls the creation of the returned file descriptor. You build a value for flags by bitwise ORing zero or more of these:

  • FSMOUNT_CLOEXEC β€” sets the close-on-exec (FD_CLOEXEC) flag on the new file descriptor. if you wanna know why that's useful, go read the description of the O_CLOEXEC flag in open(2), bestie, it's all there. πŸ”₯

attr_flags specifies the mount attributes which will be applied to the created mount object, in the form of MOUNT_ATTR_* flags. These flags are interpreted as though mount_setattr(2) was called with attr.attr_set set to the same value as attr_flags.

🚫 and listen β€” MOUNT_ATTR_* flags which would require specifying additional fields in mount_attr(2type) (such as MOUNT_ATTR_IDMAP) are not valid flag values for attr_flags. not invited to the party. πŸ™ˆ

oh and one more lil plot twist β€” if the fsmount() operation is successful, the filesystem context associated with the file descriptor fsfd is reset and placed into reconfiguration mode, as if it were just returned by fspick(2). You may continue to use fsconfig(2) with that now-reset filesystem context, including issuing the FSCONFIG_CMD_RECONFIGURE command to reconfigure the filesystem instance. she reinvented herself. main character energy πŸ‘‘


⭐ RETURN VALUE ⭐

  • On success: a new file descriptor is returned. slay. πŸŽ‰
  • On error: -1 is returned, and errno is set to indicate the error. πŸ’€

🌈 ERRORS 🌈

  • EBUSY β€” the filesystem context associated with fsfd is not in the right state to be used by fsmount(). wrong vibe. wrong moment.
  • EINVAL β€” flags had an invalid flag set. πŸ™…
  • EINVAL β€” attr_flags had an invalid MOUNT_ATTR_* flag set. also πŸ™… (yes, twice, they're different problems, don't @ me)
  • EMFILE β€” the calling process has too many open files to create more. bestie you have a hoarding problem.
  • ENFILE β€” the system has too many open files to create more. it's not you, it's everyone.
  • ENOSPC β€” the "anonymous" mount namespace necessary to contain the new mount object could not be allocated, because doing so would exceed the configured per-user limit on the number of mount namespaces in the current user namespace. (See also namespaces(7).) 😭
  • ENOMEM β€” the kernel could not allocate sufficient memory to complete the operation. no thoughts, no memory, head empty.
  • EPERM β€” the calling process does not have the required CAP_SYS_ADMIN capability. denied. go get your permissions sorted. 🫢

πŸ’œ STANDARDS πŸ’œ

Linux. 😌

πŸ“ HISTORY πŸ“

  • Linux 5.2.
  • glibc 2.36.

she's been around a minute and she's still thriving. ⭐


πŸ”₯ EXAMPLES πŸ”₯

okay here's the cute little code moment, showing off fsopen, fsconfig, fsmount, openat, unlinkat and move_mount all together. enjoy πŸ’–

int fsfd, mntfd, tmpfd;

fsfd = fsopen("tmpfs", FSOPEN_CLOEXEC);
fsconfig(fsfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0);
mntfd = fsmount(fsfd, FSMOUNT_CLOEXEC,
                MOUNT_ATTR_NODEV | MOUNT_ATTR_NOEXEC);

/* Create a new file without attaching the mount object */
tmpfd = openat(mntfd, "tmpfile", O_CREAT | O_EXCL | O_RDWR, 0600);
unlinkat(mntfd, "tmpfile", 0);

/* Attach the mount object to "/tmp" */
move_mount(mntfd, "", AT_FDCWD, "/tmp", MOVE_MOUNT_F_EMPTY_PATH);

πŸ‘‘ SEE ALSO πŸ‘‘

fsconfig(2), fsopen(2), fspick(2), mount(2), mount_setattr(2), move_mount(2), open_tree(2), mount_namespaces(7)


aaaand that's the whole page bestie πŸŽ€ go mount something responsibly. this one came from Linux man-pages 6.20, dated 2025-10-01, and yes she read the whole thing, no skimming, iykyk πŸ’…βœ¨πŸŒˆ

πŸ“¦ where this page comes from
  • arch rolling: man-pages 6.20-1 Β· BSD-2-Clause AND BSD-3-Clause AND BSD-4.3TAHOE AND BSD-4-Clause-UC AND GPL-1.0-or-later AND GPL-2.0-only AND GPL-2.0-or-later AND GPL-3.0-or-later AND LGPL-3.0-linking-exception AND LGPL-3.0-or-later AND LicenseRef-Public-Domain AND LicenseRef-UltraPermissive AND Linux-man-pages-1-para AND Linux-man-pages-copyleft AND Linux-man-pages-copyleft-2-para AND Linux-man-pages-copyleft-var AND MIT AND Spencer-94
  • nixpkgs unstable: man-pages 6.20
  • πŸ“œ the page's license: Linux-man-pages-copyleft
  • πŸ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms