summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2017-03-14 16:11:23 +0100
committerJan Kara <jack@suse.cz>2017-04-10 17:37:35 +0200
commit755b5bc681eb46de7bfaec196f85e30efd95bd9f (patch)
tree1fc0f867ae0e8edf6f672f43ed8f86ab658197f0 /fs
parentfsnotify: Make fsnotify_mark_connector hold inode reference (diff)
downloadlinux-755b5bc681eb46de7bfaec196f85e30efd95bd9f.tar.xz
linux-755b5bc681eb46de7bfaec196f85e30efd95bd9f.zip
fsnotify: Remove indirection from mark list addition
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. Reviewed-by: Miklos Szeredi <mszeredi@redhat.com> Reviewed-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs')
-rw-r--r--fs/notify/fsnotify.h14
-rw-r--r--fs/notify/inode_mark.c25
-rw-r--r--fs/notify/mark.c66
-rw-r--r--fs/notify/vfsmount_mark.c24
4 files changed, 43 insertions, 86 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 8a15c64fbe80..e8c2f829ce65 100644
--- a/fs/notify/mark.c
+++ b/fs/notify/mark.c
@@ -320,12 +320,13 @@ int fsnotify_compare_groups(struct fsnotify_group *a, struct fsnotify_group *b)
static int fsnotify_attach_connector_to_object(
struct fsnotify_mark_connector **connp,
+ spinlock_t *lock,
struct inode *inode,
struct vfsmount *mnt)
{
struct fsnotify_mark_connector *conn;
- conn = kmem_cache_alloc(fsnotify_mark_connector_cachep, GFP_ATOMIC);
+ conn = kmem_cache_alloc(fsnotify_mark_connector_cachep, GFP_KERNEL);
if (!conn)
return -ENOMEM;
INIT_HLIST_HEAD(&conn->list);
@@ -341,7 +342,12 @@ static int fsnotify_attach_connector_to_object(
* lockless_dereference() in fsnotify().
*/
smp_wmb();
- *connp = conn;
+ spin_lock(lock);
+ if (!*connp)
+ *connp = conn;
+ else
+ kmem_cache_free(fsnotify_mark_connector_cachep, conn);
+ spin_unlock(lock);
return 0;
}
@@ -352,20 +358,35 @@ static int fsnotify_attach_connector_to_object(
* 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;
+ 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) {
- err = fsnotify_attach_connector_to_object(connp, inode, mnt);
+ err = fsnotify_attach_connector_to_object(connp, lock,
+ inode, mnt);
if (err)
return err;
}
+ spin_lock(&mark->lock);
+ spin_lock(lock);
conn = *connp;
/* is mark the first mark? */
@@ -380,8 +401,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) {
@@ -395,7 +418,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;
}
/*
@@ -427,22 +453,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;
-}