@@ -592,21 +592,28 @@ static struct fanotify_event *fanotify_alloc_name_event(struct inode *dir,
592592 __kernel_fsid_t * fsid ,
593593 const struct qstr * name ,
594594 struct inode * child ,
595+ struct dentry * moved ,
595596 unsigned int * hash ,
596597 gfp_t gfp )
597598{
598599 struct fanotify_name_event * fne ;
599600 struct fanotify_info * info ;
600601 struct fanotify_fh * dfh , * ffh ;
602+ struct inode * dir2 = moved ? d_inode (moved -> d_parent ) : NULL ;
603+ const struct qstr * name2 = moved ? & moved -> d_name : NULL ;
601604 unsigned int dir_fh_len = fanotify_encode_fh_len (dir );
605+ unsigned int dir2_fh_len = fanotify_encode_fh_len (dir2 );
602606 unsigned int child_fh_len = fanotify_encode_fh_len (child );
603607 unsigned long name_len = name ? name -> len : 0 ;
608+ unsigned long name2_len = name2 ? name2 -> len : 0 ;
604609 unsigned int len , size ;
605610
606611 /* Reserve terminating null byte even for empty name */
607- size = sizeof (* fne ) + name_len + 1 ;
612+ size = sizeof (* fne ) + name_len + name2_len + 2 ;
608613 if (dir_fh_len )
609614 size += FANOTIFY_FH_HDR_LEN + dir_fh_len ;
615+ if (dir2_fh_len )
616+ size += FANOTIFY_FH_HDR_LEN + dir2_fh_len ;
610617 if (child_fh_len )
611618 size += FANOTIFY_FH_HDR_LEN + child_fh_len ;
612619 fne = kmalloc (size , gfp );
@@ -623,6 +630,11 @@ static struct fanotify_event *fanotify_alloc_name_event(struct inode *dir,
623630 len = fanotify_encode_fh (dfh , dir , dir_fh_len , hash , 0 );
624631 fanotify_info_set_dir_fh (info , len );
625632 }
633+ if (dir2_fh_len ) {
634+ dfh = fanotify_info_dir2_fh (info );
635+ len = fanotify_encode_fh (dfh , dir2 , dir2_fh_len , hash , 0 );
636+ fanotify_info_set_dir2_fh (info , len );
637+ }
626638 if (child_fh_len ) {
627639 ffh = fanotify_info_file_fh (info );
628640 len = fanotify_encode_fh (ffh , child , child_fh_len , hash , 0 );
@@ -632,11 +644,22 @@ static struct fanotify_event *fanotify_alloc_name_event(struct inode *dir,
632644 fanotify_info_copy_name (info , name );
633645 * hash ^= full_name_hash ((void * )name_len , name -> name , name_len );
634646 }
647+ if (name2_len ) {
648+ fanotify_info_copy_name2 (info , name2 );
649+ * hash ^= full_name_hash ((void * )name2_len , name2 -> name ,
650+ name2_len );
651+ }
635652
636653 pr_debug ("%s: size=%u dir_fh_len=%u child_fh_len=%u name_len=%u name='%.*s'\n" ,
637654 __func__ , size , dir_fh_len , child_fh_len ,
638655 info -> name_len , info -> name_len , fanotify_info_name (info ));
639656
657+ if (dir2_fh_len ) {
658+ pr_debug ("%s: dir2_fh_len=%u name2_len=%u name2='%.*s'\n" ,
659+ __func__ , dir2_fh_len , info -> name2_len ,
660+ info -> name2_len , fanotify_info_name2 (info ));
661+ }
662+
640663 return & fne -> fae ;
641664}
642665
@@ -692,6 +715,7 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
692715 struct inode * dirid = fanotify_dfid_inode (mask , data , data_type , dir );
693716 const struct path * path = fsnotify_data_path (data , data_type );
694717 struct mem_cgroup * old_memcg ;
718+ struct dentry * moved = NULL ;
695719 struct inode * child = NULL ;
696720 bool name_event = false;
697721 unsigned int hash = 0 ;
@@ -727,6 +751,15 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
727751 } else if ((mask & ALL_FSNOTIFY_DIRENT_EVENTS ) || !ondir ) {
728752 name_event = true;
729753 }
754+
755+ /*
756+ * In the special case of FAN_RENAME event, we record both
757+ * old and new parent+name.
758+ * 'dirid' and 'file_name' are the old parent+name and
759+ * 'moved' has the new parent+name.
760+ */
761+ if (mask & FAN_RENAME )
762+ moved = fsnotify_data_dentry (data , data_type );
730763 }
731764
732765 /*
@@ -748,9 +781,9 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
748781 } else if (fanotify_is_error_event (mask )) {
749782 event = fanotify_alloc_error_event (group , fsid , data ,
750783 data_type , & hash );
751- } else if (name_event && (file_name || child )) {
752- event = fanotify_alloc_name_event (id , fsid , file_name , child ,
753- & hash , gfp );
784+ } else if (name_event && (file_name || moved || child )) {
785+ event = fanotify_alloc_name_event (dirid , fsid , file_name , child ,
786+ moved , & hash , gfp );
754787 } else if (fid_mode ) {
755788 event = fanotify_alloc_fid_event (id , fsid , & hash , gfp );
756789 } else {
@@ -860,6 +893,7 @@ static int fanotify_handle_event(struct fsnotify_group *group, u32 mask,
860893 BUILD_BUG_ON (FAN_OPEN_EXEC != FS_OPEN_EXEC );
861894 BUILD_BUG_ON (FAN_OPEN_EXEC_PERM != FS_OPEN_EXEC_PERM );
862895 BUILD_BUG_ON (FAN_FS_ERROR != FS_ERROR );
896+ BUILD_BUG_ON (FAN_RENAME != FS_RENAME );
863897
864898 BUILD_BUG_ON (HWEIGHT32 (ALL_FANOTIFY_EVENT_BITS ) != 20 );
865899
0 commit comments