fanotify_mark(2)
π fanotify_mark(2) π
okay so bestie, welcome to the System Calls Manual (section 2, the system calls girlies). Today's episode: fanotify_mark(2). It's long, it's giving saga, so we're doing it in parts β buckle up π
πΈ NAME πΈ
fanotify_mark β add, remove, or modify an fanotify mark on a filesystem object
π LIBRARY π
Standard C library (libc, -lc)
β¨ SYNOPSIS β¨
#include <sys/fanotify.h>
int fanotify_mark(int fanotify_fd, unsigned int flags,
uint64_t mask, int dirfd,
const char *_Nullable path);
π¦ DESCRIPTION π¦
okay so first things first, if you want the whole fanotify lore, go read fanotify(7) β that's the overview, this is the details.
fanotify_mark() does exactly what it says: it adds, removes, or modifies an fanotify mark on a filesystem object. And no, you can't just mark whatever you want β the caller must have read permission on the filesystem object that is to be marked. so rude but okay π«Ά
fanotify_fd is a file descriptor that came back from fanotify_init(2). that's the group you're marking stuff in.
flags is a bit mask that says what modification we're doing. It must include exactly one of these three, no more no less:
FAN_MARK_ADDβ the events inmaskget added to the mark mask (or to the ignore mask).maskmust be nonempty or you get the errorEINVAL. periodt.FAN_MARK_REMOVEβ the events in themaskargument get removed from the mark mask (or from the ignore mask).maskmust be nonempty or, again,EINVAL.FAN_MARK_FLUSHβ wipe either all marks for filesystems, all marks for mounts, or all marks for directories and files, all from the fanotify group. IfflagscontainsFAN_MARK_MOUNT, all marks for mounts get removed from the group. IfflagscontainsFAN_MARK_FILESYSTEM, all marks for filesystems get removed from the group. Otherwise, all marks for directories and files get removed. And listen: no flag other than, and at most one of, the flagsFAN_MARK_MNTNS,FAN_MARK_MOUNT, orFAN_MARK_FILESYSTEMcan be used in conjunction withFAN_MARK_FLUSH.maskis ignored, she's not part of this conversation.
and if none of those three values is specified, or more than one is specified, the call fails with the error EINVAL. exactly one bestie, we don't do indecision here π
π the "you may OR these in" flags π
In addition, zero or more of the following values may be ORed into flags:
FAN_MARK_DONT_FOLLOWβ ifpathis a symbolic link, mark the link itself instead of the file it points at. (by default,fanotify_mark()dereferencespathif it's a symbolic link β so this flag is you saying "no, the link, I said what I said".)FAN_MARK_ONLYDIRβ if the filesystem object to be marked is not a directory, the errorENOTDIRshall be raised. directories only, gatekept β¨FAN_MARK_MNTNS(since Linux 6.14) β mark the mount namespace specified bypath. Ifpathdoesn't represent a mount namespace (e.g./proc/pid/ns/mnt), the call fails with the errorEINVAL. You also need an fanotify group that was initialized with the flagFAN_REPORT_MNT. no group, no mntns, sorry.FAN_MARK_MOUNTβ mark the mount specified bypath. Ifpathis not itself a mount point, the mount containingpathgets marked. all directories, subdirectories, and the contained files of the mount get monitored π The events which require that filesystem objects are identified by file handles β likeFAN_CREATE,FAN_ATTRIB,FAN_MOVE, andFAN_DELETE_SELFβ cannot be provided as a mask whenflagscontainsFAN_MARK_MOUNT. Trying it anyway returns the errorEINVAL. Also, using this flag requires theCAP_SYS_ADMINcapability. big girl privileges fr fr.FAN_MARK_FILESYSTEM(since Linux 4.20) β mark the filesystem specified bypath. The filesystem containingpathgets marked. all the contained files and directories of the filesystem, from any mount point, get monitored. Using this flag requires theCAP_SYS_ADMINcapability.FAN_MARK_IGNORED_MASKβ the events inmaskshall be added to or removed from the ignore mask. β οΈ note that the flagsFAN_ONDIRandFAN_EVENT_ON_CHILDhave no effect when provided with this flag. And the effect of settingFAN_ONDIRandFAN_EVENT_ON_CHILDin the mark mask on the events set in the ignore mask is undefined and depends on the Linux kernel version β so like, genuinely don't rely on it π Specifically: prior to Linux 5.9, setting a mark mask on a file and a mark with ignore mask on its parent directory would not result in ignoring events on the file, regardless of theFAN_EVENT_ON_CHILDflag in the parent directory's mark mask. Also, when the ignore mask is updated with theFAN_MARK_IGNORED_MASKflag on a mark that was previously updated with theFAN_MARK_IGNOREflag, the update fails withEEXISTerror.FAN_MARK_IGNORE(since Linux 6.0, 5.15.154, and 5.10.220) β similar vibe to setting theFAN_MARK_IGNORED_MASKflag: the events inmaskshall be added to or removed from the ignore mask. BUT, unlikeFAN_MARK_IGNORED_MASK, this flag also means theFAN_ONDIRandFAN_EVENT_ON_CHILDflags actually take effect on the ignore mask. Concretely: unless theFAN_ONDIRflag is set withFAN_MARK_IGNORE, events on directories will not be ignored. And if the flagFAN_EVENT_ON_CHILDis set withFAN_MARK_IGNORE, events on children will be ignored. Example time, bestie: a mark on a directory with a combination of a mask with theFAN_CREATEevent and theFAN_ONDIRflag, plus an ignore mask with theFAN_CREATEevent and withoutFAN_ONDIR, results in getting only the events for creation of sub-directories. Also, when you use theFAN_MARK_IGNOREflag to add to an ignore mask of a mount, filesystem, or directory inode mark, theFAN_MARK_IGNORED_SURV_MODIFYflag must be specified β fail to do that and you getEINVALorEISDIRerror.FAN_MARK_IGNORED_SURV_MODIFYβ the ignore mask shall survive modify events. If this flag is not set, the ignore mask is cleared whenever a modify event occurs on the marked object. omitting this flag is typically used to suppress events (e.g.,FAN_OPEN) for one specific file, until that specific file's content has been modified. It's far less useful to suppress events on an entire filesystem, or mount, or on all files inside a directory, until some file's content has been modified β like, imagine. For this reason, theFAN_MARK_IGNOREflag requires theFAN_MARK_IGNORED_SURV_MODIFYflag on a mount, filesystem, or directory inode mark. And heads up: this flag cannot be removed from a mark once set. When the ignore mask is updated without this flag on a mark that was previously updated with theFAN_MARK_IGNOREandFAN_MARK_IGNORED_SURV_MODIFYflags, the update fails withEEXISTerror.FAN_MARK_IGNORE_SURVβ a synonym for (FAN_MARK_IGNORE|FAN_MARK_IGNORED_SURV_MODIFY). cute lil shorthand, we love a combo deal πFAN_MARK_EVICTABLE(since Linux 5.19, 5.15.154, and 5.10.220) β when an inode mark is created with this flag, the inode object will not be pinned to the inode cache, therefore allowing the inode object to be evicted from the inode cache when the memory pressure on the system is high. the catch? the eviction of the inode object results in the evictable mark also being lost. When the mask of an evictable inode mark is updated without using theFAN_MARK_EVICATBLEflag, the marked inode is pinned to inode cache and the mark is no longer evictable. And when the mask of a non-evictable inode mark is updated with theFAN_MARK_EVICTABLEflag, the inode mark remains non-evictable and the update fails withEEXISTerror. Mounts and filesystems are not evictable objects, so an attempt to create a mount mark or a filesystem mark with theFAN_MARK_EVICTABLEflag results in the errorEINVAL. For example, inode marks can be used in combination with mount marks to reduce the amount of events from noninteresting paths: the event listener reads events, checks if the path reported in the event is of interest, and if it is not, the listener sets a mark with an ignore mask on the directory. Evictable inode marks let you use this method for a large number of directories without the concern of pinning all inodes and exhausting the system's memory. memory-safe queen π
π what mask actually means π
mask defines which events shall be listened for (or which shall be ignored). It's a bit mask composed of the following values:
FAN_ACCESSβ create an event when a file or directory (but see BUGS) is accessed (read).FAN_MODIFYβ create an event when a file is modified (write).FAN_CLOSE_WRITEβ create an event when a writable file is closed.FAN_CLOSE_NOWRITEβ create an event when a read-only file or directory is closed.FAN_OPENβ create an event when a file or directory is opened.FAN_OPEN_EXEC(since Linux 5.0) β create an event when a file is opened with the intent to be executed. see NOTES for additional details.FAN_ATTRIB(since Linux 5.1) β create an event when the metadata for a file or directory has changed. requires an fanotify group that identifies filesystem objects by file handles.FAN_CREATE(since Linux 5.1) β create an event when a file or directory has been created in a marked parent directory. requires an fanotify group that identifies filesystem objects by file handles.FAN_DELETE(since Linux 5.1) β create an event when a file or directory has been deleted in a marked parent directory. requires an fanotify group that identifies filesystem objects by file handles.FAN_DELETE_SELF(since Linux 5.1) β create an event when a marked file or directory itself is deleted. requires an fanotify group that identifies filesystem objects by file handles.FAN_MOVED_FROM(since Linux 5.1) β create an event when a file or directory has been moved from a marked parent directory. requires an fanotify group that identifies filesystem objects by file handles.FAN_MOVED_TO(since Linux 5.1) β create an event when a file or directory has been moved to a marked parent directory. requires an fanotify group that identifies filesystem objects by file handles.FAN_RENAME(since Linux 5.17, 5.15.154, and 5.10.220) β this event contains the same information provided by the eventsFAN_MOVED_FROMandFAN_MOVED_TO, however it's represented by a single event with up to two information records. requires an fanotify group that identifies filesystem objects by file handles. And if the filesystem object to be marked is not a directory, the errorENOTDIRshall be raised. one event, two records, main character energy βFAN_MOVE_SELF(since Linux 5.1) β bestie, this one fires when a marked file or directory itself gets moved. That's the whole object sliding somewhere else. You need an fanotify group that identifies filesystem objects by file handles, no exceptions, periodt.FAN_MNT_ATTACH,FAN_MNT_DETACH(both since Linux 6.14) β one event for when a mount gets attached to a marked mount namespace, one for when it gets detached π . If you try to set either of these on an inode, mount, or filesystem mark? Boom,EINVAL. You need an fanotify group initialized with the flagFAN_REPORT_MNTplus the mark flagFAN_MARK_MNTNS. Oh and you get an extra info record of typeFAN_EVENT_INFO_TYPE_MNTriding along with the event. More deets infanotify(7), iykyk.FAN_FS_ERROR(since Linux 5.16, 5.15.154, and 5.10.220) β fires when a filesystem error that leads to inconsistent filesystem metadata gets detected π. Every event in the read buffer gets an extra information record of typeFAN_EVENT_INFO_TYPE_ERROR. Needs an fanotify group that identifies filesystem objects by file handles. Also β and this is the tea β these events depend on the underlying filesystem actually supporting them. At the time of writing,ext4is literally the only one reportingFAN_FS_ERRORevents. Seefanotify(7)for more.FAN_OPEN_PERMβ fires when permission to open a file or directory is requested. You need an fanotify file descriptor created withFAN_CLASS_PRE_CONTENTorFAN_CLASS_CONTENT. πFAN_OPEN_EXEC_PERM(since Linux 5.0) β fires when permission to open a file for execution is requested π. Same deal: fanotify file descriptor created withFAN_CLASS_PRE_CONTENTorFAN_CLASS_CONTENT. Peep the NOTES section for the extra lore.FAN_ACCESS_PERMβ fires when permission to read a file or directory is requested. Yep, you guessed it: fanotify file descriptor created withFAN_CLASS_PRE_CONTENTorFAN_CLASS_CONTENTis required.FAN_PRE_ACCESS(since Linux 6.14) β this one is so iconic tbh. It fires before read or write access to a file range, which gives the event listener a chance to modify the file content before anything gets accessed in that specified range β¨. You get an extra info record of typeFAN_EVENT_INFO_TYPE_RANGEfor each event in the read buffer. Needs an fanotify file descriptor created withFAN_CLASS_PRE_CONTENT.FAN_ONDIRβ create events for directories too π β like whenopendir(3),readdir(3)(but check BUGS), andclosedir(3)get called. Without this flag you only get events for files, rip. And for directory entry events likeFAN_CREATE,FAN_DELETE,FAN_MOVED_FROM, andFAN_MOVED_TO? SpecifyingFAN_ONDIRis required if you want events when subdirectory entries get modified (that'smkdir(2)/rmdir(2)bestie).FAN_EVENT_ON_CHILDβ events for the immediate children of marked directories get created. Lowkey important: this flag does absolutely nothing when you're marking mounts and filesystems. Also, events are not generated for children of the subdirectories of marked directories. More specifically, the directory entry modification eventsFAN_CREATE,FAN_DELETE,FAN_MOVED_FROM, andFAN_MOVED_TOare not generated for any entry modifications performed inside subdirectories of marked directories. And heads up βFAN_DELETE_SELFandFAN_MOVE_SELFare not generated for children of marked directories either. So if you wanna monitor whole-ass directory trees, you have to mark the relevant mount or filesystem. No shortcuts bestie π.
The following composed values are defined:
FAN_CLOSEβ a file is closed (FAN_CLOSE_WRITE|FAN_CLOSE_NOWRITE).FAN_MOVEβ a file or directory has been moved (FAN_MOVED_FROM|FAN_MOVED_TO).
So, which filesystem object are we actually marking here? That's decided by the file descriptor dirfd and the pathname in path πΈ:
- If
pathisNULL, thendirfddefines the filesystem object to be marked. - If
pathis absolute, it defines the filesystem object to be marked, anddirfdgets ignored (sorrydirfd, not your moment). - If
pathis relative, anddirfddoes not have the valueAT_FDCWD, then the filesystem object to be marked is determined by interpretingpathrelative to the directory referred to bydirfd. - If
pathis relative, anddirfddoes have the valueAT_FDCWD, then the filesystem object to be marked is determined by interpretingpathrelative to the current working directory. (Peepopenat(2)if you're wondering why thedirfdargument is even useful β it's a whole thing.)
β¨ RETURN VALUE β¨
Slayed successfully? fanotify_mark() returns 0 π. If it goes wrong, -1 comes back and errno gets set to tell you what happened.
π ERRORS π
EBADFβ an invalid file descriptor was passed infanotify_fd.EBADFβpathis relative butdirfdis neitherAT_FDCWDnor a valid file descriptor.EEXISTβ the filesystem object indicated bydirfdandpathhas a mark that was updated without theFAN_MARK_EVICTABLEflag, and you tried to update the mark with theFAN_MARK_EVICTABLEflag. Pick a lane bestie π.EEXISTβ the filesystem object indicated bydirfdandpathhas a mark that was updated with theFAN_MARK_IGNOREflag, and you tried to update the mark with theFAN_MARK_IGNORED_MASKflag.EEXISTβ the filesystem object indicated bydirfdandpathhas a mark that was updated with theFAN_MARK_IGNOREandFAN_MARK_IGNORED_SURV_MODIFYflags, and you tried to update the mark only with theFAN_MARK_IGNOREflag.EINVALβ an invalid value was passed inflagsormask, orfanotify_fdwas not an fanotify file descriptor.EINVALβ the fanotify file descriptor was opened withFAN_CLASS_NOTIF, or the fanotify group identifies filesystem objects by file handles andmaskcontains a flag for permission events (FAN_OPEN_PERMorFAN_ACCESS_PERM).EINVALβ the group was initialized withoutFAN_REPORT_FIDbut one or more event types specified in themaskrequire it.EINVALβflagscontainsFAN_MARK_IGNORE, and eitherFAN_MARK_MOUNTorFAN_MARK_FILESYSTEM, but does not containFAN_MARK_IGNORED_SURV_MODIFY.EISDIRβflagscontainsFAN_MARK_IGNORE, but does not containFAN_MARK_IGNORED_SURV_MODIFY, anddirfdandpathspecify a directory.ENODEVβ the filesystem object indicated bydirfdandpathis associated with a filesystem that reports zerofsid(e.g.,fuse(4)). This error can be returned only with an fanotify group that identifies filesystem objects by file handles. Since Linux 6.8, this error can also be returned when trying to add a mount or filesystem mark.ENOENTβ the filesystem object indicated bydirfdandpathdoes not exist. This error also happens when you try to remove a mark from an object that isn't marked. Awkward π.ENOMEMβ the necessary memory could not be allocated.ENOSPCβ the number of marks for this user exceeds the limit and theFAN_UNLIMITED_MARKSflag was not specified when the fanotify file descriptor was created withfanotify_init(2). Seefanotify(7)for details about this limit.ENOSYSβ this kernel does not implementfanotify_mark(). The fanotify API is available only if the kernel was configured withCONFIG_FANOTIFY.ENOTDIRβflagscontainsFAN_MARK_ONLYDIR, anddirfdandpathdo not specify a directory.ENOTDIRβmaskcontainsFAN_RENAME, anddirfdandpathdo not specify a directory.ENOTDIRβflagscontainsFAN_MARK_IGNORE, or the fanotify group was initialized with flagFAN_REPORT_TARGET_FID, andmaskcontains directory entry modification events (e.g.,FAN_CREATE,FAN_DELETE), or directory event flags (e.g.,FAN_ONDIR,FAN_EVENT_ON_CHILD), anddirfdandpathdo not specify a directory.EOPNOTSUPPβ the object indicated bypathis associated with a filesystem that does not support the encoding of file handles. This error can be returned only with an fanotify group that identifies filesystem objects by file handles. Callingname_to_handle_at(2)with the flagAT_HANDLE_FID(since Linux 6.5) can be used as a test to check if a filesystem supports reporting events with file handles.EPERMβ the operation is not permitted because the caller lacks a required capability.EXDEVβ the filesystem object indicated bypathresides within a filesystem subvolume (e.g.,btrfs(5)) which uses a differentfsidthan its root superblock. This error can be returned only with an fanotify group that identifies filesystem objects by file handles. Since Linux 6.8, this error will be returned when trying to add a mount or filesystem mark on a subvolume, when trying to add inode marks in different subvolumes, or when trying to add inode marks in abtrfs(5)subvolume and in another filesystem. Since Linux 6.8, this error will also be returned when trying to add marks in different filesystems, where one of the filesystems reports zerofsid(e.g.,fuse(4)).
π STANDARDS π
Linux. That's it, that's the standard π .
π HISTORY π
Linux 2.6.37.
π NOTES π
FAN_OPEN_EXEC and FAN_OPEN_EXEC_PERM
When you use either FAN_OPEN_EXEC or FAN_OPEN_EXEC_PERM inside the mask, events of these types only get returned when a program is executed directly π«. More specifically? That means these events get generated for files opened using execve(2), execveat(2), or uselib(2). They will not be raised when an interpreter is passed (or reads) a file for interpretation. So no sneak-attack exec events via the interpreter bestie π.
Also, if a mark has also been placed on the Linux dynamic linker, expect to receive an event for it too when an ELF object has been successfully opened using execve(2) or execveat(2).
For example, if the following ELF binary were to be invoked and a FAN_OPEN_EXEC mark has been placed on /:
$ /bin/echo foo
The listening application in this case would receive FAN_OPEN_EXEC events for both the ELF binary and interpreter, respectively:
/bin/echo
/lib64/ld-linux-x86-64.so.2
π BUGS π
The following bugs were present in before Linux 3.16 β yeah, old-school, but we're keeping the receipts:
- If
flagscontainsFAN_MARK_FLUSH,dirfdandpathmust specify a valid filesystem object, even though this object is not used. readdir(2)does not generate aFAN_ACCESSevent.- If
fanotify_mark()is called withFAN_MARK_FLUSH,flagsis not checked for invalid values.
β¨ SEE ALSO β¨
okay bestie, you're not done yet β these two are literally the other halves of this whole situation, go read them π
fanotify_init(2)β the one that makes the fanotify group in the first place. you literally cannotfanotify_mark()nothing, so start here bb π±fanotify(7)β the big-picture overview page. the lore. the worldbuilding. the whole fanotify cinematic universe π¬
and that's the whole page, bestie!! you made it to the end, i'm so proud of you π₯Ήπ«Ά
this lil masterpiece comes to you from Linux man-pages 6.20, dated 2026-06-04 β so yeah, freshly dated, no dusty vibes π
now go forth, mark some files, and remember: reading the whole manpage before you ship is main character energy πβ¨ no cap.
π¦ 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