@@ -1122,11 +1122,14 @@ static __u32 fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark,
static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group,
fsnotify_connp_t *connp,
unsigned int obj_type,
+ unsigned int fan_flags,
__kernel_fsid_t *fsid)
{
struct ucounts *ucounts = group->fanotify_data.ucounts;
struct fsnotify_mark *mark;
int ret;
+ unsigned int fsn_flags = (fan_flags & FAN_MARK_VOLATILE) ?
+ FSNOTIFY_ADD_MARK_NO_IREF : 0;
/*
* Enforce per user marks limits per user in all containing user ns.
@@ -1144,7 +1147,7 @@ static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group,
}
fsnotify_init_mark(mark, group);
- ret = fsnotify_add_mark_locked(mark, connp, obj_type, 0, fsid);
+ ret = fsnotify_add_mark_locked(mark, connp, obj_type, fsn_flags, fsid);
if (ret) {
fsnotify_put_mark(mark);
goto out_dec_ucounts;
@@ -1180,7 +1183,8 @@ static int fanotify_add_mark(struct fsnotify_group *group,
mutex_lock(&group->mark_mutex);
fsn_mark = fsnotify_find_mark(connp, group);
if (!fsn_mark) {
- fsn_mark = fanotify_add_new_mark(group, connp, obj_type, fsid);
+ fsn_mark = fanotify_add_new_mark(group, connp, obj_type, flags,
+ fsid);
if (IS_ERR(fsn_mark)) {
mutex_unlock(&group->mark_mutex);
return PTR_ERR(fsn_mark);
@@ -1604,6 +1608,17 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
mark_type != FAN_MARK_FILESYSTEM)
goto fput_and_out;
+ /*
+ * Volatile is only relevant for inode, because only inode object can be
+ * evicted on memory pressure. Inode is pinned when attaching the mark
+ * to the inode, so require the FAN_MARK_CREATE flag to make sure that
+ * we are not updating an existing mark on a pinned inode.
+ */
+ if (flags & FAN_MARK_VOLATILE &&
+ (!(flags & FAN_MARK_CREATE) ||
+ mark_type != FAN_MARK_INODE))
+ goto fput_and_out;
+
/*
* Events that do not carry enough information to report
* event->fd require a group that supports reporting fid. Those
@@ -1756,7 +1771,7 @@ static int __init fanotify_user_setup(void)
BUILD_BUG_ON(FANOTIFY_INIT_FLAGS & FANOTIFY_INTERNAL_GROUP_FLAGS);
BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 12);
- BUILD_BUG_ON(HWEIGHT32(FANOTIFY_MARK_FLAGS) != 10);
+ BUILD_BUG_ON(HWEIGHT32(FANOTIFY_MARK_FLAGS) != 11);
fanotify_mark_cache = KMEM_CACHE(fsnotify_mark,
SLAB_PANIC|SLAB_ACCOUNT);
@@ -68,6 +68,7 @@
FAN_MARK_ONLYDIR | \
FAN_MARK_IGNORED_MASK | \
FAN_MARK_IGNORED_SURV_MODIFY | \
+ FAN_MARK_VOLATILE | \
FAN_MARK_CREATE)
/*
@@ -83,6 +83,7 @@
#define FAN_MARK_FLUSH 0x00000080
/* FAN_MARK_FILESYSTEM is 0x00000100 */
#define FAN_MARK_CREATE 0x00000200
+#define FAN_MARK_VOLATILE 0x00000400
/* These are NOT bitwise flags. Both bits can be used togther. */
#define FAN_MARK_INODE 0x00000000
When an inode mark is created with flag FAN_MARK_VOLATILE, it will not pin the marked inode to inode cache, so when inode is evicted from cache due to memory pressure, the mark will be lost. Volatile inode marks can be used to setup inode marks with ignored mask to suppress events from uninteresting files or directories in a lazy manner, upon receiving the first event, without having to iterate all the uninteresting files or directories before hand. The volatile inode mark feature allows performing this lazy marks setup without exhausting the system memory with pinned inodes. Link: https://lore.kernel.org/linux-fsdevel/CAOQ4uxiRDpuS=2uA6+ZUM7yG9vVU-u212tkunBmSnP_u=mkv=Q@mail.gmail.com/ Signed-off-by: Amir Goldstein <amir73il@gmail.com> --- fs/notify/fanotify/fanotify_user.c | 21 ++++++++++++++++++--- include/linux/fanotify.h | 1 + include/uapi/linux/fanotify.h | 1 + 3 files changed, 20 insertions(+), 3 deletions(-)