Commit a8988507 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull fsnotify updates from Jan Kara:
 "A few fsnotify improvements and cleanups"

* tag 'fsnotify_for_v5.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs:
  fsnotify: remove redundant parameter judgment
  fsnotify: optimize FS_MODIFY events with no ignored masks
  fsnotify: fix merge with parent's ignored mask
parents cb7cbaae f92ca72b
...@@ -1003,17 +1003,18 @@ static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark, ...@@ -1003,17 +1003,18 @@ static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark,
__u32 mask, unsigned int flags, __u32 mask, unsigned int flags,
__u32 umask, int *destroy) __u32 umask, int *destroy)
{ {
__u32 oldmask = 0; __u32 oldmask, newmask;
/* umask bits cannot be removed by user */ /* umask bits cannot be removed by user */
mask &= ~umask; mask &= ~umask;
spin_lock(&fsn_mark->lock); spin_lock(&fsn_mark->lock);
oldmask = fsnotify_calc_mask(fsn_mark);
if (!(flags & FAN_MARK_IGNORED_MASK)) { if (!(flags & FAN_MARK_IGNORED_MASK)) {
oldmask = fsn_mark->mask;
fsn_mark->mask &= ~mask; fsn_mark->mask &= ~mask;
} else { } else {
fsn_mark->ignored_mask &= ~mask; fsn_mark->ignored_mask &= ~mask;
} }
newmask = fsnotify_calc_mask(fsn_mark);
/* /*
* We need to keep the mark around even if remaining mask cannot * We need to keep the mark around even if remaining mask cannot
* result in any events (e.g. mask == FAN_ONDIR) to support incremenal * result in any events (e.g. mask == FAN_ONDIR) to support incremenal
...@@ -1023,7 +1024,7 @@ static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark, ...@@ -1023,7 +1024,7 @@ static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark,
*destroy = !((fsn_mark->mask | fsn_mark->ignored_mask) & ~umask); *destroy = !((fsn_mark->mask | fsn_mark->ignored_mask) & ~umask);
spin_unlock(&fsn_mark->lock); spin_unlock(&fsn_mark->lock);
return mask & oldmask; return oldmask & ~newmask;
} }
static int fanotify_remove_mark(struct fsnotify_group *group, static int fanotify_remove_mark(struct fsnotify_group *group,
...@@ -1080,24 +1081,42 @@ static int fanotify_remove_inode_mark(struct fsnotify_group *group, ...@@ -1080,24 +1081,42 @@ static int fanotify_remove_inode_mark(struct fsnotify_group *group,
flags, umask); flags, umask);
} }
static void fanotify_mark_add_ignored_mask(struct fsnotify_mark *fsn_mark,
__u32 mask, unsigned int flags,
__u32 *removed)
{
fsn_mark->ignored_mask |= mask;
/*
* Setting FAN_MARK_IGNORED_SURV_MODIFY for the first time may lead to
* the removal of the FS_MODIFY bit in calculated mask if it was set
* because of an ignored mask that is now going to survive FS_MODIFY.
*/
if ((flags & FAN_MARK_IGNORED_SURV_MODIFY) &&
!(fsn_mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)) {
fsn_mark->flags |= FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY;
if (!(fsn_mark->mask & FS_MODIFY))
*removed = FS_MODIFY;
}
}
static __u32 fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark, static __u32 fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark,
__u32 mask, __u32 mask, unsigned int flags,
unsigned int flags) __u32 *removed)
{ {
__u32 oldmask = -1; __u32 oldmask, newmask;
spin_lock(&fsn_mark->lock); spin_lock(&fsn_mark->lock);
oldmask = fsnotify_calc_mask(fsn_mark);
if (!(flags & FAN_MARK_IGNORED_MASK)) { if (!(flags & FAN_MARK_IGNORED_MASK)) {
oldmask = fsn_mark->mask;
fsn_mark->mask |= mask; fsn_mark->mask |= mask;
} else { } else {
fsn_mark->ignored_mask |= mask; fanotify_mark_add_ignored_mask(fsn_mark, mask, flags, removed);
if (flags & FAN_MARK_IGNORED_SURV_MODIFY)
fsn_mark->flags |= FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY;
} }
newmask = fsnotify_calc_mask(fsn_mark);
spin_unlock(&fsn_mark->lock); spin_unlock(&fsn_mark->lock);
return mask & ~oldmask; return newmask & ~oldmask;
} }
static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group, static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group,
...@@ -1155,7 +1174,7 @@ static int fanotify_add_mark(struct fsnotify_group *group, ...@@ -1155,7 +1174,7 @@ static int fanotify_add_mark(struct fsnotify_group *group,
__kernel_fsid_t *fsid) __kernel_fsid_t *fsid)
{ {
struct fsnotify_mark *fsn_mark; struct fsnotify_mark *fsn_mark;
__u32 added; __u32 added, removed = 0;
int ret = 0; int ret = 0;
mutex_lock(&group->mark_mutex); mutex_lock(&group->mark_mutex);
...@@ -1178,8 +1197,8 @@ static int fanotify_add_mark(struct fsnotify_group *group, ...@@ -1178,8 +1197,8 @@ static int fanotify_add_mark(struct fsnotify_group *group,
goto out; goto out;
} }
added = fanotify_mark_add_to_mask(fsn_mark, mask, flags); added = fanotify_mark_add_to_mask(fsn_mark, mask, flags, &removed);
if (added & ~fsnotify_conn_mask(fsn_mark->connector)) if (removed || (added & ~fsnotify_conn_mask(fsn_mark->connector)))
fsnotify_recalc_mask(fsn_mark->connector); fsnotify_recalc_mask(fsn_mark->connector);
out: out:
......
...@@ -70,8 +70,7 @@ static void fsnotify_unmount_inodes(struct super_block *sb) ...@@ -70,8 +70,7 @@ static void fsnotify_unmount_inodes(struct super_block *sb)
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
spin_unlock(&sb->s_inode_list_lock); spin_unlock(&sb->s_inode_list_lock);
if (iput_inode) iput(iput_inode);
iput(iput_inode);
/* for each watch, send FS_UNMOUNT and then remove it */ /* for each watch, send FS_UNMOUNT and then remove it */
fsnotify_inode(inode, FS_UNMOUNT); fsnotify_inode(inode, FS_UNMOUNT);
...@@ -85,8 +84,7 @@ static void fsnotify_unmount_inodes(struct super_block *sb) ...@@ -85,8 +84,7 @@ static void fsnotify_unmount_inodes(struct super_block *sb)
} }
spin_unlock(&sb->s_inode_list_lock); spin_unlock(&sb->s_inode_list_lock);
if (iput_inode) iput(iput_inode);
iput(iput_inode);
} }
void fsnotify_sb_delete(struct super_block *sb) void fsnotify_sb_delete(struct super_block *sb)
...@@ -531,11 +529,13 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir, ...@@ -531,11 +529,13 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir,
/* /*
* if this is a modify event we may need to clear the ignored masks * If this is a modify event we may need to clear some ignored masks.
* otherwise return if none of the marks care about this type of event. * In that case, the object with ignored masks will have the FS_MODIFY
* event in its mask.
* Otherwise, return if none of the marks care about this type of event.
*/ */
test_mask = (mask & ALL_FSNOTIFY_EVENTS); test_mask = (mask & ALL_FSNOTIFY_EVENTS);
if (!(mask & FS_MODIFY) && !(test_mask & marks_mask)) if (!(test_mask & marks_mask))
return 0; return 0;
iter_info.srcu_idx = srcu_read_lock(&fsnotify_mark_srcu); iter_info.srcu_idx = srcu_read_lock(&fsnotify_mark_srcu);
......
...@@ -127,7 +127,7 @@ static void __fsnotify_recalc_mask(struct fsnotify_mark_connector *conn) ...@@ -127,7 +127,7 @@ static void __fsnotify_recalc_mask(struct fsnotify_mark_connector *conn)
return; return;
hlist_for_each_entry(mark, &conn->list, obj_list) { hlist_for_each_entry(mark, &conn->list, obj_list) {
if (mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED) if (mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED)
new_mask |= mark->mask; new_mask |= fsnotify_calc_mask(mark);
} }
*fsnotify_conn_mask_p(conn) = new_mask; *fsnotify_conn_mask_p(conn) = new_mask;
} }
...@@ -692,7 +692,7 @@ int fsnotify_add_mark_locked(struct fsnotify_mark *mark, ...@@ -692,7 +692,7 @@ int fsnotify_add_mark_locked(struct fsnotify_mark *mark,
if (ret) if (ret)
goto err; goto err;
if (mark->mask) if (mark->mask || mark->ignored_mask)
fsnotify_recalc_mask(mark->connector); fsnotify_recalc_mask(mark->connector);
return ret; return ret;
......
...@@ -601,6 +601,25 @@ extern void fsnotify_remove_queued_event(struct fsnotify_group *group, ...@@ -601,6 +601,25 @@ extern void fsnotify_remove_queued_event(struct fsnotify_group *group,
/* functions used to manipulate the marks attached to inodes */ /* functions used to manipulate the marks attached to inodes */
/* Get mask for calculating object interest taking ignored mask into account */
static inline __u32 fsnotify_calc_mask(struct fsnotify_mark *mark)
{
__u32 mask = mark->mask;
if (!mark->ignored_mask)
return mask;
/* Interest in FS_MODIFY may be needed for clearing ignored mask */
if (!(mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY))
mask |= FS_MODIFY;
/*
* If mark is interested in ignoring events on children, the object must
* show interest in those events for fsnotify_parent() to notice it.
*/
return mask | (mark->ignored_mask & ALL_FSNOTIFY_EVENTS);
}
/* Get mask of events for a list of marks */ /* Get mask of events for a list of marks */
extern __u32 fsnotify_conn_mask(struct fsnotify_mark_connector *conn); extern __u32 fsnotify_conn_mask(struct fsnotify_mark_connector *conn);
/* Calculate mask of events for a list of marks */ /* Calculate mask of events for a list of marks */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment