Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

fanotify: add support for FAN_REPORT_NAME

Introduce a new fanotify_init() flag FAN_REPORT_NAME. It requires the
flag FAN_REPORT_DIR_FID and there is a constant for setting both flags
named FAN_REPORT_DFID_NAME.

For a group with flag FAN_REPORT_NAME, the parent fid and name are
reported for directory entry modification events (create/detete/move)
and for events on non-directory objects.

Events on directories themselves are reported with their own fid and
"." as the name.

The parent fid and name are reported with an info record of type
FAN_EVENT_INFO_TYPE_DFID_NAME, similar to the way that parent fid is
reported with into type FAN_EVENT_INFO_TYPE_DFID, but with an appended
null terminated name string.

Link: https://lore.kernel.org/r/20200716084230.30611-21-amir73il@gmail.com
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Jan Kara <jack@suse.cz>

authored by

Amir Goldstein and committed by
Jan Kara
929943b3 51280637

+58 -11
+17 -1
fs/notify/fanotify/fanotify.c
··· 522 522 unsigned int fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS); 523 523 bool name_event = false; 524 524 525 - if ((fid_mode & FAN_REPORT_DIR_FID) && dirid) 525 + if ((fid_mode & FAN_REPORT_DIR_FID) && dirid) { 526 526 id = dirid; 527 + 528 + /* 529 + * We record file name only in a group with FAN_REPORT_NAME 530 + * and when we have a directory inode to report. 531 + * 532 + * For directory entry modification event, we record the fid of 533 + * the directory and the name of the modified entry. 534 + * 535 + * For event on non-directory that is reported to parent, we 536 + * record the fid of the parent and the name of the child. 537 + */ 538 + if ((fid_mode & FAN_REPORT_NAME) && 539 + ((mask & ALL_FSNOTIFY_DIRENT_EVENTS) || 540 + !(mask & FAN_ONDIR))) 541 + name_event = true; 542 + } 527 543 528 544 /* 529 545 * For queues with unlimited length lost events are not expected and
+36 -9
fs/notify/fanotify/fanotify_user.c
··· 64 64 return roundup(FANOTIFY_INFO_HDR_LEN + info_len, FANOTIFY_EVENT_ALIGN); 65 65 } 66 66 67 - static int fanotify_event_info_len(struct fanotify_event *event) 67 + static int fanotify_event_info_len(unsigned int fid_mode, 68 + struct fanotify_event *event) 68 69 { 69 70 struct fanotify_info *info = fanotify_event_info(event); 70 71 int dir_fh_len = fanotify_event_dir_fh_len(event); 71 72 int fh_len = fanotify_event_object_fh_len(event); 72 73 int info_len = 0; 74 + int dot_len = 0; 73 75 74 - if (dir_fh_len) 76 + if (dir_fh_len) { 75 77 info_len += fanotify_fid_info_len(dir_fh_len, info->name_len); 78 + } else if ((fid_mode & FAN_REPORT_NAME) && (event->mask & FAN_ONDIR)) { 79 + /* 80 + * With group flag FAN_REPORT_NAME, if name was not recorded in 81 + * event on a directory, we will report the name ".". 82 + */ 83 + dot_len = 1; 84 + } 76 85 77 86 if (fh_len) 78 - info_len += fanotify_fid_info_len(fh_len, 0); 87 + info_len += fanotify_fid_info_len(fh_len, dot_len); 79 88 80 89 return info_len; 81 90 } ··· 100 91 { 101 92 size_t event_size = FAN_EVENT_METADATA_LEN; 102 93 struct fanotify_event *event = NULL; 94 + unsigned int fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS); 103 95 104 96 pr_debug("%s: group=%p count=%zd\n", __func__, group, count); 105 97 ··· 108 98 if (fsnotify_notify_queue_is_empty(group)) 109 99 goto out; 110 100 111 - if (FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS)) { 112 - event_size += fanotify_event_info_len( 101 + if (fid_mode) { 102 + event_size += fanotify_event_info_len(fid_mode, 113 103 FANOTIFY_E(fsnotify_peek_first_event(group))); 114 104 } 115 105 ··· 335 325 pr_debug("%s: group=%p event=%p\n", __func__, group, event); 336 326 337 327 metadata.event_len = FAN_EVENT_METADATA_LEN + 338 - fanotify_event_info_len(event); 328 + fanotify_event_info_len(fid_mode, event); 339 329 metadata.metadata_len = FAN_EVENT_METADATA_LEN; 340 330 metadata.vers = FANOTIFY_METADATA_VERSION; 341 331 metadata.reserved = 0; ··· 384 374 } 385 375 386 376 if (fanotify_event_object_fh_len(event)) { 377 + const char *dot = NULL; 378 + int dot_len = 0; 379 + 387 380 if (fid_mode == FAN_REPORT_FID || info_type) { 388 381 /* 389 382 * With only group flag FAN_REPORT_FID only type FID is 390 383 * reported. Second info record type is always FID. 391 384 */ 392 385 info_type = FAN_EVENT_INFO_TYPE_FID; 386 + } else if ((fid_mode & FAN_REPORT_NAME) && 387 + (event->mask & FAN_ONDIR)) { 388 + /* 389 + * With group flag FAN_REPORT_NAME, if name was not 390 + * recorded in an event on a directory, report the 391 + * name "." with info type DFID_NAME. 392 + */ 393 + info_type = FAN_EVENT_INFO_TYPE_DFID_NAME; 394 + dot = "."; 395 + dot_len = 1; 393 396 } else if ((event->mask & ALL_FSNOTIFY_DIRENT_EVENTS) || 394 397 (event->mask & FAN_ONDIR)) { 395 398 /* ··· 423 400 424 401 ret = copy_info_to_user(fanotify_event_fsid(event), 425 402 fanotify_event_object_fh(event), 426 - info_type, NULL, 0, buf, count); 403 + info_type, dot, dot_len, buf, count); 427 404 if (ret < 0) 428 405 return ret; 429 406 ··· 955 932 if (fid_mode && class != FAN_CLASS_NOTIF) 956 933 return -EINVAL; 957 934 958 - /* Reporting either object fid or dir fid */ 935 + /* 936 + * Reporting either object fid or dir fid. 937 + * Child name is reported with parent fid so requires dir fid. 938 + */ 959 939 switch (fid_mode) { 960 940 case 0: 961 941 case FAN_REPORT_FID: 962 942 case FAN_REPORT_DIR_FID: 943 + case FAN_REPORT_DFID_NAME: 963 944 break; 964 945 default: 965 946 return -EINVAL; ··· 1321 1294 */ 1322 1295 static int __init fanotify_user_setup(void) 1323 1296 { 1324 - BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 9); 1297 + BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 10); 1325 1298 BUILD_BUG_ON(HWEIGHT32(FANOTIFY_MARK_FLAGS) != 9); 1326 1299 1327 1300 fanotify_mark_cache = KMEM_CACHE(fsnotify_mark,
+1 -1
include/linux/fanotify.h
··· 18 18 #define FANOTIFY_CLASS_BITS (FAN_CLASS_NOTIF | FAN_CLASS_CONTENT | \ 19 19 FAN_CLASS_PRE_CONTENT) 20 20 21 - #define FANOTIFY_FID_BITS (FAN_REPORT_FID | FAN_REPORT_DIR_FID) 21 + #define FANOTIFY_FID_BITS (FAN_REPORT_FID | FAN_REPORT_DFID_NAME) 22 22 23 23 #define FANOTIFY_INIT_FLAGS (FANOTIFY_CLASS_BITS | FANOTIFY_FID_BITS | \ 24 24 FAN_REPORT_TID | \
+4
include/uapi/linux/fanotify.h
··· 54 54 #define FAN_REPORT_TID 0x00000100 /* event->pid is thread id */ 55 55 #define FAN_REPORT_FID 0x00000200 /* Report unique file id */ 56 56 #define FAN_REPORT_DIR_FID 0x00000400 /* Report unique directory id */ 57 + #define FAN_REPORT_NAME 0x00000800 /* Report events with name */ 58 + 59 + /* Convenience macro - FAN_REPORT_NAME requires FAN_REPORT_DIR_FID */ 60 + #define FAN_REPORT_DFID_NAME (FAN_REPORT_DIR_FID | FAN_REPORT_NAME) 57 61 58 62 /* Deprecated - do not use this in programs and do not add new flags here! */ 59 63 #define FAN_ALL_INIT_FLAGS (FAN_CLOEXEC | FAN_NONBLOCK | \