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

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'fsnotify_for_v5.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs

Pull fanotify updates from Jan Kara:
"Support for new FAN_RENAME fanotify event and support for reporting
child info in directory fanotify events (FAN_REPORT_TARGET_FID)"

* tag 'fsnotify_for_v5.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs:
fanotify: wire up FAN_RENAME event
fanotify: report old and/or new parent+name in FAN_RENAME event
fanotify: record either old name new name or both for FAN_RENAME
fanotify: record old and new parent and name in FAN_RENAME event
fanotify: support secondary dir fh and name in fanotify_info
fanotify: use helpers to parcel fanotify_info buffer
fanotify: use macros to get the offset to fanotify_info buffer
fsnotify: generate FS_RENAME event with rich information
fanotify: introduce group flag FAN_REPORT_TARGET_FID
fsnotify: separate mark iterator type from object type enum
fsnotify: clarify object type argument

+482 -143
+1 -1
fs/notify/dnotify/dnotify.c
··· 196 196 if (arg & DN_ATTRIB) 197 197 new_mask |= FS_ATTRIB; 198 198 if (arg & DN_RENAME) 199 - new_mask |= FS_DN_RENAME; 199 + new_mask |= FS_RENAME; 200 200 if (arg & DN_CREATE) 201 201 new_mask |= (FS_CREATE | FS_MOVED_TO); 202 202
+160 -51
fs/notify/fanotify/fanotify.c
··· 76 76 struct fanotify_info *info2) 77 77 { 78 78 if (info1->dir_fh_totlen != info2->dir_fh_totlen || 79 + info1->dir2_fh_totlen != info2->dir2_fh_totlen || 79 80 info1->file_fh_totlen != info2->file_fh_totlen || 80 - info1->name_len != info2->name_len) 81 + info1->name_len != info2->name_len || 82 + info1->name2_len != info2->name2_len) 81 83 return false; 82 84 83 85 if (info1->dir_fh_totlen && ··· 87 85 fanotify_info_dir_fh(info2))) 88 86 return false; 89 87 88 + if (info1->dir2_fh_totlen && 89 + !fanotify_fh_equal(fanotify_info_dir2_fh(info1), 90 + fanotify_info_dir2_fh(info2))) 91 + return false; 92 + 90 93 if (info1->file_fh_totlen && 91 94 !fanotify_fh_equal(fanotify_info_file_fh(info1), 92 95 fanotify_info_file_fh(info2))) 93 96 return false; 94 97 95 - return !info1->name_len || 96 - !memcmp(fanotify_info_name(info1), fanotify_info_name(info2), 97 - info1->name_len); 98 + if (info1->name_len && 99 + memcmp(fanotify_info_name(info1), fanotify_info_name(info2), 100 + info1->name_len)) 101 + return false; 102 + 103 + return !info1->name2_len || 104 + !memcmp(fanotify_info_name2(info1), fanotify_info_name2(info2), 105 + info1->name2_len); 98 106 } 99 107 100 108 static bool fanotify_name_event_equal(struct fanotify_name_event *fne1, ··· 151 139 * unlink pair or rmdir+create pair of events. 152 140 */ 153 141 if ((old->mask & FS_ISDIR) != (new->mask & FS_ISDIR)) 142 + return false; 143 + 144 + /* 145 + * FAN_RENAME event is reported with special info record types, 146 + * so we cannot merge it with other events. 147 + */ 148 + if ((old->mask & FAN_RENAME) != (new->mask & FAN_RENAME)) 154 149 return false; 155 150 156 151 switch (old->type) { ··· 291 272 */ 292 273 static u32 fanotify_group_event_mask(struct fsnotify_group *group, 293 274 struct fsnotify_iter_info *iter_info, 294 - u32 event_mask, const void *data, 295 - int data_type, struct inode *dir) 275 + u32 *match_mask, u32 event_mask, 276 + const void *data, int data_type, 277 + struct inode *dir) 296 278 { 297 279 __u32 marks_mask = 0, marks_ignored_mask = 0; 298 280 __u32 test_mask, user_mask = FANOTIFY_OUTGOING_EVENTS | ··· 319 299 return 0; 320 300 } 321 301 322 - fsnotify_foreach_obj_type(type) { 302 + fsnotify_foreach_iter_type(type) { 323 303 if (!fsnotify_iter_should_report_type(iter_info, type)) 324 304 continue; 325 305 mark = iter_info->marks[type]; ··· 338 318 * If the event is on a child and this mark is on a parent not 339 319 * watching children, don't send it! 340 320 */ 341 - if (type == FSNOTIFY_OBJ_TYPE_PARENT && 321 + if (type == FSNOTIFY_ITER_TYPE_PARENT && 342 322 !(mark->mask & FS_EVENT_ON_CHILD)) 343 323 continue; 344 324 345 325 marks_mask |= mark->mask; 326 + 327 + /* Record the mark types of this group that matched the event */ 328 + *match_mask |= 1U << type; 346 329 } 347 330 348 331 test_mask = event_mask & marks_mask & ~marks_ignored_mask; ··· 434 411 * be zero in that case if encoding fh len failed. 435 412 */ 436 413 err = -ENOENT; 437 - if (fh_len < 4 || WARN_ON_ONCE(fh_len % 4)) 414 + if (fh_len < 4 || WARN_ON_ONCE(fh_len % 4) || fh_len > MAX_HANDLE_SZ) 438 415 goto out_err; 439 416 440 417 /* No external buffer in a variable size allocated fh */ ··· 481 458 } 482 459 483 460 /* 484 - * The inode to use as identifier when reporting fid depends on the event. 485 - * Report the modified directory inode on dirent modification events. 486 - * Report the "victim" inode otherwise. 461 + * FAN_REPORT_FID is ambiguous in that it reports the fid of the child for 462 + * some events and the fid of the parent for create/delete/move events. 463 + * 464 + * With the FAN_REPORT_TARGET_FID flag, the fid of the child is reported 465 + * also in create/delete/move events in addition to the fid of the parent 466 + * and the name of the child. 467 + */ 468 + static inline bool fanotify_report_child_fid(unsigned int fid_mode, u32 mask) 469 + { 470 + if (mask & ALL_FSNOTIFY_DIRENT_EVENTS) 471 + return (fid_mode & FAN_REPORT_TARGET_FID); 472 + 473 + return (fid_mode & FAN_REPORT_FID) && !(mask & FAN_ONDIR); 474 + } 475 + 476 + /* 477 + * The inode to use as identifier when reporting fid depends on the event 478 + * and the group flags. 479 + * 480 + * With the group flag FAN_REPORT_TARGET_FID, always report the child fid. 481 + * 482 + * Without the group flag FAN_REPORT_TARGET_FID, report the modified directory 483 + * fid on dirent events and the child fid otherwise. 484 + * 487 485 * For example: 488 - * FS_ATTRIB reports the child inode even if reported on a watched parent. 489 - * FS_CREATE reports the modified dir inode and not the created inode. 486 + * FS_ATTRIB reports the child fid even if reported on a watched parent. 487 + * FS_CREATE reports the modified dir fid without FAN_REPORT_TARGET_FID. 488 + * and reports the created child fid with FAN_REPORT_TARGET_FID. 490 489 */ 491 490 static struct inode *fanotify_fid_inode(u32 event_mask, const void *data, 492 - int data_type, struct inode *dir) 491 + int data_type, struct inode *dir, 492 + unsigned int fid_mode) 493 493 { 494 - if (event_mask & ALL_FSNOTIFY_DIRENT_EVENTS) 494 + if ((event_mask & ALL_FSNOTIFY_DIRENT_EVENTS) && 495 + !(fid_mode & FAN_REPORT_TARGET_FID)) 495 496 return dir; 496 497 497 498 return fsnotify_data_inode(data, data_type); ··· 599 552 return &ffe->fae; 600 553 } 601 554 602 - static struct fanotify_event *fanotify_alloc_name_event(struct inode *id, 555 + static struct fanotify_event *fanotify_alloc_name_event(struct inode *dir, 603 556 __kernel_fsid_t *fsid, 604 557 const struct qstr *name, 605 558 struct inode *child, 559 + struct dentry *moved, 606 560 unsigned int *hash, 607 561 gfp_t gfp) 608 562 { 609 563 struct fanotify_name_event *fne; 610 564 struct fanotify_info *info; 611 565 struct fanotify_fh *dfh, *ffh; 612 - unsigned int dir_fh_len = fanotify_encode_fh_len(id); 566 + struct inode *dir2 = moved ? d_inode(moved->d_parent) : NULL; 567 + const struct qstr *name2 = moved ? &moved->d_name : NULL; 568 + unsigned int dir_fh_len = fanotify_encode_fh_len(dir); 569 + unsigned int dir2_fh_len = fanotify_encode_fh_len(dir2); 613 570 unsigned int child_fh_len = fanotify_encode_fh_len(child); 614 - unsigned int size; 571 + unsigned long name_len = name ? name->len : 0; 572 + unsigned long name2_len = name2 ? name2->len : 0; 573 + unsigned int len, size; 615 574 616 - size = sizeof(*fne) + FANOTIFY_FH_HDR_LEN + dir_fh_len; 575 + /* Reserve terminating null byte even for empty name */ 576 + size = sizeof(*fne) + name_len + name2_len + 2; 577 + if (dir_fh_len) 578 + size += FANOTIFY_FH_HDR_LEN + dir_fh_len; 579 + if (dir2_fh_len) 580 + size += FANOTIFY_FH_HDR_LEN + dir2_fh_len; 617 581 if (child_fh_len) 618 582 size += FANOTIFY_FH_HDR_LEN + child_fh_len; 619 - if (name) 620 - size += name->len + 1; 621 583 fne = kmalloc(size, gfp); 622 584 if (!fne) 623 585 return NULL; ··· 636 580 *hash ^= fanotify_hash_fsid(fsid); 637 581 info = &fne->info; 638 582 fanotify_info_init(info); 639 - dfh = fanotify_info_dir_fh(info); 640 - info->dir_fh_totlen = fanotify_encode_fh(dfh, id, dir_fh_len, hash, 0); 583 + if (dir_fh_len) { 584 + dfh = fanotify_info_dir_fh(info); 585 + len = fanotify_encode_fh(dfh, dir, dir_fh_len, hash, 0); 586 + fanotify_info_set_dir_fh(info, len); 587 + } 588 + if (dir2_fh_len) { 589 + dfh = fanotify_info_dir2_fh(info); 590 + len = fanotify_encode_fh(dfh, dir2, dir2_fh_len, hash, 0); 591 + fanotify_info_set_dir2_fh(info, len); 592 + } 641 593 if (child_fh_len) { 642 594 ffh = fanotify_info_file_fh(info); 643 - info->file_fh_totlen = fanotify_encode_fh(ffh, child, 644 - child_fh_len, hash, 0); 595 + len = fanotify_encode_fh(ffh, child, child_fh_len, hash, 0); 596 + fanotify_info_set_file_fh(info, len); 645 597 } 646 - if (name) { 647 - long salt = name->len; 648 - 598 + if (name_len) { 649 599 fanotify_info_copy_name(info, name); 650 - *hash ^= full_name_hash((void *)salt, name->name, name->len); 600 + *hash ^= full_name_hash((void *)name_len, name->name, name_len); 601 + } 602 + if (name2_len) { 603 + fanotify_info_copy_name2(info, name2); 604 + *hash ^= full_name_hash((void *)name2_len, name2->name, 605 + name2_len); 651 606 } 652 607 653 - pr_debug("%s: ino=%lu size=%u dir_fh_len=%u child_fh_len=%u name_len=%u name='%.*s'\n", 654 - __func__, id->i_ino, size, dir_fh_len, child_fh_len, 608 + pr_debug("%s: size=%u dir_fh_len=%u child_fh_len=%u name_len=%u name='%.*s'\n", 609 + __func__, size, dir_fh_len, child_fh_len, 655 610 info->name_len, info->name_len, fanotify_info_name(info)); 611 + 612 + if (dir2_fh_len) { 613 + pr_debug("%s: dir2_fh_len=%u name2_len=%u name2='%.*s'\n", 614 + __func__, dir2_fh_len, info->name2_len, 615 + info->name2_len, fanotify_info_name2(info)); 616 + } 656 617 657 618 return &fne->fae; 658 619 } ··· 712 639 return &fee->fae; 713 640 } 714 641 715 - static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, 716 - u32 mask, const void *data, 717 - int data_type, struct inode *dir, 718 - const struct qstr *file_name, 719 - __kernel_fsid_t *fsid) 642 + static struct fanotify_event *fanotify_alloc_event( 643 + struct fsnotify_group *group, 644 + u32 mask, const void *data, int data_type, 645 + struct inode *dir, const struct qstr *file_name, 646 + __kernel_fsid_t *fsid, u32 match_mask) 720 647 { 721 648 struct fanotify_event *event = NULL; 722 649 gfp_t gfp = GFP_KERNEL_ACCOUNT; 723 - struct inode *id = fanotify_fid_inode(mask, data, data_type, dir); 650 + unsigned int fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS); 651 + struct inode *id = fanotify_fid_inode(mask, data, data_type, dir, 652 + fid_mode); 724 653 struct inode *dirid = fanotify_dfid_inode(mask, data, data_type, dir); 725 654 const struct path *path = fsnotify_data_path(data, data_type); 726 - unsigned int fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS); 727 655 struct mem_cgroup *old_memcg; 656 + struct dentry *moved = NULL; 728 657 struct inode *child = NULL; 729 658 bool name_event = false; 730 659 unsigned int hash = 0; ··· 735 660 736 661 if ((fid_mode & FAN_REPORT_DIR_FID) && dirid) { 737 662 /* 738 - * With both flags FAN_REPORT_DIR_FID and FAN_REPORT_FID, we 739 - * report the child fid for events reported on a non-dir child 663 + * For certain events and group flags, report the child fid 740 664 * in addition to reporting the parent fid and maybe child name. 741 665 */ 742 - if ((fid_mode & FAN_REPORT_FID) && id != dirid && !ondir) 666 + if (fanotify_report_child_fid(fid_mode, mask) && id != dirid) 743 667 child = id; 744 668 745 669 id = dirid; ··· 762 688 } else if ((mask & ALL_FSNOTIFY_DIRENT_EVENTS) || !ondir) { 763 689 name_event = true; 764 690 } 691 + 692 + /* 693 + * In the special case of FAN_RENAME event, use the match_mask 694 + * to determine if we need to report only the old parent+name, 695 + * only the new parent+name or both. 696 + * 'dirid' and 'file_name' are the old parent+name and 697 + * 'moved' has the new parent+name. 698 + */ 699 + if (mask & FAN_RENAME) { 700 + bool report_old, report_new; 701 + 702 + if (WARN_ON_ONCE(!match_mask)) 703 + return NULL; 704 + 705 + /* Report both old and new parent+name if sb watching */ 706 + report_old = report_new = 707 + match_mask & (1U << FSNOTIFY_ITER_TYPE_SB); 708 + report_old |= 709 + match_mask & (1U << FSNOTIFY_ITER_TYPE_INODE); 710 + report_new |= 711 + match_mask & (1U << FSNOTIFY_ITER_TYPE_INODE2); 712 + 713 + if (!report_old) { 714 + /* Do not report old parent+name */ 715 + dirid = NULL; 716 + file_name = NULL; 717 + } 718 + if (report_new) { 719 + /* Report new parent+name */ 720 + moved = fsnotify_data_dentry(data, data_type); 721 + } 722 + } 765 723 } 766 724 767 725 /* ··· 815 709 } else if (fanotify_is_error_event(mask)) { 816 710 event = fanotify_alloc_error_event(group, fsid, data, 817 711 data_type, &hash); 818 - } else if (name_event && (file_name || child)) { 819 - event = fanotify_alloc_name_event(id, fsid, file_name, child, 820 - &hash, gfp); 712 + } else if (name_event && (file_name || moved || child)) { 713 + event = fanotify_alloc_name_event(dirid, fsid, file_name, child, 714 + moved, &hash, gfp); 821 715 } else if (fid_mode) { 822 716 event = fanotify_alloc_fid_event(id, fsid, &hash, gfp); 823 717 } else { ··· 852 746 int type; 853 747 __kernel_fsid_t fsid = {}; 854 748 855 - fsnotify_foreach_obj_type(type) { 749 + fsnotify_foreach_iter_type(type) { 856 750 struct fsnotify_mark_connector *conn; 857 751 858 752 if (!fsnotify_iter_should_report_type(iter_info, type)) ··· 906 800 struct fanotify_event *event; 907 801 struct fsnotify_event *fsn_event; 908 802 __kernel_fsid_t fsid = {}; 803 + u32 match_mask = 0; 909 804 910 805 BUILD_BUG_ON(FAN_ACCESS != FS_ACCESS); 911 806 BUILD_BUG_ON(FAN_MODIFY != FS_MODIFY); ··· 928 821 BUILD_BUG_ON(FAN_OPEN_EXEC != FS_OPEN_EXEC); 929 822 BUILD_BUG_ON(FAN_OPEN_EXEC_PERM != FS_OPEN_EXEC_PERM); 930 823 BUILD_BUG_ON(FAN_FS_ERROR != FS_ERROR); 824 + BUILD_BUG_ON(FAN_RENAME != FS_RENAME); 931 825 932 - BUILD_BUG_ON(HWEIGHT32(ALL_FANOTIFY_EVENT_BITS) != 20); 826 + BUILD_BUG_ON(HWEIGHT32(ALL_FANOTIFY_EVENT_BITS) != 21); 933 827 934 - mask = fanotify_group_event_mask(group, iter_info, mask, data, 935 - data_type, dir); 828 + mask = fanotify_group_event_mask(group, iter_info, &match_mask, 829 + mask, data, data_type, dir); 936 830 if (!mask) 937 831 return 0; 938 832 939 - pr_debug("%s: group=%p mask=%x\n", __func__, group, mask); 833 + pr_debug("%s: group=%p mask=%x report_mask=%x\n", __func__, 834 + group, mask, match_mask); 940 835 941 836 if (fanotify_is_perm_event(mask)) { 942 837 /* ··· 957 848 } 958 849 959 850 event = fanotify_alloc_event(group, mask, data, data_type, dir, 960 - file_name, &fsid); 851 + file_name, &fsid, match_mask); 961 852 ret = -ENOMEM; 962 853 if (unlikely(!event)) { 963 854 /*
+131 -11
fs/notify/fanotify/fanotify.h
··· 40 40 struct fanotify_info { 41 41 /* size of dir_fh/file_fh including fanotify_fh hdr size */ 42 42 u8 dir_fh_totlen; 43 + u8 dir2_fh_totlen; 43 44 u8 file_fh_totlen; 44 45 u8 name_len; 45 - u8 pad; 46 + u8 name2_len; 47 + u8 pad[3]; 46 48 unsigned char buf[]; 47 49 /* 48 50 * (struct fanotify_fh) dir_fh starts at buf[0] 49 - * (optional) file_fh starts at buf[dir_fh_totlen] 50 - * name starts at buf[dir_fh_totlen + file_fh_totlen] 51 + * (optional) dir2_fh starts at buf[dir_fh_totlen] 52 + * (optional) file_fh starts at buf[dir_fh_totlen + dir2_fh_totlen] 53 + * name starts at buf[dir_fh_totlen + dir2_fh_totlen + file_fh_totlen] 54 + * ... 51 55 */ 56 + #define FANOTIFY_DIR_FH_SIZE(info) ((info)->dir_fh_totlen) 57 + #define FANOTIFY_DIR2_FH_SIZE(info) ((info)->dir2_fh_totlen) 58 + #define FANOTIFY_FILE_FH_SIZE(info) ((info)->file_fh_totlen) 59 + #define FANOTIFY_NAME_SIZE(info) ((info)->name_len + 1) 60 + #define FANOTIFY_NAME2_SIZE(info) ((info)->name2_len + 1) 61 + 62 + #define FANOTIFY_DIR_FH_OFFSET(info) 0 63 + #define FANOTIFY_DIR2_FH_OFFSET(info) \ 64 + (FANOTIFY_DIR_FH_OFFSET(info) + FANOTIFY_DIR_FH_SIZE(info)) 65 + #define FANOTIFY_FILE_FH_OFFSET(info) \ 66 + (FANOTIFY_DIR2_FH_OFFSET(info) + FANOTIFY_DIR2_FH_SIZE(info)) 67 + #define FANOTIFY_NAME_OFFSET(info) \ 68 + (FANOTIFY_FILE_FH_OFFSET(info) + FANOTIFY_FILE_FH_SIZE(info)) 69 + #define FANOTIFY_NAME2_OFFSET(info) \ 70 + (FANOTIFY_NAME_OFFSET(info) + FANOTIFY_NAME_SIZE(info)) 71 + 72 + #define FANOTIFY_DIR_FH_BUF(info) \ 73 + ((info)->buf + FANOTIFY_DIR_FH_OFFSET(info)) 74 + #define FANOTIFY_DIR2_FH_BUF(info) \ 75 + ((info)->buf + FANOTIFY_DIR2_FH_OFFSET(info)) 76 + #define FANOTIFY_FILE_FH_BUF(info) \ 77 + ((info)->buf + FANOTIFY_FILE_FH_OFFSET(info)) 78 + #define FANOTIFY_NAME_BUF(info) \ 79 + ((info)->buf + FANOTIFY_NAME_OFFSET(info)) 80 + #define FANOTIFY_NAME2_BUF(info) \ 81 + ((info)->buf + FANOTIFY_NAME2_OFFSET(info)) 52 82 } __aligned(4); 53 83 54 84 static inline bool fanotify_fh_has_ext_buf(struct fanotify_fh *fh) ··· 117 87 { 118 88 BUILD_BUG_ON(offsetof(struct fanotify_info, buf) % 4); 119 89 120 - return (struct fanotify_fh *)info->buf; 90 + return (struct fanotify_fh *)FANOTIFY_DIR_FH_BUF(info); 91 + } 92 + 93 + static inline int fanotify_info_dir2_fh_len(struct fanotify_info *info) 94 + { 95 + if (!info->dir2_fh_totlen || 96 + WARN_ON_ONCE(info->dir2_fh_totlen < FANOTIFY_FH_HDR_LEN)) 97 + return 0; 98 + 99 + return info->dir2_fh_totlen - FANOTIFY_FH_HDR_LEN; 100 + } 101 + 102 + static inline struct fanotify_fh *fanotify_info_dir2_fh(struct fanotify_info *info) 103 + { 104 + return (struct fanotify_fh *)FANOTIFY_DIR2_FH_BUF(info); 121 105 } 122 106 123 107 static inline int fanotify_info_file_fh_len(struct fanotify_info *info) ··· 145 101 146 102 static inline struct fanotify_fh *fanotify_info_file_fh(struct fanotify_info *info) 147 103 { 148 - return (struct fanotify_fh *)(info->buf + info->dir_fh_totlen); 104 + return (struct fanotify_fh *)FANOTIFY_FILE_FH_BUF(info); 149 105 } 150 106 151 - static inline const char *fanotify_info_name(struct fanotify_info *info) 107 + static inline char *fanotify_info_name(struct fanotify_info *info) 152 108 { 153 - return info->buf + info->dir_fh_totlen + info->file_fh_totlen; 109 + if (!info->name_len) 110 + return NULL; 111 + 112 + return FANOTIFY_NAME_BUF(info); 113 + } 114 + 115 + static inline char *fanotify_info_name2(struct fanotify_info *info) 116 + { 117 + if (!info->name2_len) 118 + return NULL; 119 + 120 + return FANOTIFY_NAME2_BUF(info); 154 121 } 155 122 156 123 static inline void fanotify_info_init(struct fanotify_info *info) 157 124 { 125 + BUILD_BUG_ON(FANOTIFY_FH_HDR_LEN + MAX_HANDLE_SZ > U8_MAX); 126 + BUILD_BUG_ON(NAME_MAX > U8_MAX); 127 + 158 128 info->dir_fh_totlen = 0; 129 + info->dir2_fh_totlen = 0; 159 130 info->file_fh_totlen = 0; 160 131 info->name_len = 0; 132 + info->name2_len = 0; 161 133 } 162 134 163 - static inline unsigned int fanotify_info_len(struct fanotify_info *info) 135 + /* These set/copy helpers MUST be called by order */ 136 + static inline void fanotify_info_set_dir_fh(struct fanotify_info *info, 137 + unsigned int totlen) 164 138 { 165 - return info->dir_fh_totlen + info->file_fh_totlen + info->name_len; 139 + if (WARN_ON_ONCE(info->dir2_fh_totlen > 0) || 140 + WARN_ON_ONCE(info->file_fh_totlen > 0) || 141 + WARN_ON_ONCE(info->name_len > 0) || 142 + WARN_ON_ONCE(info->name2_len > 0)) 143 + return; 144 + 145 + info->dir_fh_totlen = totlen; 146 + } 147 + 148 + static inline void fanotify_info_set_dir2_fh(struct fanotify_info *info, 149 + unsigned int totlen) 150 + { 151 + if (WARN_ON_ONCE(info->file_fh_totlen > 0) || 152 + WARN_ON_ONCE(info->name_len > 0) || 153 + WARN_ON_ONCE(info->name2_len > 0)) 154 + return; 155 + 156 + info->dir2_fh_totlen = totlen; 157 + } 158 + 159 + static inline void fanotify_info_set_file_fh(struct fanotify_info *info, 160 + unsigned int totlen) 161 + { 162 + if (WARN_ON_ONCE(info->name_len > 0) || 163 + WARN_ON_ONCE(info->name2_len > 0)) 164 + return; 165 + 166 + info->file_fh_totlen = totlen; 166 167 } 167 168 168 169 static inline void fanotify_info_copy_name(struct fanotify_info *info, 169 170 const struct qstr *name) 170 171 { 172 + if (WARN_ON_ONCE(name->len > NAME_MAX) || 173 + WARN_ON_ONCE(info->name2_len > 0)) 174 + return; 175 + 171 176 info->name_len = name->len; 172 - strcpy(info->buf + info->dir_fh_totlen + info->file_fh_totlen, 173 - name->name); 177 + strcpy(fanotify_info_name(info), name->name); 178 + } 179 + 180 + static inline void fanotify_info_copy_name2(struct fanotify_info *info, 181 + const struct qstr *name) 182 + { 183 + if (WARN_ON_ONCE(name->len > NAME_MAX)) 184 + return; 185 + 186 + info->name2_len = name->len; 187 + strcpy(fanotify_info_name2(info), name->name); 174 188 } 175 189 176 190 /* ··· 373 271 return info ? fanotify_info_dir_fh_len(info) : 0; 374 272 } 375 273 274 + static inline int fanotify_event_dir2_fh_len(struct fanotify_event *event) 275 + { 276 + struct fanotify_info *info = fanotify_event_info(event); 277 + 278 + return info ? fanotify_info_dir2_fh_len(info) : 0; 279 + } 280 + 376 281 static inline bool fanotify_event_has_object_fh(struct fanotify_event *event) 377 282 { 378 283 /* For error events, even zeroed fh are reported. */ ··· 391 282 static inline bool fanotify_event_has_dir_fh(struct fanotify_event *event) 392 283 { 393 284 return fanotify_event_dir_fh_len(event) > 0; 285 + } 286 + 287 + static inline bool fanotify_event_has_dir2_fh(struct fanotify_event *event) 288 + { 289 + return fanotify_event_dir2_fh_len(event) > 0; 290 + } 291 + 292 + static inline bool fanotify_event_has_any_dir_fh(struct fanotify_event *event) 293 + { 294 + return fanotify_event_has_dir_fh(event) || 295 + fanotify_event_has_dir2_fh(event); 394 296 } 395 297 396 298 struct fanotify_path_event {
+70 -12
fs/notify/fanotify/fanotify_user.c
··· 129 129 FANOTIFY_EVENT_ALIGN); 130 130 } 131 131 132 + /* FAN_RENAME may have one or two dir+name info records */ 133 + static int fanotify_dir_name_info_len(struct fanotify_event *event) 134 + { 135 + struct fanotify_info *info = fanotify_event_info(event); 136 + int dir_fh_len = fanotify_event_dir_fh_len(event); 137 + int dir2_fh_len = fanotify_event_dir2_fh_len(event); 138 + int info_len = 0; 139 + 140 + if (dir_fh_len) 141 + info_len += fanotify_fid_info_len(dir_fh_len, 142 + info->name_len); 143 + if (dir2_fh_len) 144 + info_len += fanotify_fid_info_len(dir2_fh_len, 145 + info->name2_len); 146 + 147 + return info_len; 148 + } 149 + 132 150 static size_t fanotify_event_len(unsigned int info_mode, 133 151 struct fanotify_event *event) 134 152 { 135 153 size_t event_len = FAN_EVENT_METADATA_LEN; 136 154 struct fanotify_info *info; 137 - int dir_fh_len; 138 155 int fh_len; 139 156 int dot_len = 0; 140 157 ··· 163 146 164 147 info = fanotify_event_info(event); 165 148 166 - if (fanotify_event_has_dir_fh(event)) { 167 - dir_fh_len = fanotify_event_dir_fh_len(event); 168 - event_len += fanotify_fid_info_len(dir_fh_len, info->name_len); 149 + if (fanotify_event_has_any_dir_fh(event)) { 150 + event_len += fanotify_dir_name_info_len(event); 169 151 } else if ((info_mode & FAN_REPORT_NAME) && 170 152 (event->mask & FAN_ONDIR)) { 171 153 /* ··· 348 332 static size_t copy_error_info_to_user(struct fanotify_event *event, 349 333 char __user *buf, int count) 350 334 { 351 - struct fanotify_event_info_error info; 335 + struct fanotify_event_info_error info = { }; 352 336 struct fanotify_error_event *fee = FANOTIFY_EE(event); 353 337 354 338 info.hdr.info_type = FAN_EVENT_INFO_TYPE_ERROR; 355 - info.hdr.pad = 0; 356 339 info.hdr.len = FANOTIFY_ERROR_INFO_LEN; 357 340 358 341 if (WARN_ON(count < info.hdr.len)) ··· 395 380 return -EFAULT; 396 381 break; 397 382 case FAN_EVENT_INFO_TYPE_DFID_NAME: 383 + case FAN_EVENT_INFO_TYPE_OLD_DFID_NAME: 384 + case FAN_EVENT_INFO_TYPE_NEW_DFID_NAME: 398 385 if (WARN_ON_ONCE(!name || !name_len)) 399 386 return -EFAULT; 400 387 break; ··· 496 479 unsigned int pidfd_mode = info_mode & FAN_REPORT_PIDFD; 497 480 498 481 /* 499 - * Event info records order is as follows: dir fid + name, child fid. 482 + * Event info records order is as follows: 483 + * 1. dir fid + name 484 + * 2. (optional) new dir fid + new name 485 + * 3. (optional) child fid 500 486 */ 501 487 if (fanotify_event_has_dir_fh(event)) { 502 488 info_type = info->name_len ? FAN_EVENT_INFO_TYPE_DFID_NAME : 503 489 FAN_EVENT_INFO_TYPE_DFID; 490 + 491 + /* FAN_RENAME uses special info types */ 492 + if (event->mask & FAN_RENAME) 493 + info_type = FAN_EVENT_INFO_TYPE_OLD_DFID_NAME; 494 + 504 495 ret = copy_fid_info_to_user(fanotify_event_fsid(event), 505 496 fanotify_info_dir_fh(info), 506 497 info_type, 507 498 fanotify_info_name(info), 508 499 info->name_len, buf, count); 500 + if (ret < 0) 501 + return ret; 502 + 503 + buf += ret; 504 + count -= ret; 505 + total_bytes += ret; 506 + } 507 + 508 + /* New dir fid+name may be reported in addition to old dir fid+name */ 509 + if (fanotify_event_has_dir2_fh(event)) { 510 + info_type = FAN_EVENT_INFO_TYPE_NEW_DFID_NAME; 511 + ret = copy_fid_info_to_user(fanotify_event_fsid(event), 512 + fanotify_info_dir2_fh(info), 513 + info_type, 514 + fanotify_info_name2(info), 515 + info->name2_len, buf, count); 509 516 if (ret < 0) 510 517 return ret; 511 518 ··· 1098 1057 1099 1058 static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group, 1100 1059 fsnotify_connp_t *connp, 1101 - unsigned int type, 1060 + unsigned int obj_type, 1102 1061 __kernel_fsid_t *fsid) 1103 1062 { 1104 1063 struct ucounts *ucounts = group->fanotify_data.ucounts; ··· 1121 1080 } 1122 1081 1123 1082 fsnotify_init_mark(mark, group); 1124 - ret = fsnotify_add_mark_locked(mark, connp, type, 0, fsid); 1083 + ret = fsnotify_add_mark_locked(mark, connp, obj_type, 0, fsid); 1125 1084 if (ret) { 1126 1085 fsnotify_put_mark(mark); 1127 1086 goto out_dec_ucounts; ··· 1146 1105 } 1147 1106 1148 1107 static int fanotify_add_mark(struct fsnotify_group *group, 1149 - fsnotify_connp_t *connp, unsigned int type, 1108 + fsnotify_connp_t *connp, unsigned int obj_type, 1150 1109 __u32 mask, unsigned int flags, 1151 1110 __kernel_fsid_t *fsid) 1152 1111 { ··· 1157 1116 mutex_lock(&group->mark_mutex); 1158 1117 fsn_mark = fsnotify_find_mark(connp, group); 1159 1118 if (!fsn_mark) { 1160 - fsn_mark = fanotify_add_new_mark(group, connp, type, fsid); 1119 + fsn_mark = fanotify_add_new_mark(group, connp, obj_type, fsid); 1161 1120 if (IS_ERR(fsn_mark)) { 1162 1121 mutex_unlock(&group->mark_mutex); 1163 1122 return PTR_ERR(fsn_mark); ··· 1314 1273 * We can report both child fid and dir fid with or without name. 1315 1274 */ 1316 1275 if ((fid_mode & FAN_REPORT_NAME) && !(fid_mode & FAN_REPORT_DIR_FID)) 1276 + return -EINVAL; 1277 + 1278 + /* 1279 + * FAN_REPORT_TARGET_FID requires FAN_REPORT_NAME and FAN_REPORT_FID 1280 + * and is used as an indication to report both dir and child fid on all 1281 + * dirent events. 1282 + */ 1283 + if ((fid_mode & FAN_REPORT_TARGET_FID) && 1284 + (!(fid_mode & FAN_REPORT_NAME) || !(fid_mode & FAN_REPORT_FID))) 1317 1285 return -EINVAL; 1318 1286 1319 1287 f_flags = O_RDWR | FMODE_NONOTIFY; ··· 1586 1536 (!fid_mode || mark_type == FAN_MARK_MOUNT)) 1587 1537 goto fput_and_out; 1588 1538 1539 + /* 1540 + * FAN_RENAME uses special info type records to report the old and 1541 + * new parent+name. Reporting only old and new parent id is less 1542 + * useful and was not implemented. 1543 + */ 1544 + if (mask & FAN_RENAME && !(fid_mode & FAN_REPORT_NAME)) 1545 + goto fput_and_out; 1546 + 1589 1547 if (flags & FAN_MARK_FLUSH) { 1590 1548 ret = 0; 1591 1549 if (mark_type == FAN_MARK_MOUNT) ··· 1725 1667 FANOTIFY_DEFAULT_MAX_USER_MARKS); 1726 1668 1727 1669 BUILD_BUG_ON(FANOTIFY_INIT_FLAGS & FANOTIFY_INTERNAL_GROUP_FLAGS); 1728 - BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 11); 1670 + BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 12); 1729 1671 BUILD_BUG_ON(HWEIGHT32(FANOTIFY_MARK_FLAGS) != 9); 1730 1672 1731 1673 fanotify_mark_cache = KMEM_CACHE(fsnotify_mark,
+37 -16
fs/notify/fsnotify.c
··· 279 279 WARN_ON_ONCE(fsnotify_iter_vfsmount_mark(iter_info))) 280 280 return 0; 281 281 282 + /* 283 + * For FS_RENAME, 'dir' is old dir and 'data' is new dentry. 284 + * The only ->handle_inode_event() backend that supports FS_RENAME is 285 + * dnotify, where it means file was renamed within same parent. 286 + */ 287 + if (mask & FS_RENAME) { 288 + struct dentry *moved = fsnotify_data_dentry(data, data_type); 289 + 290 + if (dir != moved->d_parent->d_inode) 291 + return 0; 292 + } 293 + 282 294 if (parent_mark) { 283 295 /* 284 296 * parent_mark indicates that the parent inode is watching ··· 342 330 343 331 /* clear ignored on inode modification */ 344 332 if (mask & FS_MODIFY) { 345 - fsnotify_foreach_obj_type(type) { 333 + fsnotify_foreach_iter_type(type) { 346 334 if (!fsnotify_iter_should_report_type(iter_info, type)) 347 335 continue; 348 336 mark = iter_info->marks[type]; ··· 352 340 } 353 341 } 354 342 355 - fsnotify_foreach_obj_type(type) { 343 + fsnotify_foreach_iter_type(type) { 356 344 if (!fsnotify_iter_should_report_type(iter_info, type)) 357 345 continue; 358 346 mark = iter_info->marks[type]; ··· 417 405 int type; 418 406 419 407 /* Choose max prio group among groups of all queue heads */ 420 - fsnotify_foreach_obj_type(type) { 408 + fsnotify_foreach_iter_type(type) { 421 409 mark = iter_info->marks[type]; 422 410 if (mark && 423 411 fsnotify_compare_groups(max_prio_group, mark->group) > 0) ··· 429 417 430 418 /* Set the report mask for marks from same group as max prio group */ 431 419 iter_info->report_mask = 0; 432 - fsnotify_foreach_obj_type(type) { 420 + fsnotify_foreach_iter_type(type) { 433 421 mark = iter_info->marks[type]; 434 422 if (mark && 435 423 fsnotify_compare_groups(max_prio_group, mark->group) == 0) ··· 447 435 { 448 436 int type; 449 437 450 - fsnotify_foreach_obj_type(type) { 438 + fsnotify_foreach_iter_type(type) { 451 439 if (fsnotify_iter_should_report_type(iter_info, type)) 452 440 iter_info->marks[type] = 453 441 fsnotify_next_mark(iter_info->marks[type]); ··· 481 469 struct super_block *sb = fsnotify_data_sb(data, data_type); 482 470 struct fsnotify_iter_info iter_info = {}; 483 471 struct mount *mnt = NULL; 484 - struct inode *parent = NULL; 472 + struct inode *inode2 = NULL; 473 + struct dentry *moved; 474 + int inode2_type; 485 475 int ret = 0; 486 476 __u32 test_mask, marks_mask; 487 477 ··· 493 479 if (!inode) { 494 480 /* Dirent event - report on TYPE_INODE to dir */ 495 481 inode = dir; 482 + /* For FS_RENAME, inode is old_dir and inode2 is new_dir */ 483 + if (mask & FS_RENAME) { 484 + moved = fsnotify_data_dentry(data, data_type); 485 + inode2 = moved->d_parent->d_inode; 486 + inode2_type = FSNOTIFY_ITER_TYPE_INODE2; 487 + } 496 488 } else if (mask & FS_EVENT_ON_CHILD) { 497 489 /* 498 490 * Event on child - report on TYPE_PARENT to dir if it is 499 491 * watching children and on TYPE_INODE to child. 500 492 */ 501 - parent = dir; 493 + inode2 = dir; 494 + inode2_type = FSNOTIFY_ITER_TYPE_PARENT; 502 495 } 503 496 504 497 /* ··· 518 497 if (!sb->s_fsnotify_marks && 519 498 (!mnt || !mnt->mnt_fsnotify_marks) && 520 499 (!inode || !inode->i_fsnotify_marks) && 521 - (!parent || !parent->i_fsnotify_marks)) 500 + (!inode2 || !inode2->i_fsnotify_marks)) 522 501 return 0; 523 502 524 503 marks_mask = sb->s_fsnotify_mask; ··· 526 505 marks_mask |= mnt->mnt_fsnotify_mask; 527 506 if (inode) 528 507 marks_mask |= inode->i_fsnotify_mask; 529 - if (parent) 530 - marks_mask |= parent->i_fsnotify_mask; 508 + if (inode2) 509 + marks_mask |= inode2->i_fsnotify_mask; 531 510 532 511 533 512 /* ··· 540 519 541 520 iter_info.srcu_idx = srcu_read_lock(&fsnotify_mark_srcu); 542 521 543 - iter_info.marks[FSNOTIFY_OBJ_TYPE_SB] = 522 + iter_info.marks[FSNOTIFY_ITER_TYPE_SB] = 544 523 fsnotify_first_mark(&sb->s_fsnotify_marks); 545 524 if (mnt) { 546 - iter_info.marks[FSNOTIFY_OBJ_TYPE_VFSMOUNT] = 525 + iter_info.marks[FSNOTIFY_ITER_TYPE_VFSMOUNT] = 547 526 fsnotify_first_mark(&mnt->mnt_fsnotify_marks); 548 527 } 549 528 if (inode) { 550 - iter_info.marks[FSNOTIFY_OBJ_TYPE_INODE] = 529 + iter_info.marks[FSNOTIFY_ITER_TYPE_INODE] = 551 530 fsnotify_first_mark(&inode->i_fsnotify_marks); 552 531 } 553 - if (parent) { 554 - iter_info.marks[FSNOTIFY_OBJ_TYPE_PARENT] = 555 - fsnotify_first_mark(&parent->i_fsnotify_marks); 532 + if (inode2) { 533 + iter_info.marks[inode2_type] = 534 + fsnotify_first_mark(&inode2->i_fsnotify_marks); 556 535 } 557 536 558 537 /*
+1 -1
fs/notify/group.c
··· 58 58 fsnotify_group_stop_queueing(group); 59 59 60 60 /* Clear all marks for this group and queue them for destruction */ 61 - fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_ALL_TYPES_MASK); 61 + fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_TYPE_ANY); 62 62 63 63 /* 64 64 * Some marks can still be pinned when waiting for response from
+17 -14
fs/notify/mark.c
··· 353 353 { 354 354 int type; 355 355 356 - fsnotify_foreach_obj_type(type) { 356 + fsnotify_foreach_iter_type(type) { 357 357 /* This can fail if mark is being removed */ 358 358 if (!fsnotify_get_mark_safe(iter_info->marks[type])) { 359 359 __release(&fsnotify_mark_srcu); ··· 382 382 int type; 383 383 384 384 iter_info->srcu_idx = srcu_read_lock(&fsnotify_mark_srcu); 385 - fsnotify_foreach_obj_type(type) 385 + fsnotify_foreach_iter_type(type) 386 386 fsnotify_put_mark_wake(iter_info->marks[type]); 387 387 } 388 388 ··· 496 496 } 497 497 498 498 static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp, 499 - unsigned int type, 499 + unsigned int obj_type, 500 500 __kernel_fsid_t *fsid) 501 501 { 502 502 struct inode *inode = NULL; ··· 507 507 return -ENOMEM; 508 508 spin_lock_init(&conn->lock); 509 509 INIT_HLIST_HEAD(&conn->list); 510 - conn->type = type; 510 + conn->type = obj_type; 511 511 conn->obj = connp; 512 512 /* Cache fsid of filesystem containing the object */ 513 513 if (fsid) { ··· 572 572 * priority, highest number first, and then by the group's location in memory. 573 573 */ 574 574 static int fsnotify_add_mark_list(struct fsnotify_mark *mark, 575 - fsnotify_connp_t *connp, unsigned int type, 575 + fsnotify_connp_t *connp, 576 + unsigned int obj_type, 576 577 int allow_dups, __kernel_fsid_t *fsid) 577 578 { 578 579 struct fsnotify_mark *lmark, *last = NULL; ··· 581 580 int cmp; 582 581 int err = 0; 583 582 584 - if (WARN_ON(!fsnotify_valid_obj_type(type))) 583 + if (WARN_ON(!fsnotify_valid_obj_type(obj_type))) 585 584 return -EINVAL; 586 585 587 586 /* Backend is expected to check for zero fsid (e.g. tmpfs) */ ··· 593 592 conn = fsnotify_grab_connector(connp); 594 593 if (!conn) { 595 594 spin_unlock(&mark->lock); 596 - err = fsnotify_attach_connector_to_object(connp, type, fsid); 595 + err = fsnotify_attach_connector_to_object(connp, obj_type, 596 + fsid); 597 597 if (err) 598 598 return err; 599 599 goto restart; ··· 667 665 * event types should be delivered to which group. 668 666 */ 669 667 int fsnotify_add_mark_locked(struct fsnotify_mark *mark, 670 - fsnotify_connp_t *connp, unsigned int type, 668 + fsnotify_connp_t *connp, unsigned int obj_type, 671 669 int allow_dups, __kernel_fsid_t *fsid) 672 670 { 673 671 struct fsnotify_group *group = mark->group; ··· 688 686 fsnotify_get_mark(mark); /* for g_list */ 689 687 spin_unlock(&mark->lock); 690 688 691 - ret = fsnotify_add_mark_list(mark, connp, type, allow_dups, fsid); 689 + ret = fsnotify_add_mark_list(mark, connp, obj_type, allow_dups, fsid); 692 690 if (ret) 693 691 goto err; 694 692 ··· 708 706 } 709 707 710 708 int fsnotify_add_mark(struct fsnotify_mark *mark, fsnotify_connp_t *connp, 711 - unsigned int type, int allow_dups, __kernel_fsid_t *fsid) 709 + unsigned int obj_type, int allow_dups, 710 + __kernel_fsid_t *fsid) 712 711 { 713 712 int ret; 714 713 struct fsnotify_group *group = mark->group; 715 714 716 715 mutex_lock(&group->mark_mutex); 717 - ret = fsnotify_add_mark_locked(mark, connp, type, allow_dups, fsid); 716 + ret = fsnotify_add_mark_locked(mark, connp, obj_type, allow_dups, fsid); 718 717 mutex_unlock(&group->mark_mutex); 719 718 return ret; 720 719 } ··· 750 747 751 748 /* Clear any marks in a group with given type mask */ 752 749 void fsnotify_clear_marks_by_group(struct fsnotify_group *group, 753 - unsigned int type_mask) 750 + unsigned int obj_type) 754 751 { 755 752 struct fsnotify_mark *lmark, *mark; 756 753 LIST_HEAD(to_free); 757 754 struct list_head *head = &to_free; 758 755 759 756 /* Skip selection step if we want to clear all marks. */ 760 - if (type_mask == FSNOTIFY_OBJ_ALL_TYPES_MASK) { 757 + if (obj_type == FSNOTIFY_OBJ_TYPE_ANY) { 761 758 head = &group->marks_list; 762 759 goto clear; 763 760 } ··· 772 769 */ 773 770 mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING); 774 771 list_for_each_entry_safe(mark, lmark, &group->marks_list, g_list) { 775 - if ((1U << mark->connector->type) & type_mask) 772 + if (mark->connector->type == obj_type) 776 773 list_move(&mark->g_list, &to_free); 777 774 } 778 775 mutex_unlock(&group->mark_mutex);
+1 -1
include/linux/dnotify.h
··· 26 26 FS_MODIFY | FS_MODIFY_CHILD |\ 27 27 FS_ACCESS | FS_ACCESS_CHILD |\ 28 28 FS_ATTRIB | FS_ATTRIB_CHILD |\ 29 - FS_CREATE | FS_DN_RENAME |\ 29 + FS_CREATE | FS_RENAME |\ 30 30 FS_MOVED_FROM | FS_MOVED_TO) 31 31 32 32 extern int dir_notify_enable;
+3 -2
include/linux/fanotify.h
··· 25 25 26 26 #define FANOTIFY_CLASS_BITS (FAN_CLASS_NOTIF | FANOTIFY_PERM_CLASSES) 27 27 28 - #define FANOTIFY_FID_BITS (FAN_REPORT_FID | FAN_REPORT_DFID_NAME) 28 + #define FANOTIFY_FID_BITS (FAN_REPORT_DFID_NAME_TARGET) 29 29 30 30 #define FANOTIFY_INFO_MODES (FANOTIFY_FID_BITS | FAN_REPORT_PIDFD) 31 31 ··· 82 82 * Directory entry modification events - reported only to directory 83 83 * where entry is modified and not to a watching parent. 84 84 */ 85 - #define FANOTIFY_DIRENT_EVENTS (FAN_MOVE | FAN_CREATE | FAN_DELETE) 85 + #define FANOTIFY_DIRENT_EVENTS (FAN_MOVE | FAN_CREATE | FAN_DELETE | \ 86 + FAN_RENAME) 86 87 87 88 /* Events that can be reported with event->fd */ 88 89 #define FANOTIFY_FD_EVENTS (FANOTIFY_PATH_EVENTS | FANOTIFY_PERM_EVENTS)
+6 -3
include/linux/fsnotify.h
··· 144 144 u32 fs_cookie = fsnotify_get_cookie(); 145 145 __u32 old_dir_mask = FS_MOVED_FROM; 146 146 __u32 new_dir_mask = FS_MOVED_TO; 147 + __u32 rename_mask = FS_RENAME; 147 148 const struct qstr *new_name = &moved->d_name; 148 - 149 - if (old_dir == new_dir) 150 - old_dir_mask |= FS_DN_RENAME; 151 149 152 150 if (isdir) { 153 151 old_dir_mask |= FS_ISDIR; 154 152 new_dir_mask |= FS_ISDIR; 153 + rename_mask |= FS_ISDIR; 155 154 } 155 + 156 + /* Event with information about both old and new parent+name */ 157 + fsnotify_name(rename_mask, moved, FSNOTIFY_EVENT_DENTRY, 158 + old_dir, old_name, 0); 156 159 157 160 fsnotify_name(old_dir_mask, source, FSNOTIFY_EVENT_INODE, 158 161 old_dir, old_name, fs_cookie);
+43 -31
include/linux/fsnotify_backend.h
··· 63 63 */ 64 64 #define FS_EVENT_ON_CHILD 0x08000000 65 65 66 - #define FS_DN_RENAME 0x10000000 /* file renamed */ 66 + #define FS_RENAME 0x10000000 /* File was renamed */ 67 67 #define FS_DN_MULTISHOT 0x20000000 /* dnotify multishot */ 68 68 #define FS_ISDIR 0x40000000 /* event occurred against dir */ 69 69 #define FS_IN_ONESHOT 0x80000000 /* only send event once */ ··· 76 76 * The watching parent may get an FS_ATTRIB|FS_EVENT_ON_CHILD event 77 77 * when a directory entry inside a child subdir changes. 78 78 */ 79 - #define ALL_FSNOTIFY_DIRENT_EVENTS (FS_CREATE | FS_DELETE | FS_MOVE) 79 + #define ALL_FSNOTIFY_DIRENT_EVENTS (FS_CREATE | FS_DELETE | FS_MOVE | FS_RENAME) 80 80 81 81 #define ALL_FSNOTIFY_PERM_EVENTS (FS_OPEN_PERM | FS_ACCESS_PERM | \ 82 82 FS_OPEN_EXEC_PERM) ··· 101 101 /* Events that can be reported to backends */ 102 102 #define ALL_FSNOTIFY_EVENTS (ALL_FSNOTIFY_DIRENT_EVENTS | \ 103 103 FS_EVENTS_POSS_ON_CHILD | \ 104 - FS_DELETE_SELF | FS_MOVE_SELF | FS_DN_RENAME | \ 104 + FS_DELETE_SELF | FS_MOVE_SELF | \ 105 105 FS_UNMOUNT | FS_Q_OVERFLOW | FS_IN_IGNORED | \ 106 106 FS_ERROR) 107 107 ··· 337 337 } 338 338 } 339 339 340 + /* 341 + * Index to merged marks iterator array that correlates to a type of watch. 342 + * The type of watched object can be deduced from the iterator type, but not 343 + * the other way around, because an event can match different watched objects 344 + * of the same object type. 345 + * For example, both parent and child are watching an object of type inode. 346 + */ 347 + enum fsnotify_iter_type { 348 + FSNOTIFY_ITER_TYPE_INODE, 349 + FSNOTIFY_ITER_TYPE_VFSMOUNT, 350 + FSNOTIFY_ITER_TYPE_SB, 351 + FSNOTIFY_ITER_TYPE_PARENT, 352 + FSNOTIFY_ITER_TYPE_INODE2, 353 + FSNOTIFY_ITER_TYPE_COUNT 354 + }; 355 + 356 + /* The type of object that a mark is attached to */ 340 357 enum fsnotify_obj_type { 358 + FSNOTIFY_OBJ_TYPE_ANY = -1, 341 359 FSNOTIFY_OBJ_TYPE_INODE, 342 - FSNOTIFY_OBJ_TYPE_PARENT, 343 360 FSNOTIFY_OBJ_TYPE_VFSMOUNT, 344 361 FSNOTIFY_OBJ_TYPE_SB, 345 362 FSNOTIFY_OBJ_TYPE_COUNT, 346 363 FSNOTIFY_OBJ_TYPE_DETACHED = FSNOTIFY_OBJ_TYPE_COUNT 347 364 }; 348 365 349 - #define FSNOTIFY_OBJ_TYPE_INODE_FL (1U << FSNOTIFY_OBJ_TYPE_INODE) 350 - #define FSNOTIFY_OBJ_TYPE_PARENT_FL (1U << FSNOTIFY_OBJ_TYPE_PARENT) 351 - #define FSNOTIFY_OBJ_TYPE_VFSMOUNT_FL (1U << FSNOTIFY_OBJ_TYPE_VFSMOUNT) 352 - #define FSNOTIFY_OBJ_TYPE_SB_FL (1U << FSNOTIFY_OBJ_TYPE_SB) 353 - #define FSNOTIFY_OBJ_ALL_TYPES_MASK ((1U << FSNOTIFY_OBJ_TYPE_COUNT) - 1) 354 - 355 - static inline bool fsnotify_valid_obj_type(unsigned int type) 366 + static inline bool fsnotify_valid_obj_type(unsigned int obj_type) 356 367 { 357 - return (type < FSNOTIFY_OBJ_TYPE_COUNT); 368 + return (obj_type < FSNOTIFY_OBJ_TYPE_COUNT); 358 369 } 359 370 360 371 struct fsnotify_iter_info { 361 - struct fsnotify_mark *marks[FSNOTIFY_OBJ_TYPE_COUNT]; 372 + struct fsnotify_mark *marks[FSNOTIFY_ITER_TYPE_COUNT]; 362 373 unsigned int report_mask; 363 374 int srcu_idx; 364 375 }; 365 376 366 377 static inline bool fsnotify_iter_should_report_type( 367 - struct fsnotify_iter_info *iter_info, int type) 378 + struct fsnotify_iter_info *iter_info, int iter_type) 368 379 { 369 - return (iter_info->report_mask & (1U << type)); 380 + return (iter_info->report_mask & (1U << iter_type)); 370 381 } 371 382 372 383 static inline void fsnotify_iter_set_report_type( 373 - struct fsnotify_iter_info *iter_info, int type) 384 + struct fsnotify_iter_info *iter_info, int iter_type) 374 385 { 375 - iter_info->report_mask |= (1U << type); 386 + iter_info->report_mask |= (1U << iter_type); 376 387 } 377 388 378 389 static inline void fsnotify_iter_set_report_type_mark( 379 - struct fsnotify_iter_info *iter_info, int type, 390 + struct fsnotify_iter_info *iter_info, int iter_type, 380 391 struct fsnotify_mark *mark) 381 392 { 382 - iter_info->marks[type] = mark; 383 - iter_info->report_mask |= (1U << type); 393 + iter_info->marks[iter_type] = mark; 394 + iter_info->report_mask |= (1U << iter_type); 384 395 } 385 396 386 397 #define FSNOTIFY_ITER_FUNCS(name, NAME) \ 387 398 static inline struct fsnotify_mark *fsnotify_iter_##name##_mark( \ 388 399 struct fsnotify_iter_info *iter_info) \ 389 400 { \ 390 - return (iter_info->report_mask & FSNOTIFY_OBJ_TYPE_##NAME##_FL) ? \ 391 - iter_info->marks[FSNOTIFY_OBJ_TYPE_##NAME] : NULL; \ 401 + return (iter_info->report_mask & (1U << FSNOTIFY_ITER_TYPE_##NAME)) ? \ 402 + iter_info->marks[FSNOTIFY_ITER_TYPE_##NAME] : NULL; \ 392 403 } 393 404 394 405 FSNOTIFY_ITER_FUNCS(inode, INODE) ··· 407 396 FSNOTIFY_ITER_FUNCS(vfsmount, VFSMOUNT) 408 397 FSNOTIFY_ITER_FUNCS(sb, SB) 409 398 410 - #define fsnotify_foreach_obj_type(type) \ 411 - for (type = 0; type < FSNOTIFY_OBJ_TYPE_COUNT; type++) 399 + #define fsnotify_foreach_iter_type(type) \ 400 + for (type = 0; type < FSNOTIFY_ITER_TYPE_COUNT; type++) 412 401 413 402 /* 414 403 * fsnotify_connp_t is what we embed in objects which connector can be attached ··· 615 604 __kernel_fsid_t *fsid); 616 605 /* attach the mark to the object */ 617 606 extern int fsnotify_add_mark(struct fsnotify_mark *mark, 618 - fsnotify_connp_t *connp, unsigned int type, 607 + fsnotify_connp_t *connp, unsigned int obj_type, 619 608 int allow_dups, __kernel_fsid_t *fsid); 620 609 extern int fsnotify_add_mark_locked(struct fsnotify_mark *mark, 621 610 fsnotify_connp_t *connp, 622 - unsigned int type, int allow_dups, 611 + unsigned int obj_type, int allow_dups, 623 612 __kernel_fsid_t *fsid); 624 613 625 614 /* attach the mark to the inode */ ··· 648 637 extern void fsnotify_free_mark(struct fsnotify_mark *mark); 649 638 /* Wait until all marks queued for destruction are destroyed */ 650 639 extern void fsnotify_wait_marks_destroyed(void); 651 - /* run all the marks in a group, and clear all of the marks attached to given object type */ 652 - extern void fsnotify_clear_marks_by_group(struct fsnotify_group *group, unsigned int type); 640 + /* Clear all of the marks of a group attached to a given object type */ 641 + extern void fsnotify_clear_marks_by_group(struct fsnotify_group *group, 642 + unsigned int obj_type); 653 643 /* run all the marks in a group, and clear all of the vfsmount marks */ 654 644 static inline void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group) 655 645 { 656 - fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_TYPE_VFSMOUNT_FL); 646 + fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_TYPE_VFSMOUNT); 657 647 } 658 648 /* run all the marks in a group, and clear all of the inode marks */ 659 649 static inline void fsnotify_clear_inode_marks_by_group(struct fsnotify_group *group) 660 650 { 661 - fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_TYPE_INODE_FL); 651 + fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_TYPE_INODE); 662 652 } 663 653 /* run all the marks in a group, and clear all of the sn marks */ 664 654 static inline void fsnotify_clear_sb_marks_by_group(struct fsnotify_group *group) 665 655 { 666 - fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_TYPE_SB_FL); 656 + fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_TYPE_SB); 667 657 } 668 658 extern void fsnotify_get_mark(struct fsnotify_mark *mark); 669 659 extern void fsnotify_put_mark(struct fsnotify_mark *mark);
+12
include/uapi/linux/fanotify.h
··· 28 28 29 29 #define FAN_EVENT_ON_CHILD 0x08000000 /* Interested in child events */ 30 30 31 + #define FAN_RENAME 0x10000000 /* File was renamed */ 32 + 31 33 #define FAN_ONDIR 0x40000000 /* Event occurred against dir */ 32 34 33 35 /* helper events */ ··· 59 57 #define FAN_REPORT_FID 0x00000200 /* Report unique file id */ 60 58 #define FAN_REPORT_DIR_FID 0x00000400 /* Report unique directory id */ 61 59 #define FAN_REPORT_NAME 0x00000800 /* Report events with name */ 60 + #define FAN_REPORT_TARGET_FID 0x00001000 /* Report dirent target id */ 62 61 63 62 /* Convenience macro - FAN_REPORT_NAME requires FAN_REPORT_DIR_FID */ 64 63 #define FAN_REPORT_DFID_NAME (FAN_REPORT_DIR_FID | FAN_REPORT_NAME) 64 + /* Convenience macro - FAN_REPORT_TARGET_FID requires all other FID flags */ 65 + #define FAN_REPORT_DFID_NAME_TARGET (FAN_REPORT_DFID_NAME | \ 66 + FAN_REPORT_FID | FAN_REPORT_TARGET_FID) 65 67 66 68 /* Deprecated - do not use this in programs and do not add new flags here! */ 67 69 #define FAN_ALL_INIT_FLAGS (FAN_CLOEXEC | FAN_NONBLOCK | \ ··· 133 127 #define FAN_EVENT_INFO_TYPE_DFID 3 134 128 #define FAN_EVENT_INFO_TYPE_PIDFD 4 135 129 #define FAN_EVENT_INFO_TYPE_ERROR 5 130 + 131 + /* Special info types for FAN_RENAME */ 132 + #define FAN_EVENT_INFO_TYPE_OLD_DFID_NAME 10 133 + /* Reserved for FAN_EVENT_INFO_TYPE_OLD_DFID 11 */ 134 + #define FAN_EVENT_INFO_TYPE_NEW_DFID_NAME 12 135 + /* Reserved for FAN_EVENT_INFO_TYPE_NEW_DFID 13 */ 136 136 137 137 /* Variable length info record following event metadata */ 138 138 struct fanotify_event_info_header {