On Tue, Mar 19, 2024 at 1:11 AM Sasha Levin <sashal@xxxxxxxxxx> wrote: > > This is a note to let you know that I've just added the patch titled > > fanotify: introduce group flag FAN_REPORT_TARGET_FID > > to the 5.15-stable tree which can be found at: > http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary > > The filename of the patch is: > fanotify-introduce-group-flag-fan_report_target_fid.patch > and it can be found in the queue-5.15 subdirectory. > > If you, or anyone else, feels it should not be added to the stable tree, > please let <stable@xxxxxxxxxxxxxxx> know about it. > Hi Chuck, Please follow up with update of man page fanotify_init(2) after merge: FAN_REPORT_TARGET_FID (since Linux 5.17) For the records, the following fix commit are explicitly mentioned in test fanotify14: .tags = (const struct tst_tag[]) { {"linux-git", "ceaf69f8eadc"}, {"linux-git", "8698e3bab4dd"}, Because we took the opportunity of new API flags (FAN_RENAME and FAN_REPORT_TARGET_FID) to refine the semantics of some legacy undefined behavior. Since you backported both those commits, no further action item here. Thanks, Amir. > > > commit 590125f72397ab80cf7946dec01a3f5d700e530e > Author: Amir Goldstein <amir73il@xxxxxxxxx> > Date: Mon Nov 29 22:15:29 2021 +0200 > > fanotify: introduce group flag FAN_REPORT_TARGET_FID > > [ Upstream commit d61fd650e9d206a71fda789f02a1ced4b19944c4 ] > > FAN_REPORT_FID is ambiguous in that it reports the fid of the child for > some events and the fid of the parent for create/delete/move events. > > The new FAN_REPORT_TARGET_FID flag is an implicit request to report > the fid of the target object of the operation (a.k.a the child inode) > also in create/delete/move events in addition to the fid of the parent > and the name of the child. > > To reduce the test matrix for uninteresting use cases, the new > FAN_REPORT_TARGET_FID flag requires both FAN_REPORT_NAME and > FAN_REPORT_FID. The convenience macro FAN_REPORT_DFID_NAME_TARGET > combines FAN_REPORT_TARGET_FID with all the required flags. > > Link: https://lore.kernel.org/r/20211129201537.1932819-4-amir73il@xxxxxxxxx > Signed-off-by: Amir Goldstein <amir73il@xxxxxxxxx> > Signed-off-by: Jan Kara <jack@xxxxxxx> > Signed-off-by: Chuck Lever <chuck.lever@xxxxxxxxxx> > > diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c > index 652fe84cb8acd..85e542b164c8c 100644 > --- a/fs/notify/fanotify/fanotify.c > +++ b/fs/notify/fanotify/fanotify.c > @@ -458,17 +458,41 @@ static int fanotify_encode_fh(struct fanotify_fh *fh, struct inode *inode, > } > > /* > - * The inode to use as identifier when reporting fid depends on the event. > - * Report the modified directory inode on dirent modification events. > - * Report the "victim" inode otherwise. > + * FAN_REPORT_FID is ambiguous in that it reports the fid of the child for > + * some events and the fid of the parent for create/delete/move events. > + * > + * With the FAN_REPORT_TARGET_FID flag, the fid of the child is reported > + * also in create/delete/move events in addition to the fid of the parent > + * and the name of the child. > + */ > +static inline bool fanotify_report_child_fid(unsigned int fid_mode, u32 mask) > +{ > + if (mask & ALL_FSNOTIFY_DIRENT_EVENTS) > + return (fid_mode & FAN_REPORT_TARGET_FID); > + > + return (fid_mode & FAN_REPORT_FID) && !(mask & FAN_ONDIR); > +} > + > +/* > + * The inode to use as identifier when reporting fid depends on the event > + * and the group flags. > + * > + * With the group flag FAN_REPORT_TARGET_FID, always report the child fid. > + * > + * Without the group flag FAN_REPORT_TARGET_FID, report the modified directory > + * fid on dirent events and the child fid otherwise. > + * > * For example: > - * FS_ATTRIB reports the child inode even if reported on a watched parent. > - * FS_CREATE reports the modified dir inode and not the created inode. > + * FS_ATTRIB reports the child fid even if reported on a watched parent. > + * FS_CREATE reports the modified dir fid without FAN_REPORT_TARGET_FID. > + * and reports the created child fid with FAN_REPORT_TARGET_FID. > */ > static struct inode *fanotify_fid_inode(u32 event_mask, const void *data, > - int data_type, struct inode *dir) > + int data_type, struct inode *dir, > + unsigned int fid_mode) > { > - if (event_mask & ALL_FSNOTIFY_DIRENT_EVENTS) > + if ((event_mask & ALL_FSNOTIFY_DIRENT_EVENTS) && > + !(fid_mode & FAN_REPORT_TARGET_FID)) > return dir; > > return fsnotify_data_inode(data, data_type); > @@ -647,10 +671,11 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, > { > struct fanotify_event *event = NULL; > gfp_t gfp = GFP_KERNEL_ACCOUNT; > - struct inode *id = fanotify_fid_inode(mask, data, data_type, dir); > + unsigned int fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS); > + struct inode *id = fanotify_fid_inode(mask, data, data_type, dir, > + fid_mode); > struct inode *dirid = fanotify_dfid_inode(mask, data, data_type, dir); > const struct path *path = fsnotify_data_path(data, data_type); > - unsigned int fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS); > struct mem_cgroup *old_memcg; > struct inode *child = NULL; > bool name_event = false; > @@ -660,11 +685,10 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, > > if ((fid_mode & FAN_REPORT_DIR_FID) && dirid) { > /* > - * With both flags FAN_REPORT_DIR_FID and FAN_REPORT_FID, we > - * report the child fid for events reported on a non-dir child > + * For certain events and group flags, report the child fid > * in addition to reporting the parent fid and maybe child name. > */ > - if ((fid_mode & FAN_REPORT_FID) && id != dirid && !ondir) > + if (fanotify_report_child_fid(fid_mode, mask) && id != dirid) > child = id; > > id = dirid; > diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c > index e8f6c843e9204..bfafda0447ea7 100644 > --- a/fs/notify/fanotify/fanotify_user.c > +++ b/fs/notify/fanotify/fanotify_user.c > @@ -1275,6 +1275,15 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) > if ((fid_mode & FAN_REPORT_NAME) && !(fid_mode & FAN_REPORT_DIR_FID)) > return -EINVAL; > > + /* > + * FAN_REPORT_TARGET_FID requires FAN_REPORT_NAME and FAN_REPORT_FID > + * and is used as an indication to report both dir and child fid on all > + * dirent events. > + */ > + if ((fid_mode & FAN_REPORT_TARGET_FID) && > + (!(fid_mode & FAN_REPORT_NAME) || !(fid_mode & FAN_REPORT_FID))) > + return -EINVAL; > + > f_flags = O_RDWR | FMODE_NONOTIFY; > if (flags & FAN_CLOEXEC) > f_flags |= O_CLOEXEC; > @@ -1685,7 +1694,7 @@ static int __init fanotify_user_setup(void) > FANOTIFY_DEFAULT_MAX_USER_MARKS); > > BUILD_BUG_ON(FANOTIFY_INIT_FLAGS & FANOTIFY_INTERNAL_GROUP_FLAGS); > - BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 11); > + BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 12); > BUILD_BUG_ON(HWEIGHT32(FANOTIFY_MARK_FLAGS) != 9); > > fanotify_mark_cache = KMEM_CACHE(fsnotify_mark, > diff --git a/include/linux/fanotify.h b/include/linux/fanotify.h > index 616af2ea20f30..376e050e6f384 100644 > --- a/include/linux/fanotify.h > +++ b/include/linux/fanotify.h > @@ -25,7 +25,7 @@ extern struct ctl_table fanotify_table[]; /* for sysctl */ > > #define FANOTIFY_CLASS_BITS (FAN_CLASS_NOTIF | FANOTIFY_PERM_CLASSES) > > -#define FANOTIFY_FID_BITS (FAN_REPORT_FID | FAN_REPORT_DFID_NAME) > +#define FANOTIFY_FID_BITS (FAN_REPORT_DFID_NAME_TARGET) > > #define FANOTIFY_INFO_MODES (FANOTIFY_FID_BITS | FAN_REPORT_PIDFD) > > diff --git a/include/uapi/linux/fanotify.h b/include/uapi/linux/fanotify.h > index bd1932c2074d5..60f73639a896a 100644 > --- a/include/uapi/linux/fanotify.h > +++ b/include/uapi/linux/fanotify.h > @@ -57,9 +57,13 @@ > #define FAN_REPORT_FID 0x00000200 /* Report unique file id */ > #define FAN_REPORT_DIR_FID 0x00000400 /* Report unique directory id */ > #define FAN_REPORT_NAME 0x00000800 /* Report events with name */ > +#define FAN_REPORT_TARGET_FID 0x00001000 /* Report dirent target id */ > > /* Convenience macro - FAN_REPORT_NAME requires FAN_REPORT_DIR_FID */ > #define FAN_REPORT_DFID_NAME (FAN_REPORT_DIR_FID | FAN_REPORT_NAME) > +/* Convenience macro - FAN_REPORT_TARGET_FID requires all other FID flags */ > +#define FAN_REPORT_DFID_NAME_TARGET (FAN_REPORT_DFID_NAME | \ > + FAN_REPORT_FID | FAN_REPORT_TARGET_FID) > > /* Deprecated - do not use this in programs and do not add new flags here! */ > #define FAN_ALL_INIT_FLAGS (FAN_CLOEXEC | FAN_NONBLOCK | \