Adding notification mark to object list has been currently done through fsnotify_add_{inode|vfsmount}_mark() helpers from fsnotify_add_mark_locked() which call fsnotify_add_mark_list(). Remove this unnecessary indirection to simplify the code. Pushing all the locking to fsnotify_add_mark_list() also allows us to allocate the connector structure with GFP_KERNEL mode. Signed-off-by: Jan Kara <jack@xxxxxxx> --- fs/notify/fsnotify.h | 14 ----------- fs/notify/inode_mark.c | 25 ------------------- fs/notify/mark.c | 63 +++++++++++++++++++++++++++++++---------------- fs/notify/vfsmount_mark.c | 24 ------------------ 4 files changed, 42 insertions(+), 84 deletions(-) diff --git a/fs/notify/fsnotify.h b/fs/notify/fsnotify.h index 1a2aec65ebd8..0354338aad78 100644 --- a/fs/notify/fsnotify.h +++ b/fs/notify/fsnotify.h @@ -21,20 +21,6 @@ extern u32 fsnotify_recalc_mask(struct fsnotify_mark_connector *conn); extern int fsnotify_compare_groups(struct fsnotify_group *a, struct fsnotify_group *b); -/* Add mark to a proper place in mark list */ -extern int fsnotify_add_mark_list(struct fsnotify_mark_connector **connp, - struct fsnotify_mark *mark, - struct inode *inode, struct vfsmount *mnt, - int allow_dups); -/* add a mark to an inode */ -extern int fsnotify_add_inode_mark(struct fsnotify_mark *mark, - struct fsnotify_group *group, struct inode *inode, - int allow_dups); -/* add a mark to a vfsmount */ -extern int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark, - struct fsnotify_group *group, struct vfsmount *mnt, - int allow_dups); - /* vfsmount specific destruction of a mark */ extern void fsnotify_destroy_vfsmount_mark(struct fsnotify_mark *mark); /* inode specific destruction of a mark */ diff --git a/fs/notify/inode_mark.c b/fs/notify/inode_mark.c index c3873b6920e7..87bef7d802db 100644 --- a/fs/notify/inode_mark.c +++ b/fs/notify/inode_mark.c @@ -92,31 +92,6 @@ struct fsnotify_mark *fsnotify_find_inode_mark(struct fsnotify_group *group, return mark; } -/* - * Attach an initialized mark to a given inode. - * These marks may be used for the fsnotify backend to determine which - * event types should be delivered to which group and for which inodes. These - * marks are ordered according to priority, highest number first, and then by - * the group's location in memory. - */ -int fsnotify_add_inode_mark(struct fsnotify_mark *mark, - struct fsnotify_group *group, struct inode *inode, - int allow_dups) -{ - int ret; - - BUG_ON(!mutex_is_locked(&group->mark_mutex)); - assert_spin_locked(&mark->lock); - - spin_lock(&inode->i_lock); - ret = fsnotify_add_mark_list(&inode->i_fsnotify_marks, mark, inode, - NULL, allow_dups); - inode->i_fsnotify_mask = fsnotify_recalc_mask(inode->i_fsnotify_marks); - spin_unlock(&inode->i_lock); - - return ret; -} - /** * fsnotify_unmount_inodes - an sb is unmounting. handle any watched inodes. * @sb: superblock being unmounted. diff --git a/fs/notify/mark.c b/fs/notify/mark.c index 6a1c305038ea..12310d140d58 100644 --- a/fs/notify/mark.c +++ b/fs/notify/mark.c @@ -324,17 +324,30 @@ int fsnotify_compare_groups(struct fsnotify_group *a, struct fsnotify_group *b) * to which group and for which inodes. These marks are ordered according to * priority, highest number first, and then by the group's location in memory. */ -int fsnotify_add_mark_list(struct fsnotify_mark_connector **connp, - struct fsnotify_mark *mark, struct inode *inode, - struct vfsmount *mnt, int allow_dups) +static int fsnotify_add_mark_list(struct fsnotify_mark *mark, + struct inode *inode, struct vfsmount *mnt, + int allow_dups) { struct fsnotify_mark *lmark, *last = NULL; struct fsnotify_mark_connector *conn; + struct fsnotify_mark_connector **connp; + spinlock_t *lock; int cmp; + int err = 0; + + if (WARN_ON(!inode && !mnt)) + return -EINVAL; + if (inode) { + connp = &inode->i_fsnotify_marks; + lock = &inode->i_lock; + } else { + connp = &real_mount(mnt)->mnt_fsnotify_marks; + lock = &mnt->mnt_root->d_lock; + } if (!*connp) { conn = kmem_cache_alloc(fsnotify_mark_connector_cachep, - GFP_ATOMIC); + GFP_KERNEL); if (!conn) return -ENOMEM; INIT_HLIST_HEAD(&conn->list); @@ -350,8 +363,17 @@ int fsnotify_add_mark_list(struct fsnotify_mark_connector **connp, * lockless_dereference() in fsnotify(). */ smp_wmb(); - *connp = conn; + spin_lock(&mark->lock); + spin_lock(lock); + if (!*connp) { + *connp = conn; + } else { + kmem_cache_free(fsnotify_mark_connector_cachep, conn); + conn = *connp; + } } else { + spin_lock(&mark->lock); + spin_lock(lock); conn = *connp; } @@ -367,8 +389,10 @@ int fsnotify_add_mark_list(struct fsnotify_mark_connector **connp, hlist_for_each_entry(lmark, &conn->list, obj_list) { last = lmark; - if ((lmark->group == mark->group) && !allow_dups) - return -EEXIST; + if ((lmark->group == mark->group) && !allow_dups) { + err = -EEXIST; + goto out_err; + } cmp = fsnotify_compare_groups(lmark->group, mark->group); if (cmp >= 0) { @@ -382,7 +406,10 @@ int fsnotify_add_mark_list(struct fsnotify_mark_connector **connp, hlist_add_behind_rcu(&mark->obj_list, &last->obj_list); added: mark->connector = conn; - return 0; +out_err: + spin_unlock(lock); + spin_unlock(&mark->lock); + return err; } /* @@ -414,22 +441,16 @@ int fsnotify_add_mark_locked(struct fsnotify_mark *mark, list_add(&mark->g_list, &group->marks_list); atomic_inc(&group->num_marks); fsnotify_get_mark(mark); /* for i_list and g_list */ - - if (inode) { - ret = fsnotify_add_inode_mark(mark, group, inode, allow_dups); - if (ret) - goto err; - } else if (mnt) { - ret = fsnotify_add_vfsmount_mark(mark, group, mnt, allow_dups); - if (ret) - goto err; - } else { - BUG(); - } spin_unlock(&mark->lock); + ret = fsnotify_add_mark_list(mark, inode, mnt, allow_dups); + if (ret) + goto err; + if (inode) - __fsnotify_update_child_dentry_flags(inode); + fsnotify_recalc_inode_mask(inode); + else + fsnotify_recalc_vfsmount_mask(mnt); return ret; err: diff --git a/fs/notify/vfsmount_mark.c b/fs/notify/vfsmount_mark.c index e04e33ef02d4..49ccbdb74f82 100644 --- a/fs/notify/vfsmount_mark.c +++ b/fs/notify/vfsmount_mark.c @@ -80,27 +80,3 @@ struct fsnotify_mark *fsnotify_find_vfsmount_mark(struct fsnotify_group *group, return mark; } - -/* - * Attach an initialized mark to a given group and vfsmount. - * These marks may be used for the fsnotify backend to determine which - * event types should be delivered to which groups. - */ -int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark, - struct fsnotify_group *group, struct vfsmount *mnt, - int allow_dups) -{ - struct mount *m = real_mount(mnt); - int ret; - - BUG_ON(!mutex_is_locked(&group->mark_mutex)); - assert_spin_locked(&mark->lock); - - spin_lock(&mnt->mnt_root->d_lock); - ret = fsnotify_add_mark_list(&m->mnt_fsnotify_marks, mark, NULL, mnt, - allow_dups); - m->mnt_fsnotify_mask = fsnotify_recalc_mask(m->mnt_fsnotify_marks); - spin_unlock(&mnt->mnt_root->d_lock); - - return ret; -} -- 2.10.2