mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 05:02:12 +00:00
\n
-----BEGIN PGP SIGNATURE----- iQEzBAABCAAdFiEEq1nRK9aeMoq1VSgcnJ2qBz9kQNkFAmHektkACgkQnJ2qBz9k QNk73Qf9G/8C29GC7lTZvW8ZOqM2onvP16/wpMU98jkw6/xpsdGLMmQlP4JCdB6Y mTttvPxwMMVrdRmt+MNIgvWPOK2LKHdkbNbj0DRw4JxLEIm+zXddAXAcvX2vLeUn N24idiVQxIKWS3zJhQ6H7sFjSrZ7ztjkeHWff70LIzURIupYO0+rRmKDgOqo6D5g cKAdb8x9ZQLr0CTQoHKQxA8IeCSirSblVaDMdes2KrJH+i05s3aqS9jBvY16nrLo Xvm4Vv7ecQXcmKDswuxVcmBVlVVsWxoYv1w8+v9qRGJnbgpQkjjgCGjCh54M18Do /OovTVlqGWRfmf2Eo1FCXXz90ppGlQ== =gvMh -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
3d3d673306
@ -196,7 +196,7 @@ static __u32 convert_arg(unsigned long arg)
|
||||
if (arg & DN_ATTRIB)
|
||||
new_mask |= FS_ATTRIB;
|
||||
if (arg & DN_RENAME)
|
||||
new_mask |= FS_DN_RENAME;
|
||||
new_mask |= FS_RENAME;
|
||||
if (arg & DN_CREATE)
|
||||
new_mask |= (FS_CREATE | FS_MOVED_TO);
|
||||
|
||||
|
@ -76,8 +76,10 @@ static bool fanotify_info_equal(struct fanotify_info *info1,
|
||||
struct fanotify_info *info2)
|
||||
{
|
||||
if (info1->dir_fh_totlen != info2->dir_fh_totlen ||
|
||||
info1->dir2_fh_totlen != info2->dir2_fh_totlen ||
|
||||
info1->file_fh_totlen != info2->file_fh_totlen ||
|
||||
info1->name_len != info2->name_len)
|
||||
info1->name_len != info2->name_len ||
|
||||
info1->name2_len != info2->name2_len)
|
||||
return false;
|
||||
|
||||
if (info1->dir_fh_totlen &&
|
||||
@ -85,14 +87,24 @@ static bool fanotify_info_equal(struct fanotify_info *info1,
|
||||
fanotify_info_dir_fh(info2)))
|
||||
return false;
|
||||
|
||||
if (info1->dir2_fh_totlen &&
|
||||
!fanotify_fh_equal(fanotify_info_dir2_fh(info1),
|
||||
fanotify_info_dir2_fh(info2)))
|
||||
return false;
|
||||
|
||||
if (info1->file_fh_totlen &&
|
||||
!fanotify_fh_equal(fanotify_info_file_fh(info1),
|
||||
fanotify_info_file_fh(info2)))
|
||||
return false;
|
||||
|
||||
return !info1->name_len ||
|
||||
!memcmp(fanotify_info_name(info1), fanotify_info_name(info2),
|
||||
info1->name_len);
|
||||
if (info1->name_len &&
|
||||
memcmp(fanotify_info_name(info1), fanotify_info_name(info2),
|
||||
info1->name_len))
|
||||
return false;
|
||||
|
||||
return !info1->name2_len ||
|
||||
!memcmp(fanotify_info_name2(info1), fanotify_info_name2(info2),
|
||||
info1->name2_len);
|
||||
}
|
||||
|
||||
static bool fanotify_name_event_equal(struct fanotify_name_event *fne1,
|
||||
@ -141,6 +153,13 @@ static bool fanotify_should_merge(struct fanotify_event *old,
|
||||
if ((old->mask & FS_ISDIR) != (new->mask & FS_ISDIR))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* FAN_RENAME event is reported with special info record types,
|
||||
* so we cannot merge it with other events.
|
||||
*/
|
||||
if ((old->mask & FAN_RENAME) != (new->mask & FAN_RENAME))
|
||||
return false;
|
||||
|
||||
switch (old->type) {
|
||||
case FANOTIFY_EVENT_TYPE_PATH:
|
||||
return fanotify_path_equal(fanotify_event_path(old),
|
||||
@ -272,8 +291,9 @@ out:
|
||||
*/
|
||||
static u32 fanotify_group_event_mask(struct fsnotify_group *group,
|
||||
struct fsnotify_iter_info *iter_info,
|
||||
u32 event_mask, const void *data,
|
||||
int data_type, struct inode *dir)
|
||||
u32 *match_mask, u32 event_mask,
|
||||
const void *data, int data_type,
|
||||
struct inode *dir)
|
||||
{
|
||||
__u32 marks_mask = 0, marks_ignored_mask = 0;
|
||||
__u32 test_mask, user_mask = FANOTIFY_OUTGOING_EVENTS |
|
||||
@ -299,7 +319,7 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group,
|
||||
return 0;
|
||||
}
|
||||
|
||||
fsnotify_foreach_obj_type(type) {
|
||||
fsnotify_foreach_iter_type(type) {
|
||||
if (!fsnotify_iter_should_report_type(iter_info, type))
|
||||
continue;
|
||||
mark = iter_info->marks[type];
|
||||
@ -318,11 +338,14 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group,
|
||||
* If the event is on a child and this mark is on a parent not
|
||||
* watching children, don't send it!
|
||||
*/
|
||||
if (type == FSNOTIFY_OBJ_TYPE_PARENT &&
|
||||
if (type == FSNOTIFY_ITER_TYPE_PARENT &&
|
||||
!(mark->mask & FS_EVENT_ON_CHILD))
|
||||
continue;
|
||||
|
||||
marks_mask |= mark->mask;
|
||||
|
||||
/* Record the mark types of this group that matched the event */
|
||||
*match_mask |= 1U << type;
|
||||
}
|
||||
|
||||
test_mask = event_mask & marks_mask & ~marks_ignored_mask;
|
||||
@ -411,7 +434,7 @@ static int fanotify_encode_fh(struct fanotify_fh *fh, struct inode *inode,
|
||||
* be zero in that case if encoding fh len failed.
|
||||
*/
|
||||
err = -ENOENT;
|
||||
if (fh_len < 4 || WARN_ON_ONCE(fh_len % 4))
|
||||
if (fh_len < 4 || WARN_ON_ONCE(fh_len % 4) || fh_len > MAX_HANDLE_SZ)
|
||||
goto out_err;
|
||||
|
||||
/* No external buffer in a variable size allocated fh */
|
||||
@ -458,17 +481,41 @@ out_err:
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
@ -552,25 +599,34 @@ static struct fanotify_event *fanotify_alloc_fid_event(struct inode *id,
|
||||
return &ffe->fae;
|
||||
}
|
||||
|
||||
static struct fanotify_event *fanotify_alloc_name_event(struct inode *id,
|
||||
static struct fanotify_event *fanotify_alloc_name_event(struct inode *dir,
|
||||
__kernel_fsid_t *fsid,
|
||||
const struct qstr *name,
|
||||
struct inode *child,
|
||||
struct dentry *moved,
|
||||
unsigned int *hash,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct fanotify_name_event *fne;
|
||||
struct fanotify_info *info;
|
||||
struct fanotify_fh *dfh, *ffh;
|
||||
unsigned int dir_fh_len = fanotify_encode_fh_len(id);
|
||||
struct inode *dir2 = moved ? d_inode(moved->d_parent) : NULL;
|
||||
const struct qstr *name2 = moved ? &moved->d_name : NULL;
|
||||
unsigned int dir_fh_len = fanotify_encode_fh_len(dir);
|
||||
unsigned int dir2_fh_len = fanotify_encode_fh_len(dir2);
|
||||
unsigned int child_fh_len = fanotify_encode_fh_len(child);
|
||||
unsigned int size;
|
||||
unsigned long name_len = name ? name->len : 0;
|
||||
unsigned long name2_len = name2 ? name2->len : 0;
|
||||
unsigned int len, size;
|
||||
|
||||
size = sizeof(*fne) + FANOTIFY_FH_HDR_LEN + dir_fh_len;
|
||||
/* Reserve terminating null byte even for empty name */
|
||||
size = sizeof(*fne) + name_len + name2_len + 2;
|
||||
if (dir_fh_len)
|
||||
size += FANOTIFY_FH_HDR_LEN + dir_fh_len;
|
||||
if (dir2_fh_len)
|
||||
size += FANOTIFY_FH_HDR_LEN + dir2_fh_len;
|
||||
if (child_fh_len)
|
||||
size += FANOTIFY_FH_HDR_LEN + child_fh_len;
|
||||
if (name)
|
||||
size += name->len + 1;
|
||||
fne = kmalloc(size, gfp);
|
||||
if (!fne)
|
||||
return NULL;
|
||||
@ -580,24 +636,41 @@ static struct fanotify_event *fanotify_alloc_name_event(struct inode *id,
|
||||
*hash ^= fanotify_hash_fsid(fsid);
|
||||
info = &fne->info;
|
||||
fanotify_info_init(info);
|
||||
dfh = fanotify_info_dir_fh(info);
|
||||
info->dir_fh_totlen = fanotify_encode_fh(dfh, id, dir_fh_len, hash, 0);
|
||||
if (dir_fh_len) {
|
||||
dfh = fanotify_info_dir_fh(info);
|
||||
len = fanotify_encode_fh(dfh, dir, dir_fh_len, hash, 0);
|
||||
fanotify_info_set_dir_fh(info, len);
|
||||
}
|
||||
if (dir2_fh_len) {
|
||||
dfh = fanotify_info_dir2_fh(info);
|
||||
len = fanotify_encode_fh(dfh, dir2, dir2_fh_len, hash, 0);
|
||||
fanotify_info_set_dir2_fh(info, len);
|
||||
}
|
||||
if (child_fh_len) {
|
||||
ffh = fanotify_info_file_fh(info);
|
||||
info->file_fh_totlen = fanotify_encode_fh(ffh, child,
|
||||
child_fh_len, hash, 0);
|
||||
len = fanotify_encode_fh(ffh, child, child_fh_len, hash, 0);
|
||||
fanotify_info_set_file_fh(info, len);
|
||||
}
|
||||
if (name) {
|
||||
long salt = name->len;
|
||||
|
||||
if (name_len) {
|
||||
fanotify_info_copy_name(info, name);
|
||||
*hash ^= full_name_hash((void *)salt, name->name, name->len);
|
||||
*hash ^= full_name_hash((void *)name_len, name->name, name_len);
|
||||
}
|
||||
if (name2_len) {
|
||||
fanotify_info_copy_name2(info, name2);
|
||||
*hash ^= full_name_hash((void *)name2_len, name2->name,
|
||||
name2_len);
|
||||
}
|
||||
|
||||
pr_debug("%s: ino=%lu size=%u dir_fh_len=%u child_fh_len=%u name_len=%u name='%.*s'\n",
|
||||
__func__, id->i_ino, size, dir_fh_len, child_fh_len,
|
||||
pr_debug("%s: size=%u dir_fh_len=%u child_fh_len=%u name_len=%u name='%.*s'\n",
|
||||
__func__, size, dir_fh_len, child_fh_len,
|
||||
info->name_len, info->name_len, fanotify_info_name(info));
|
||||
|
||||
if (dir2_fh_len) {
|
||||
pr_debug("%s: dir2_fh_len=%u name2_len=%u name2='%.*s'\n",
|
||||
__func__, dir2_fh_len, info->name2_len,
|
||||
info->name2_len, fanotify_info_name2(info));
|
||||
}
|
||||
|
||||
return &fne->fae;
|
||||
}
|
||||
|
||||
@ -639,19 +712,21 @@ static struct fanotify_event *fanotify_alloc_error_event(
|
||||
return &fee->fae;
|
||||
}
|
||||
|
||||
static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
|
||||
u32 mask, const void *data,
|
||||
int data_type, struct inode *dir,
|
||||
const struct qstr *file_name,
|
||||
__kernel_fsid_t *fsid)
|
||||
static struct fanotify_event *fanotify_alloc_event(
|
||||
struct fsnotify_group *group,
|
||||
u32 mask, const void *data, int data_type,
|
||||
struct inode *dir, const struct qstr *file_name,
|
||||
__kernel_fsid_t *fsid, u32 match_mask)
|
||||
{
|
||||
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 dentry *moved = NULL;
|
||||
struct inode *child = NULL;
|
||||
bool name_event = false;
|
||||
unsigned int hash = 0;
|
||||
@ -660,11 +735,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;
|
||||
@ -688,6 +762,38 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
|
||||
} else if ((mask & ALL_FSNOTIFY_DIRENT_EVENTS) || !ondir) {
|
||||
name_event = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* In the special case of FAN_RENAME event, use the match_mask
|
||||
* to determine if we need to report only the old parent+name,
|
||||
* only the new parent+name or both.
|
||||
* 'dirid' and 'file_name' are the old parent+name and
|
||||
* 'moved' has the new parent+name.
|
||||
*/
|
||||
if (mask & FAN_RENAME) {
|
||||
bool report_old, report_new;
|
||||
|
||||
if (WARN_ON_ONCE(!match_mask))
|
||||
return NULL;
|
||||
|
||||
/* Report both old and new parent+name if sb watching */
|
||||
report_old = report_new =
|
||||
match_mask & (1U << FSNOTIFY_ITER_TYPE_SB);
|
||||
report_old |=
|
||||
match_mask & (1U << FSNOTIFY_ITER_TYPE_INODE);
|
||||
report_new |=
|
||||
match_mask & (1U << FSNOTIFY_ITER_TYPE_INODE2);
|
||||
|
||||
if (!report_old) {
|
||||
/* Do not report old parent+name */
|
||||
dirid = NULL;
|
||||
file_name = NULL;
|
||||
}
|
||||
if (report_new) {
|
||||
/* Report new parent+name */
|
||||
moved = fsnotify_data_dentry(data, data_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -709,9 +815,9 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
|
||||
} else if (fanotify_is_error_event(mask)) {
|
||||
event = fanotify_alloc_error_event(group, fsid, data,
|
||||
data_type, &hash);
|
||||
} else if (name_event && (file_name || child)) {
|
||||
event = fanotify_alloc_name_event(id, fsid, file_name, child,
|
||||
&hash, gfp);
|
||||
} else if (name_event && (file_name || moved || child)) {
|
||||
event = fanotify_alloc_name_event(dirid, fsid, file_name, child,
|
||||
moved, &hash, gfp);
|
||||
} else if (fid_mode) {
|
||||
event = fanotify_alloc_fid_event(id, fsid, &hash, gfp);
|
||||
} else {
|
||||
@ -746,7 +852,7 @@ static __kernel_fsid_t fanotify_get_fsid(struct fsnotify_iter_info *iter_info)
|
||||
int type;
|
||||
__kernel_fsid_t fsid = {};
|
||||
|
||||
fsnotify_foreach_obj_type(type) {
|
||||
fsnotify_foreach_iter_type(type) {
|
||||
struct fsnotify_mark_connector *conn;
|
||||
|
||||
if (!fsnotify_iter_should_report_type(iter_info, type))
|
||||
@ -800,6 +906,7 @@ static int fanotify_handle_event(struct fsnotify_group *group, u32 mask,
|
||||
struct fanotify_event *event;
|
||||
struct fsnotify_event *fsn_event;
|
||||
__kernel_fsid_t fsid = {};
|
||||
u32 match_mask = 0;
|
||||
|
||||
BUILD_BUG_ON(FAN_ACCESS != FS_ACCESS);
|
||||
BUILD_BUG_ON(FAN_MODIFY != FS_MODIFY);
|
||||
@ -821,15 +928,17 @@ static int fanotify_handle_event(struct fsnotify_group *group, u32 mask,
|
||||
BUILD_BUG_ON(FAN_OPEN_EXEC != FS_OPEN_EXEC);
|
||||
BUILD_BUG_ON(FAN_OPEN_EXEC_PERM != FS_OPEN_EXEC_PERM);
|
||||
BUILD_BUG_ON(FAN_FS_ERROR != FS_ERROR);
|
||||
BUILD_BUG_ON(FAN_RENAME != FS_RENAME);
|
||||
|
||||
BUILD_BUG_ON(HWEIGHT32(ALL_FANOTIFY_EVENT_BITS) != 20);
|
||||
BUILD_BUG_ON(HWEIGHT32(ALL_FANOTIFY_EVENT_BITS) != 21);
|
||||
|
||||
mask = fanotify_group_event_mask(group, iter_info, mask, data,
|
||||
data_type, dir);
|
||||
mask = fanotify_group_event_mask(group, iter_info, &match_mask,
|
||||
mask, data, data_type, dir);
|
||||
if (!mask)
|
||||
return 0;
|
||||
|
||||
pr_debug("%s: group=%p mask=%x\n", __func__, group, mask);
|
||||
pr_debug("%s: group=%p mask=%x report_mask=%x\n", __func__,
|
||||
group, mask, match_mask);
|
||||
|
||||
if (fanotify_is_perm_event(mask)) {
|
||||
/*
|
||||
@ -848,7 +957,7 @@ static int fanotify_handle_event(struct fsnotify_group *group, u32 mask,
|
||||
}
|
||||
|
||||
event = fanotify_alloc_event(group, mask, data, data_type, dir,
|
||||
file_name, &fsid);
|
||||
file_name, &fsid, match_mask);
|
||||
ret = -ENOMEM;
|
||||
if (unlikely(!event)) {
|
||||
/*
|
||||
|
@ -40,15 +40,45 @@ struct fanotify_fh {
|
||||
struct fanotify_info {
|
||||
/* size of dir_fh/file_fh including fanotify_fh hdr size */
|
||||
u8 dir_fh_totlen;
|
||||
u8 dir2_fh_totlen;
|
||||
u8 file_fh_totlen;
|
||||
u8 name_len;
|
||||
u8 pad;
|
||||
u8 name2_len;
|
||||
u8 pad[3];
|
||||
unsigned char buf[];
|
||||
/*
|
||||
* (struct fanotify_fh) dir_fh starts at buf[0]
|
||||
* (optional) file_fh starts at buf[dir_fh_totlen]
|
||||
* name starts at buf[dir_fh_totlen + file_fh_totlen]
|
||||
* (optional) dir2_fh starts at buf[dir_fh_totlen]
|
||||
* (optional) file_fh starts at buf[dir_fh_totlen + dir2_fh_totlen]
|
||||
* name starts at buf[dir_fh_totlen + dir2_fh_totlen + file_fh_totlen]
|
||||
* ...
|
||||
*/
|
||||
#define FANOTIFY_DIR_FH_SIZE(info) ((info)->dir_fh_totlen)
|
||||
#define FANOTIFY_DIR2_FH_SIZE(info) ((info)->dir2_fh_totlen)
|
||||
#define FANOTIFY_FILE_FH_SIZE(info) ((info)->file_fh_totlen)
|
||||
#define FANOTIFY_NAME_SIZE(info) ((info)->name_len + 1)
|
||||
#define FANOTIFY_NAME2_SIZE(info) ((info)->name2_len + 1)
|
||||
|
||||
#define FANOTIFY_DIR_FH_OFFSET(info) 0
|
||||
#define FANOTIFY_DIR2_FH_OFFSET(info) \
|
||||
(FANOTIFY_DIR_FH_OFFSET(info) + FANOTIFY_DIR_FH_SIZE(info))
|
||||
#define FANOTIFY_FILE_FH_OFFSET(info) \
|
||||
(FANOTIFY_DIR2_FH_OFFSET(info) + FANOTIFY_DIR2_FH_SIZE(info))
|
||||
#define FANOTIFY_NAME_OFFSET(info) \
|
||||
(FANOTIFY_FILE_FH_OFFSET(info) + FANOTIFY_FILE_FH_SIZE(info))
|
||||
#define FANOTIFY_NAME2_OFFSET(info) \
|
||||
(FANOTIFY_NAME_OFFSET(info) + FANOTIFY_NAME_SIZE(info))
|
||||
|
||||
#define FANOTIFY_DIR_FH_BUF(info) \
|
||||
((info)->buf + FANOTIFY_DIR_FH_OFFSET(info))
|
||||
#define FANOTIFY_DIR2_FH_BUF(info) \
|
||||
((info)->buf + FANOTIFY_DIR2_FH_OFFSET(info))
|
||||
#define FANOTIFY_FILE_FH_BUF(info) \
|
||||
((info)->buf + FANOTIFY_FILE_FH_OFFSET(info))
|
||||
#define FANOTIFY_NAME_BUF(info) \
|
||||
((info)->buf + FANOTIFY_NAME_OFFSET(info))
|
||||
#define FANOTIFY_NAME2_BUF(info) \
|
||||
((info)->buf + FANOTIFY_NAME2_OFFSET(info))
|
||||
} __aligned(4);
|
||||
|
||||
static inline bool fanotify_fh_has_ext_buf(struct fanotify_fh *fh)
|
||||
@ -87,7 +117,21 @@ static inline struct fanotify_fh *fanotify_info_dir_fh(struct fanotify_info *inf
|
||||
{
|
||||
BUILD_BUG_ON(offsetof(struct fanotify_info, buf) % 4);
|
||||
|
||||
return (struct fanotify_fh *)info->buf;
|
||||
return (struct fanotify_fh *)FANOTIFY_DIR_FH_BUF(info);
|
||||
}
|
||||
|
||||
static inline int fanotify_info_dir2_fh_len(struct fanotify_info *info)
|
||||
{
|
||||
if (!info->dir2_fh_totlen ||
|
||||
WARN_ON_ONCE(info->dir2_fh_totlen < FANOTIFY_FH_HDR_LEN))
|
||||
return 0;
|
||||
|
||||
return info->dir2_fh_totlen - FANOTIFY_FH_HDR_LEN;
|
||||
}
|
||||
|
||||
static inline struct fanotify_fh *fanotify_info_dir2_fh(struct fanotify_info *info)
|
||||
{
|
||||
return (struct fanotify_fh *)FANOTIFY_DIR2_FH_BUF(info);
|
||||
}
|
||||
|
||||
static inline int fanotify_info_file_fh_len(struct fanotify_info *info)
|
||||
@ -101,32 +145,90 @@ static inline int fanotify_info_file_fh_len(struct fanotify_info *info)
|
||||
|
||||
static inline struct fanotify_fh *fanotify_info_file_fh(struct fanotify_info *info)
|
||||
{
|
||||
return (struct fanotify_fh *)(info->buf + info->dir_fh_totlen);
|
||||
return (struct fanotify_fh *)FANOTIFY_FILE_FH_BUF(info);
|
||||
}
|
||||
|
||||
static inline const char *fanotify_info_name(struct fanotify_info *info)
|
||||
static inline char *fanotify_info_name(struct fanotify_info *info)
|
||||
{
|
||||
return info->buf + info->dir_fh_totlen + info->file_fh_totlen;
|
||||
if (!info->name_len)
|
||||
return NULL;
|
||||
|
||||
return FANOTIFY_NAME_BUF(info);
|
||||
}
|
||||
|
||||
static inline char *fanotify_info_name2(struct fanotify_info *info)
|
||||
{
|
||||
if (!info->name2_len)
|
||||
return NULL;
|
||||
|
||||
return FANOTIFY_NAME2_BUF(info);
|
||||
}
|
||||
|
||||
static inline void fanotify_info_init(struct fanotify_info *info)
|
||||
{
|
||||
BUILD_BUG_ON(FANOTIFY_FH_HDR_LEN + MAX_HANDLE_SZ > U8_MAX);
|
||||
BUILD_BUG_ON(NAME_MAX > U8_MAX);
|
||||
|
||||
info->dir_fh_totlen = 0;
|
||||
info->dir2_fh_totlen = 0;
|
||||
info->file_fh_totlen = 0;
|
||||
info->name_len = 0;
|
||||
info->name2_len = 0;
|
||||
}
|
||||
|
||||
static inline unsigned int fanotify_info_len(struct fanotify_info *info)
|
||||
/* These set/copy helpers MUST be called by order */
|
||||
static inline void fanotify_info_set_dir_fh(struct fanotify_info *info,
|
||||
unsigned int totlen)
|
||||
{
|
||||
return info->dir_fh_totlen + info->file_fh_totlen + info->name_len;
|
||||
if (WARN_ON_ONCE(info->dir2_fh_totlen > 0) ||
|
||||
WARN_ON_ONCE(info->file_fh_totlen > 0) ||
|
||||
WARN_ON_ONCE(info->name_len > 0) ||
|
||||
WARN_ON_ONCE(info->name2_len > 0))
|
||||
return;
|
||||
|
||||
info->dir_fh_totlen = totlen;
|
||||
}
|
||||
|
||||
static inline void fanotify_info_set_dir2_fh(struct fanotify_info *info,
|
||||
unsigned int totlen)
|
||||
{
|
||||
if (WARN_ON_ONCE(info->file_fh_totlen > 0) ||
|
||||
WARN_ON_ONCE(info->name_len > 0) ||
|
||||
WARN_ON_ONCE(info->name2_len > 0))
|
||||
return;
|
||||
|
||||
info->dir2_fh_totlen = totlen;
|
||||
}
|
||||
|
||||
static inline void fanotify_info_set_file_fh(struct fanotify_info *info,
|
||||
unsigned int totlen)
|
||||
{
|
||||
if (WARN_ON_ONCE(info->name_len > 0) ||
|
||||
WARN_ON_ONCE(info->name2_len > 0))
|
||||
return;
|
||||
|
||||
info->file_fh_totlen = totlen;
|
||||
}
|
||||
|
||||
static inline void fanotify_info_copy_name(struct fanotify_info *info,
|
||||
const struct qstr *name)
|
||||
{
|
||||
if (WARN_ON_ONCE(name->len > NAME_MAX) ||
|
||||
WARN_ON_ONCE(info->name2_len > 0))
|
||||
return;
|
||||
|
||||
info->name_len = name->len;
|
||||
strcpy(info->buf + info->dir_fh_totlen + info->file_fh_totlen,
|
||||
name->name);
|
||||
strcpy(fanotify_info_name(info), name->name);
|
||||
}
|
||||
|
||||
static inline void fanotify_info_copy_name2(struct fanotify_info *info,
|
||||
const struct qstr *name)
|
||||
{
|
||||
if (WARN_ON_ONCE(name->len > NAME_MAX))
|
||||
return;
|
||||
|
||||
info->name2_len = name->len;
|
||||
strcpy(fanotify_info_name2(info), name->name);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -271,6 +373,13 @@ static inline int fanotify_event_dir_fh_len(struct fanotify_event *event)
|
||||
return info ? fanotify_info_dir_fh_len(info) : 0;
|
||||
}
|
||||
|
||||
static inline int fanotify_event_dir2_fh_len(struct fanotify_event *event)
|
||||
{
|
||||
struct fanotify_info *info = fanotify_event_info(event);
|
||||
|
||||
return info ? fanotify_info_dir2_fh_len(info) : 0;
|
||||
}
|
||||
|
||||
static inline bool fanotify_event_has_object_fh(struct fanotify_event *event)
|
||||
{
|
||||
/* For error events, even zeroed fh are reported. */
|
||||
@ -284,6 +393,17 @@ static inline bool fanotify_event_has_dir_fh(struct fanotify_event *event)
|
||||
return fanotify_event_dir_fh_len(event) > 0;
|
||||
}
|
||||
|
||||
static inline bool fanotify_event_has_dir2_fh(struct fanotify_event *event)
|
||||
{
|
||||
return fanotify_event_dir2_fh_len(event) > 0;
|
||||
}
|
||||
|
||||
static inline bool fanotify_event_has_any_dir_fh(struct fanotify_event *event)
|
||||
{
|
||||
return fanotify_event_has_dir_fh(event) ||
|
||||
fanotify_event_has_dir2_fh(event);
|
||||
}
|
||||
|
||||
struct fanotify_path_event {
|
||||
struct fanotify_event fae;
|
||||
struct path path;
|
||||
|
@ -129,12 +129,29 @@ static int fanotify_fid_info_len(int fh_len, int name_len)
|
||||
FANOTIFY_EVENT_ALIGN);
|
||||
}
|
||||
|
||||
/* FAN_RENAME may have one or two dir+name info records */
|
||||
static int fanotify_dir_name_info_len(struct fanotify_event *event)
|
||||
{
|
||||
struct fanotify_info *info = fanotify_event_info(event);
|
||||
int dir_fh_len = fanotify_event_dir_fh_len(event);
|
||||
int dir2_fh_len = fanotify_event_dir2_fh_len(event);
|
||||
int info_len = 0;
|
||||
|
||||
if (dir_fh_len)
|
||||
info_len += fanotify_fid_info_len(dir_fh_len,
|
||||
info->name_len);
|
||||
if (dir2_fh_len)
|
||||
info_len += fanotify_fid_info_len(dir2_fh_len,
|
||||
info->name2_len);
|
||||
|
||||
return info_len;
|
||||
}
|
||||
|
||||
static size_t fanotify_event_len(unsigned int info_mode,
|
||||
struct fanotify_event *event)
|
||||
{
|
||||
size_t event_len = FAN_EVENT_METADATA_LEN;
|
||||
struct fanotify_info *info;
|
||||
int dir_fh_len;
|
||||
int fh_len;
|
||||
int dot_len = 0;
|
||||
|
||||
@ -146,9 +163,8 @@ static size_t fanotify_event_len(unsigned int info_mode,
|
||||
|
||||
info = fanotify_event_info(event);
|
||||
|
||||
if (fanotify_event_has_dir_fh(event)) {
|
||||
dir_fh_len = fanotify_event_dir_fh_len(event);
|
||||
event_len += fanotify_fid_info_len(dir_fh_len, info->name_len);
|
||||
if (fanotify_event_has_any_dir_fh(event)) {
|
||||
event_len += fanotify_dir_name_info_len(event);
|
||||
} else if ((info_mode & FAN_REPORT_NAME) &&
|
||||
(event->mask & FAN_ONDIR)) {
|
||||
/*
|
||||
@ -332,11 +348,10 @@ static int process_access_response(struct fsnotify_group *group,
|
||||
static size_t copy_error_info_to_user(struct fanotify_event *event,
|
||||
char __user *buf, int count)
|
||||
{
|
||||
struct fanotify_event_info_error info;
|
||||
struct fanotify_event_info_error info = { };
|
||||
struct fanotify_error_event *fee = FANOTIFY_EE(event);
|
||||
|
||||
info.hdr.info_type = FAN_EVENT_INFO_TYPE_ERROR;
|
||||
info.hdr.pad = 0;
|
||||
info.hdr.len = FANOTIFY_ERROR_INFO_LEN;
|
||||
|
||||
if (WARN_ON(count < info.hdr.len))
|
||||
@ -380,6 +395,8 @@ static int copy_fid_info_to_user(__kernel_fsid_t *fsid, struct fanotify_fh *fh,
|
||||
return -EFAULT;
|
||||
break;
|
||||
case FAN_EVENT_INFO_TYPE_DFID_NAME:
|
||||
case FAN_EVENT_INFO_TYPE_OLD_DFID_NAME:
|
||||
case FAN_EVENT_INFO_TYPE_NEW_DFID_NAME:
|
||||
if (WARN_ON_ONCE(!name || !name_len))
|
||||
return -EFAULT;
|
||||
break;
|
||||
@ -479,11 +496,19 @@ static int copy_info_records_to_user(struct fanotify_event *event,
|
||||
unsigned int pidfd_mode = info_mode & FAN_REPORT_PIDFD;
|
||||
|
||||
/*
|
||||
* Event info records order is as follows: dir fid + name, child fid.
|
||||
* Event info records order is as follows:
|
||||
* 1. dir fid + name
|
||||
* 2. (optional) new dir fid + new name
|
||||
* 3. (optional) child fid
|
||||
*/
|
||||
if (fanotify_event_has_dir_fh(event)) {
|
||||
info_type = info->name_len ? FAN_EVENT_INFO_TYPE_DFID_NAME :
|
||||
FAN_EVENT_INFO_TYPE_DFID;
|
||||
|
||||
/* FAN_RENAME uses special info types */
|
||||
if (event->mask & FAN_RENAME)
|
||||
info_type = FAN_EVENT_INFO_TYPE_OLD_DFID_NAME;
|
||||
|
||||
ret = copy_fid_info_to_user(fanotify_event_fsid(event),
|
||||
fanotify_info_dir_fh(info),
|
||||
info_type,
|
||||
@ -497,6 +522,22 @@ static int copy_info_records_to_user(struct fanotify_event *event,
|
||||
total_bytes += ret;
|
||||
}
|
||||
|
||||
/* New dir fid+name may be reported in addition to old dir fid+name */
|
||||
if (fanotify_event_has_dir2_fh(event)) {
|
||||
info_type = FAN_EVENT_INFO_TYPE_NEW_DFID_NAME;
|
||||
ret = copy_fid_info_to_user(fanotify_event_fsid(event),
|
||||
fanotify_info_dir2_fh(info),
|
||||
info_type,
|
||||
fanotify_info_name2(info),
|
||||
info->name2_len, buf, count);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
buf += ret;
|
||||
count -= ret;
|
||||
total_bytes += ret;
|
||||
}
|
||||
|
||||
if (fanotify_event_has_object_fh(event)) {
|
||||
const char *dot = NULL;
|
||||
int dot_len = 0;
|
||||
@ -1057,7 +1098,7 @@ 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 type,
|
||||
unsigned int obj_type,
|
||||
__kernel_fsid_t *fsid)
|
||||
{
|
||||
struct ucounts *ucounts = group->fanotify_data.ucounts;
|
||||
@ -1080,7 +1121,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, type, 0, fsid);
|
||||
ret = fsnotify_add_mark_locked(mark, connp, obj_type, 0, fsid);
|
||||
if (ret) {
|
||||
fsnotify_put_mark(mark);
|
||||
goto out_dec_ucounts;
|
||||
@ -1105,7 +1146,7 @@ static int fanotify_group_init_error_pool(struct fsnotify_group *group)
|
||||
}
|
||||
|
||||
static int fanotify_add_mark(struct fsnotify_group *group,
|
||||
fsnotify_connp_t *connp, unsigned int type,
|
||||
fsnotify_connp_t *connp, unsigned int obj_type,
|
||||
__u32 mask, unsigned int flags,
|
||||
__kernel_fsid_t *fsid)
|
||||
{
|
||||
@ -1116,7 +1157,7 @@ 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, type, fsid);
|
||||
fsn_mark = fanotify_add_new_mark(group, connp, obj_type, fsid);
|
||||
if (IS_ERR(fsn_mark)) {
|
||||
mutex_unlock(&group->mark_mutex);
|
||||
return PTR_ERR(fsn_mark);
|
||||
@ -1275,6 +1316,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;
|
||||
@ -1536,6 +1586,14 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
|
||||
(!fid_mode || mark_type == FAN_MARK_MOUNT))
|
||||
goto fput_and_out;
|
||||
|
||||
/*
|
||||
* FAN_RENAME uses special info type records to report the old and
|
||||
* new parent+name. Reporting only old and new parent id is less
|
||||
* useful and was not implemented.
|
||||
*/
|
||||
if (mask & FAN_RENAME && !(fid_mode & FAN_REPORT_NAME))
|
||||
goto fput_and_out;
|
||||
|
||||
if (flags & FAN_MARK_FLUSH) {
|
||||
ret = 0;
|
||||
if (mark_type == FAN_MARK_MOUNT)
|
||||
@ -1667,7 +1725,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,
|
||||
|
@ -279,6 +279,18 @@ static int fsnotify_handle_event(struct fsnotify_group *group, __u32 mask,
|
||||
WARN_ON_ONCE(fsnotify_iter_vfsmount_mark(iter_info)))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* For FS_RENAME, 'dir' is old dir and 'data' is new dentry.
|
||||
* The only ->handle_inode_event() backend that supports FS_RENAME is
|
||||
* dnotify, where it means file was renamed within same parent.
|
||||
*/
|
||||
if (mask & FS_RENAME) {
|
||||
struct dentry *moved = fsnotify_data_dentry(data, data_type);
|
||||
|
||||
if (dir != moved->d_parent->d_inode)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (parent_mark) {
|
||||
/*
|
||||
* parent_mark indicates that the parent inode is watching
|
||||
@ -330,7 +342,7 @@ static int send_to_group(__u32 mask, const void *data, int data_type,
|
||||
|
||||
/* clear ignored on inode modification */
|
||||
if (mask & FS_MODIFY) {
|
||||
fsnotify_foreach_obj_type(type) {
|
||||
fsnotify_foreach_iter_type(type) {
|
||||
if (!fsnotify_iter_should_report_type(iter_info, type))
|
||||
continue;
|
||||
mark = iter_info->marks[type];
|
||||
@ -340,7 +352,7 @@ static int send_to_group(__u32 mask, const void *data, int data_type,
|
||||
}
|
||||
}
|
||||
|
||||
fsnotify_foreach_obj_type(type) {
|
||||
fsnotify_foreach_iter_type(type) {
|
||||
if (!fsnotify_iter_should_report_type(iter_info, type))
|
||||
continue;
|
||||
mark = iter_info->marks[type];
|
||||
@ -405,7 +417,7 @@ static unsigned int fsnotify_iter_select_report_types(
|
||||
int type;
|
||||
|
||||
/* Choose max prio group among groups of all queue heads */
|
||||
fsnotify_foreach_obj_type(type) {
|
||||
fsnotify_foreach_iter_type(type) {
|
||||
mark = iter_info->marks[type];
|
||||
if (mark &&
|
||||
fsnotify_compare_groups(max_prio_group, mark->group) > 0)
|
||||
@ -417,7 +429,7 @@ static unsigned int fsnotify_iter_select_report_types(
|
||||
|
||||
/* Set the report mask for marks from same group as max prio group */
|
||||
iter_info->report_mask = 0;
|
||||
fsnotify_foreach_obj_type(type) {
|
||||
fsnotify_foreach_iter_type(type) {
|
||||
mark = iter_info->marks[type];
|
||||
if (mark &&
|
||||
fsnotify_compare_groups(max_prio_group, mark->group) == 0)
|
||||
@ -435,7 +447,7 @@ static void fsnotify_iter_next(struct fsnotify_iter_info *iter_info)
|
||||
{
|
||||
int type;
|
||||
|
||||
fsnotify_foreach_obj_type(type) {
|
||||
fsnotify_foreach_iter_type(type) {
|
||||
if (fsnotify_iter_should_report_type(iter_info, type))
|
||||
iter_info->marks[type] =
|
||||
fsnotify_next_mark(iter_info->marks[type]);
|
||||
@ -469,7 +481,9 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir,
|
||||
struct super_block *sb = fsnotify_data_sb(data, data_type);
|
||||
struct fsnotify_iter_info iter_info = {};
|
||||
struct mount *mnt = NULL;
|
||||
struct inode *parent = NULL;
|
||||
struct inode *inode2 = NULL;
|
||||
struct dentry *moved;
|
||||
int inode2_type;
|
||||
int ret = 0;
|
||||
__u32 test_mask, marks_mask;
|
||||
|
||||
@ -479,12 +493,19 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir,
|
||||
if (!inode) {
|
||||
/* Dirent event - report on TYPE_INODE to dir */
|
||||
inode = dir;
|
||||
/* For FS_RENAME, inode is old_dir and inode2 is new_dir */
|
||||
if (mask & FS_RENAME) {
|
||||
moved = fsnotify_data_dentry(data, data_type);
|
||||
inode2 = moved->d_parent->d_inode;
|
||||
inode2_type = FSNOTIFY_ITER_TYPE_INODE2;
|
||||
}
|
||||
} else if (mask & FS_EVENT_ON_CHILD) {
|
||||
/*
|
||||
* Event on child - report on TYPE_PARENT to dir if it is
|
||||
* watching children and on TYPE_INODE to child.
|
||||
*/
|
||||
parent = dir;
|
||||
inode2 = dir;
|
||||
inode2_type = FSNOTIFY_ITER_TYPE_PARENT;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -497,7 +518,7 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir,
|
||||
if (!sb->s_fsnotify_marks &&
|
||||
(!mnt || !mnt->mnt_fsnotify_marks) &&
|
||||
(!inode || !inode->i_fsnotify_marks) &&
|
||||
(!parent || !parent->i_fsnotify_marks))
|
||||
(!inode2 || !inode2->i_fsnotify_marks))
|
||||
return 0;
|
||||
|
||||
marks_mask = sb->s_fsnotify_mask;
|
||||
@ -505,8 +526,8 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir,
|
||||
marks_mask |= mnt->mnt_fsnotify_mask;
|
||||
if (inode)
|
||||
marks_mask |= inode->i_fsnotify_mask;
|
||||
if (parent)
|
||||
marks_mask |= parent->i_fsnotify_mask;
|
||||
if (inode2)
|
||||
marks_mask |= inode2->i_fsnotify_mask;
|
||||
|
||||
|
||||
/*
|
||||
@ -519,19 +540,19 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir,
|
||||
|
||||
iter_info.srcu_idx = srcu_read_lock(&fsnotify_mark_srcu);
|
||||
|
||||
iter_info.marks[FSNOTIFY_OBJ_TYPE_SB] =
|
||||
iter_info.marks[FSNOTIFY_ITER_TYPE_SB] =
|
||||
fsnotify_first_mark(&sb->s_fsnotify_marks);
|
||||
if (mnt) {
|
||||
iter_info.marks[FSNOTIFY_OBJ_TYPE_VFSMOUNT] =
|
||||
iter_info.marks[FSNOTIFY_ITER_TYPE_VFSMOUNT] =
|
||||
fsnotify_first_mark(&mnt->mnt_fsnotify_marks);
|
||||
}
|
||||
if (inode) {
|
||||
iter_info.marks[FSNOTIFY_OBJ_TYPE_INODE] =
|
||||
iter_info.marks[FSNOTIFY_ITER_TYPE_INODE] =
|
||||
fsnotify_first_mark(&inode->i_fsnotify_marks);
|
||||
}
|
||||
if (parent) {
|
||||
iter_info.marks[FSNOTIFY_OBJ_TYPE_PARENT] =
|
||||
fsnotify_first_mark(&parent->i_fsnotify_marks);
|
||||
if (inode2) {
|
||||
iter_info.marks[inode2_type] =
|
||||
fsnotify_first_mark(&inode2->i_fsnotify_marks);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -58,7 +58,7 @@ void fsnotify_destroy_group(struct fsnotify_group *group)
|
||||
fsnotify_group_stop_queueing(group);
|
||||
|
||||
/* Clear all marks for this group and queue them for destruction */
|
||||
fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_ALL_TYPES_MASK);
|
||||
fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_TYPE_ANY);
|
||||
|
||||
/*
|
||||
* Some marks can still be pinned when waiting for response from
|
||||
|
@ -353,7 +353,7 @@ bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info)
|
||||
{
|
||||
int type;
|
||||
|
||||
fsnotify_foreach_obj_type(type) {
|
||||
fsnotify_foreach_iter_type(type) {
|
||||
/* This can fail if mark is being removed */
|
||||
if (!fsnotify_get_mark_safe(iter_info->marks[type])) {
|
||||
__release(&fsnotify_mark_srcu);
|
||||
@ -382,7 +382,7 @@ void fsnotify_finish_user_wait(struct fsnotify_iter_info *iter_info)
|
||||
int type;
|
||||
|
||||
iter_info->srcu_idx = srcu_read_lock(&fsnotify_mark_srcu);
|
||||
fsnotify_foreach_obj_type(type)
|
||||
fsnotify_foreach_iter_type(type)
|
||||
fsnotify_put_mark_wake(iter_info->marks[type]);
|
||||
}
|
||||
|
||||
@ -496,7 +496,7 @@ int fsnotify_compare_groups(struct fsnotify_group *a, struct fsnotify_group *b)
|
||||
}
|
||||
|
||||
static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp,
|
||||
unsigned int type,
|
||||
unsigned int obj_type,
|
||||
__kernel_fsid_t *fsid)
|
||||
{
|
||||
struct inode *inode = NULL;
|
||||
@ -507,7 +507,7 @@ static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp,
|
||||
return -ENOMEM;
|
||||
spin_lock_init(&conn->lock);
|
||||
INIT_HLIST_HEAD(&conn->list);
|
||||
conn->type = type;
|
||||
conn->type = obj_type;
|
||||
conn->obj = connp;
|
||||
/* Cache fsid of filesystem containing the object */
|
||||
if (fsid) {
|
||||
@ -572,7 +572,8 @@ out:
|
||||
* priority, highest number first, and then by the group's location in memory.
|
||||
*/
|
||||
static int fsnotify_add_mark_list(struct fsnotify_mark *mark,
|
||||
fsnotify_connp_t *connp, unsigned int type,
|
||||
fsnotify_connp_t *connp,
|
||||
unsigned int obj_type,
|
||||
int allow_dups, __kernel_fsid_t *fsid)
|
||||
{
|
||||
struct fsnotify_mark *lmark, *last = NULL;
|
||||
@ -580,7 +581,7 @@ static int fsnotify_add_mark_list(struct fsnotify_mark *mark,
|
||||
int cmp;
|
||||
int err = 0;
|
||||
|
||||
if (WARN_ON(!fsnotify_valid_obj_type(type)))
|
||||
if (WARN_ON(!fsnotify_valid_obj_type(obj_type)))
|
||||
return -EINVAL;
|
||||
|
||||
/* Backend is expected to check for zero fsid (e.g. tmpfs) */
|
||||
@ -592,7 +593,8 @@ restart:
|
||||
conn = fsnotify_grab_connector(connp);
|
||||
if (!conn) {
|
||||
spin_unlock(&mark->lock);
|
||||
err = fsnotify_attach_connector_to_object(connp, type, fsid);
|
||||
err = fsnotify_attach_connector_to_object(connp, obj_type,
|
||||
fsid);
|
||||
if (err)
|
||||
return err;
|
||||
goto restart;
|
||||
@ -665,7 +667,7 @@ out_err:
|
||||
* event types should be delivered to which group.
|
||||
*/
|
||||
int fsnotify_add_mark_locked(struct fsnotify_mark *mark,
|
||||
fsnotify_connp_t *connp, unsigned int type,
|
||||
fsnotify_connp_t *connp, unsigned int obj_type,
|
||||
int allow_dups, __kernel_fsid_t *fsid)
|
||||
{
|
||||
struct fsnotify_group *group = mark->group;
|
||||
@ -686,7 +688,7 @@ int fsnotify_add_mark_locked(struct fsnotify_mark *mark,
|
||||
fsnotify_get_mark(mark); /* for g_list */
|
||||
spin_unlock(&mark->lock);
|
||||
|
||||
ret = fsnotify_add_mark_list(mark, connp, type, allow_dups, fsid);
|
||||
ret = fsnotify_add_mark_list(mark, connp, obj_type, allow_dups, fsid);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
@ -706,13 +708,14 @@ err:
|
||||
}
|
||||
|
||||
int fsnotify_add_mark(struct fsnotify_mark *mark, fsnotify_connp_t *connp,
|
||||
unsigned int type, int allow_dups, __kernel_fsid_t *fsid)
|
||||
unsigned int obj_type, int allow_dups,
|
||||
__kernel_fsid_t *fsid)
|
||||
{
|
||||
int ret;
|
||||
struct fsnotify_group *group = mark->group;
|
||||
|
||||
mutex_lock(&group->mark_mutex);
|
||||
ret = fsnotify_add_mark_locked(mark, connp, type, allow_dups, fsid);
|
||||
ret = fsnotify_add_mark_locked(mark, connp, obj_type, allow_dups, fsid);
|
||||
mutex_unlock(&group->mark_mutex);
|
||||
return ret;
|
||||
}
|
||||
@ -747,14 +750,14 @@ EXPORT_SYMBOL_GPL(fsnotify_find_mark);
|
||||
|
||||
/* Clear any marks in a group with given type mask */
|
||||
void fsnotify_clear_marks_by_group(struct fsnotify_group *group,
|
||||
unsigned int type_mask)
|
||||
unsigned int obj_type)
|
||||
{
|
||||
struct fsnotify_mark *lmark, *mark;
|
||||
LIST_HEAD(to_free);
|
||||
struct list_head *head = &to_free;
|
||||
|
||||
/* Skip selection step if we want to clear all marks. */
|
||||
if (type_mask == FSNOTIFY_OBJ_ALL_TYPES_MASK) {
|
||||
if (obj_type == FSNOTIFY_OBJ_TYPE_ANY) {
|
||||
head = &group->marks_list;
|
||||
goto clear;
|
||||
}
|
||||
@ -769,7 +772,7 @@ void fsnotify_clear_marks_by_group(struct fsnotify_group *group,
|
||||
*/
|
||||
mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING);
|
||||
list_for_each_entry_safe(mark, lmark, &group->marks_list, g_list) {
|
||||
if ((1U << mark->connector->type) & type_mask)
|
||||
if (mark->connector->type == obj_type)
|
||||
list_move(&mark->g_list, &to_free);
|
||||
}
|
||||
mutex_unlock(&group->mark_mutex);
|
||||
|
@ -26,7 +26,7 @@ struct dnotify_struct {
|
||||
FS_MODIFY | FS_MODIFY_CHILD |\
|
||||
FS_ACCESS | FS_ACCESS_CHILD |\
|
||||
FS_ATTRIB | FS_ATTRIB_CHILD |\
|
||||
FS_CREATE | FS_DN_RENAME |\
|
||||
FS_CREATE | FS_RENAME |\
|
||||
FS_MOVED_FROM | FS_MOVED_TO)
|
||||
|
||||
extern int dir_notify_enable;
|
||||
|
@ -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)
|
||||
|
||||
@ -82,7 +82,8 @@ extern struct ctl_table fanotify_table[]; /* for sysctl */
|
||||
* Directory entry modification events - reported only to directory
|
||||
* where entry is modified and not to a watching parent.
|
||||
*/
|
||||
#define FANOTIFY_DIRENT_EVENTS (FAN_MOVE | FAN_CREATE | FAN_DELETE)
|
||||
#define FANOTIFY_DIRENT_EVENTS (FAN_MOVE | FAN_CREATE | FAN_DELETE | \
|
||||
FAN_RENAME)
|
||||
|
||||
/* Events that can be reported with event->fd */
|
||||
#define FANOTIFY_FD_EVENTS (FANOTIFY_PATH_EVENTS | FANOTIFY_PERM_EVENTS)
|
||||
|
@ -144,16 +144,19 @@ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
|
||||
u32 fs_cookie = fsnotify_get_cookie();
|
||||
__u32 old_dir_mask = FS_MOVED_FROM;
|
||||
__u32 new_dir_mask = FS_MOVED_TO;
|
||||
__u32 rename_mask = FS_RENAME;
|
||||
const struct qstr *new_name = &moved->d_name;
|
||||
|
||||
if (old_dir == new_dir)
|
||||
old_dir_mask |= FS_DN_RENAME;
|
||||
|
||||
if (isdir) {
|
||||
old_dir_mask |= FS_ISDIR;
|
||||
new_dir_mask |= FS_ISDIR;
|
||||
rename_mask |= FS_ISDIR;
|
||||
}
|
||||
|
||||
/* Event with information about both old and new parent+name */
|
||||
fsnotify_name(rename_mask, moved, FSNOTIFY_EVENT_DENTRY,
|
||||
old_dir, old_name, 0);
|
||||
|
||||
fsnotify_name(old_dir_mask, source, FSNOTIFY_EVENT_INODE,
|
||||
old_dir, old_name, fs_cookie);
|
||||
fsnotify_name(new_dir_mask, source, FSNOTIFY_EVENT_INODE,
|
||||
|
@ -63,7 +63,7 @@
|
||||
*/
|
||||
#define FS_EVENT_ON_CHILD 0x08000000
|
||||
|
||||
#define FS_DN_RENAME 0x10000000 /* file renamed */
|
||||
#define FS_RENAME 0x10000000 /* File was renamed */
|
||||
#define FS_DN_MULTISHOT 0x20000000 /* dnotify multishot */
|
||||
#define FS_ISDIR 0x40000000 /* event occurred against dir */
|
||||
#define FS_IN_ONESHOT 0x80000000 /* only send event once */
|
||||
@ -76,7 +76,7 @@
|
||||
* The watching parent may get an FS_ATTRIB|FS_EVENT_ON_CHILD event
|
||||
* when a directory entry inside a child subdir changes.
|
||||
*/
|
||||
#define ALL_FSNOTIFY_DIRENT_EVENTS (FS_CREATE | FS_DELETE | FS_MOVE)
|
||||
#define ALL_FSNOTIFY_DIRENT_EVENTS (FS_CREATE | FS_DELETE | FS_MOVE | FS_RENAME)
|
||||
|
||||
#define ALL_FSNOTIFY_PERM_EVENTS (FS_OPEN_PERM | FS_ACCESS_PERM | \
|
||||
FS_OPEN_EXEC_PERM)
|
||||
@ -101,7 +101,7 @@
|
||||
/* Events that can be reported to backends */
|
||||
#define ALL_FSNOTIFY_EVENTS (ALL_FSNOTIFY_DIRENT_EVENTS | \
|
||||
FS_EVENTS_POSS_ON_CHILD | \
|
||||
FS_DELETE_SELF | FS_MOVE_SELF | FS_DN_RENAME | \
|
||||
FS_DELETE_SELF | FS_MOVE_SELF | \
|
||||
FS_UNMOUNT | FS_Q_OVERFLOW | FS_IN_IGNORED | \
|
||||
FS_ERROR)
|
||||
|
||||
@ -337,58 +337,69 @@ static inline struct fs_error_report *fsnotify_data_error_report(
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Index to merged marks iterator array that correlates to a type of watch.
|
||||
* The type of watched object can be deduced from the iterator type, but not
|
||||
* the other way around, because an event can match different watched objects
|
||||
* of the same object type.
|
||||
* For example, both parent and child are watching an object of type inode.
|
||||
*/
|
||||
enum fsnotify_iter_type {
|
||||
FSNOTIFY_ITER_TYPE_INODE,
|
||||
FSNOTIFY_ITER_TYPE_VFSMOUNT,
|
||||
FSNOTIFY_ITER_TYPE_SB,
|
||||
FSNOTIFY_ITER_TYPE_PARENT,
|
||||
FSNOTIFY_ITER_TYPE_INODE2,
|
||||
FSNOTIFY_ITER_TYPE_COUNT
|
||||
};
|
||||
|
||||
/* The type of object that a mark is attached to */
|
||||
enum fsnotify_obj_type {
|
||||
FSNOTIFY_OBJ_TYPE_ANY = -1,
|
||||
FSNOTIFY_OBJ_TYPE_INODE,
|
||||
FSNOTIFY_OBJ_TYPE_PARENT,
|
||||
FSNOTIFY_OBJ_TYPE_VFSMOUNT,
|
||||
FSNOTIFY_OBJ_TYPE_SB,
|
||||
FSNOTIFY_OBJ_TYPE_COUNT,
|
||||
FSNOTIFY_OBJ_TYPE_DETACHED = FSNOTIFY_OBJ_TYPE_COUNT
|
||||
};
|
||||
|
||||
#define FSNOTIFY_OBJ_TYPE_INODE_FL (1U << FSNOTIFY_OBJ_TYPE_INODE)
|
||||
#define FSNOTIFY_OBJ_TYPE_PARENT_FL (1U << FSNOTIFY_OBJ_TYPE_PARENT)
|
||||
#define FSNOTIFY_OBJ_TYPE_VFSMOUNT_FL (1U << FSNOTIFY_OBJ_TYPE_VFSMOUNT)
|
||||
#define FSNOTIFY_OBJ_TYPE_SB_FL (1U << FSNOTIFY_OBJ_TYPE_SB)
|
||||
#define FSNOTIFY_OBJ_ALL_TYPES_MASK ((1U << FSNOTIFY_OBJ_TYPE_COUNT) - 1)
|
||||
|
||||
static inline bool fsnotify_valid_obj_type(unsigned int type)
|
||||
static inline bool fsnotify_valid_obj_type(unsigned int obj_type)
|
||||
{
|
||||
return (type < FSNOTIFY_OBJ_TYPE_COUNT);
|
||||
return (obj_type < FSNOTIFY_OBJ_TYPE_COUNT);
|
||||
}
|
||||
|
||||
struct fsnotify_iter_info {
|
||||
struct fsnotify_mark *marks[FSNOTIFY_OBJ_TYPE_COUNT];
|
||||
struct fsnotify_mark *marks[FSNOTIFY_ITER_TYPE_COUNT];
|
||||
unsigned int report_mask;
|
||||
int srcu_idx;
|
||||
};
|
||||
|
||||
static inline bool fsnotify_iter_should_report_type(
|
||||
struct fsnotify_iter_info *iter_info, int type)
|
||||
struct fsnotify_iter_info *iter_info, int iter_type)
|
||||
{
|
||||
return (iter_info->report_mask & (1U << type));
|
||||
return (iter_info->report_mask & (1U << iter_type));
|
||||
}
|
||||
|
||||
static inline void fsnotify_iter_set_report_type(
|
||||
struct fsnotify_iter_info *iter_info, int type)
|
||||
struct fsnotify_iter_info *iter_info, int iter_type)
|
||||
{
|
||||
iter_info->report_mask |= (1U << type);
|
||||
iter_info->report_mask |= (1U << iter_type);
|
||||
}
|
||||
|
||||
static inline void fsnotify_iter_set_report_type_mark(
|
||||
struct fsnotify_iter_info *iter_info, int type,
|
||||
struct fsnotify_iter_info *iter_info, int iter_type,
|
||||
struct fsnotify_mark *mark)
|
||||
{
|
||||
iter_info->marks[type] = mark;
|
||||
iter_info->report_mask |= (1U << type);
|
||||
iter_info->marks[iter_type] = mark;
|
||||
iter_info->report_mask |= (1U << iter_type);
|
||||
}
|
||||
|
||||
#define FSNOTIFY_ITER_FUNCS(name, NAME) \
|
||||
static inline struct fsnotify_mark *fsnotify_iter_##name##_mark( \
|
||||
struct fsnotify_iter_info *iter_info) \
|
||||
{ \
|
||||
return (iter_info->report_mask & FSNOTIFY_OBJ_TYPE_##NAME##_FL) ? \
|
||||
iter_info->marks[FSNOTIFY_OBJ_TYPE_##NAME] : NULL; \
|
||||
return (iter_info->report_mask & (1U << FSNOTIFY_ITER_TYPE_##NAME)) ? \
|
||||
iter_info->marks[FSNOTIFY_ITER_TYPE_##NAME] : NULL; \
|
||||
}
|
||||
|
||||
FSNOTIFY_ITER_FUNCS(inode, INODE)
|
||||
@ -396,8 +407,8 @@ FSNOTIFY_ITER_FUNCS(parent, PARENT)
|
||||
FSNOTIFY_ITER_FUNCS(vfsmount, VFSMOUNT)
|
||||
FSNOTIFY_ITER_FUNCS(sb, SB)
|
||||
|
||||
#define fsnotify_foreach_obj_type(type) \
|
||||
for (type = 0; type < FSNOTIFY_OBJ_TYPE_COUNT; type++)
|
||||
#define fsnotify_foreach_iter_type(type) \
|
||||
for (type = 0; type < FSNOTIFY_ITER_TYPE_COUNT; type++)
|
||||
|
||||
/*
|
||||
* fsnotify_connp_t is what we embed in objects which connector can be attached
|
||||
@ -604,11 +615,11 @@ extern int fsnotify_get_conn_fsid(const struct fsnotify_mark_connector *conn,
|
||||
__kernel_fsid_t *fsid);
|
||||
/* attach the mark to the object */
|
||||
extern int fsnotify_add_mark(struct fsnotify_mark *mark,
|
||||
fsnotify_connp_t *connp, unsigned int type,
|
||||
fsnotify_connp_t *connp, unsigned int obj_type,
|
||||
int allow_dups, __kernel_fsid_t *fsid);
|
||||
extern int fsnotify_add_mark_locked(struct fsnotify_mark *mark,
|
||||
fsnotify_connp_t *connp,
|
||||
unsigned int type, int allow_dups,
|
||||
unsigned int obj_type, int allow_dups,
|
||||
__kernel_fsid_t *fsid);
|
||||
|
||||
/* attach the mark to the inode */
|
||||
@ -637,22 +648,23 @@ extern void fsnotify_detach_mark(struct fsnotify_mark *mark);
|
||||
extern void fsnotify_free_mark(struct fsnotify_mark *mark);
|
||||
/* Wait until all marks queued for destruction are destroyed */
|
||||
extern void fsnotify_wait_marks_destroyed(void);
|
||||
/* run all the marks in a group, and clear all of the marks attached to given object type */
|
||||
extern void fsnotify_clear_marks_by_group(struct fsnotify_group *group, unsigned int type);
|
||||
/* Clear all of the marks of a group attached to a given object type */
|
||||
extern void fsnotify_clear_marks_by_group(struct fsnotify_group *group,
|
||||
unsigned int obj_type);
|
||||
/* run all the marks in a group, and clear all of the vfsmount marks */
|
||||
static inline void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group)
|
||||
{
|
||||
fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_TYPE_VFSMOUNT_FL);
|
||||
fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_TYPE_VFSMOUNT);
|
||||
}
|
||||
/* run all the marks in a group, and clear all of the inode marks */
|
||||
static inline void fsnotify_clear_inode_marks_by_group(struct fsnotify_group *group)
|
||||
{
|
||||
fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_TYPE_INODE_FL);
|
||||
fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_TYPE_INODE);
|
||||
}
|
||||
/* run all the marks in a group, and clear all of the sn marks */
|
||||
static inline void fsnotify_clear_sb_marks_by_group(struct fsnotify_group *group)
|
||||
{
|
||||
fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_TYPE_SB_FL);
|
||||
fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_TYPE_SB);
|
||||
}
|
||||
extern void fsnotify_get_mark(struct fsnotify_mark *mark);
|
||||
extern void fsnotify_put_mark(struct fsnotify_mark *mark);
|
||||
|
@ -28,6 +28,8 @@
|
||||
|
||||
#define FAN_EVENT_ON_CHILD 0x08000000 /* Interested in child events */
|
||||
|
||||
#define FAN_RENAME 0x10000000 /* File was renamed */
|
||||
|
||||
#define FAN_ONDIR 0x40000000 /* Event occurred against dir */
|
||||
|
||||
/* helper events */
|
||||
@ -57,9 +59,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 | \
|
||||
@ -128,6 +134,12 @@ struct fanotify_event_metadata {
|
||||
#define FAN_EVENT_INFO_TYPE_PIDFD 4
|
||||
#define FAN_EVENT_INFO_TYPE_ERROR 5
|
||||
|
||||
/* Special info types for FAN_RENAME */
|
||||
#define FAN_EVENT_INFO_TYPE_OLD_DFID_NAME 10
|
||||
/* Reserved for FAN_EVENT_INFO_TYPE_OLD_DFID 11 */
|
||||
#define FAN_EVENT_INFO_TYPE_NEW_DFID_NAME 12
|
||||
/* Reserved for FAN_EVENT_INFO_TYPE_NEW_DFID 13 */
|
||||
|
||||
/* Variable length info record following event metadata */
|
||||
struct fanotify_event_info_header {
|
||||
__u8 info_type;
|
||||
|
Loading…
Reference in New Issue
Block a user