summaryrefslogtreecommitdiff
path: root/fs/notify/mark.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/notify/mark.c')
-rw-r--r--fs/notify/mark.c103
1 files changed, 55 insertions, 48 deletions
diff --git a/fs/notify/mark.c b/fs/notify/mark.c
index 61f4c5fa34c7..05506d60131c 100644
--- a/fs/notify/mark.c
+++ b/fs/notify/mark.c
@@ -109,6 +109,23 @@ void fsnotify_get_mark(struct fsnotify_mark *mark)
refcount_inc(&mark->refcnt);
}
+static __u32 *fsnotify_conn_mask_p(struct fsnotify_mark_connector *conn)
+{
+ if (conn->type == FSNOTIFY_OBJ_TYPE_INODE)
+ return &fsnotify_conn_inode(conn)->i_fsnotify_mask;
+ else if (conn->type == FSNOTIFY_OBJ_TYPE_VFSMOUNT)
+ return &fsnotify_conn_mount(conn)->mnt_fsnotify_mask;
+ return NULL;
+}
+
+__u32 fsnotify_conn_mask(struct fsnotify_mark_connector *conn)
+{
+ if (WARN_ON(!fsnotify_valid_obj_type(conn->type)))
+ return 0;
+
+ return *fsnotify_conn_mask_p(conn);
+}
+
static void __fsnotify_recalc_mask(struct fsnotify_mark_connector *conn)
{
u32 new_mask = 0;
@@ -119,15 +136,15 @@ static void __fsnotify_recalc_mask(struct fsnotify_mark_connector *conn)
if (mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED)
new_mask |= mark->mask;
}
- if (conn->type == FSNOTIFY_OBJ_TYPE_INODE)
- conn->inode->i_fsnotify_mask = new_mask;
- else if (conn->type == FSNOTIFY_OBJ_TYPE_VFSMOUNT)
- real_mount(conn->mnt)->mnt_fsnotify_mask = new_mask;
+ if (WARN_ON(!fsnotify_valid_obj_type(conn->type)))
+ return;
+
+ *fsnotify_conn_mask_p(conn) = new_mask;
}
/*
* Calculate mask of events for a list of marks. The caller must make sure
- * connector and connector->inode cannot disappear under us. Callers achieve
+ * connector and connector->obj cannot disappear under us. Callers achieve
* this by holding a mark->lock or mark->group->mark_mutex for a mark on this
* list.
*/
@@ -140,7 +157,8 @@ void fsnotify_recalc_mask(struct fsnotify_mark_connector *conn)
__fsnotify_recalc_mask(conn);
spin_unlock(&conn->lock);
if (conn->type == FSNOTIFY_OBJ_TYPE_INODE)
- __fsnotify_update_child_dentry_flags(conn->inode);
+ __fsnotify_update_child_dentry_flags(
+ fsnotify_conn_inode(conn));
}
/* Free all connectors queued for freeing once SRCU period ends */
@@ -166,20 +184,20 @@ static struct inode *fsnotify_detach_connector_from_object(
{
struct inode *inode = NULL;
+ if (conn->type == FSNOTIFY_OBJ_TYPE_DETACHED)
+ return NULL;
+
if (conn->type == FSNOTIFY_OBJ_TYPE_INODE) {
- inode = conn->inode;
- rcu_assign_pointer(inode->i_fsnotify_marks, NULL);
+ inode = fsnotify_conn_inode(conn);
inode->i_fsnotify_mask = 0;
- conn->inode = NULL;
- conn->type = FSNOTIFY_OBJ_TYPE_DETACHED;
} else if (conn->type == FSNOTIFY_OBJ_TYPE_VFSMOUNT) {
- rcu_assign_pointer(real_mount(conn->mnt)->mnt_fsnotify_marks,
- NULL);
- real_mount(conn->mnt)->mnt_fsnotify_mask = 0;
- conn->mnt = NULL;
- conn->type = FSNOTIFY_OBJ_TYPE_DETACHED;
+ fsnotify_conn_mount(conn)->mnt_fsnotify_mask = 0;
}
+ rcu_assign_pointer(*(conn->obj), NULL);
+ conn->obj = NULL;
+ conn->type = FSNOTIFY_OBJ_TYPE_DETACHED;
+
return inode;
}
@@ -436,11 +454,10 @@ int fsnotify_compare_groups(struct fsnotify_group *a, struct fsnotify_group *b)
return -1;
}
-static int fsnotify_attach_connector_to_object(
- struct fsnotify_mark_connector __rcu **connp,
- struct inode *inode,
- struct vfsmount *mnt)
+static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp,
+ unsigned int type)
{
+ struct inode *inode = NULL;
struct fsnotify_mark_connector *conn;
conn = kmem_cache_alloc(fsnotify_mark_connector_cachep, GFP_KERNEL);
@@ -448,13 +465,10 @@ static int fsnotify_attach_connector_to_object(
return -ENOMEM;
spin_lock_init(&conn->lock);
INIT_HLIST_HEAD(&conn->list);
- if (inode) {
- conn->type = FSNOTIFY_OBJ_TYPE_INODE;
- conn->inode = igrab(inode);
- } else {
- conn->type = FSNOTIFY_OBJ_TYPE_VFSMOUNT;
- conn->mnt = mnt;
- }
+ conn->type = type;
+ conn->obj = connp;
+ if (conn->type == FSNOTIFY_OBJ_TYPE_INODE)
+ inode = igrab(fsnotify_conn_inode(conn));
/*
* cmpxchg() provides the barrier so that readers of *connp can see
* only initialized structure
@@ -476,7 +490,7 @@ static int fsnotify_attach_connector_to_object(
* they are sure list cannot go away under them.
*/
static struct fsnotify_mark_connector *fsnotify_grab_connector(
- struct fsnotify_mark_connector __rcu **connp)
+ fsnotify_connp_t *connp)
{
struct fsnotify_mark_connector *conn;
int idx;
@@ -503,27 +517,22 @@ out:
* priority, highest number first, and then by the group's location in memory.
*/
static int fsnotify_add_mark_list(struct fsnotify_mark *mark,
- struct inode *inode, struct vfsmount *mnt,
+ fsnotify_connp_t *connp, unsigned int type,
int allow_dups)
{
struct fsnotify_mark *lmark, *last = NULL;
struct fsnotify_mark_connector *conn;
- struct fsnotify_mark_connector __rcu **connp;
int cmp;
int err = 0;
- if (WARN_ON(!inode && !mnt))
+ if (WARN_ON(!fsnotify_valid_obj_type(type)))
return -EINVAL;
- if (inode)
- connp = &inode->i_fsnotify_marks;
- else
- connp = &real_mount(mnt)->mnt_fsnotify_marks;
restart:
spin_lock(&mark->lock);
conn = fsnotify_grab_connector(connp);
if (!conn) {
spin_unlock(&mark->lock);
- err = fsnotify_attach_connector_to_object(connp, inode, mnt);
+ err = fsnotify_attach_connector_to_object(connp, type);
if (err)
return err;
goto restart;
@@ -569,14 +578,13 @@ out_err:
* These marks may be used for the fsnotify backend to determine which
* event types should be delivered to which group.
*/
-int fsnotify_add_mark_locked(struct fsnotify_mark *mark, struct inode *inode,
- struct vfsmount *mnt, int allow_dups)
+int fsnotify_add_mark_locked(struct fsnotify_mark *mark,
+ fsnotify_connp_t *connp, unsigned int type,
+ int allow_dups)
{
struct fsnotify_group *group = mark->group;
int ret = 0;
- BUG_ON(inode && mnt);
- BUG_ON(!inode && !mnt);
BUG_ON(!mutex_is_locked(&group->mark_mutex));
/*
@@ -593,7 +601,7 @@ int fsnotify_add_mark_locked(struct fsnotify_mark *mark, struct inode *inode,
fsnotify_get_mark(mark); /* for g_list */
spin_unlock(&mark->lock);
- ret = fsnotify_add_mark_list(mark, inode, mnt, allow_dups);
+ ret = fsnotify_add_mark_list(mark, connp, type, allow_dups);
if (ret)
goto err;
@@ -613,14 +621,14 @@ err:
return ret;
}
-int fsnotify_add_mark(struct fsnotify_mark *mark, struct inode *inode,
- struct vfsmount *mnt, int allow_dups)
+int fsnotify_add_mark(struct fsnotify_mark *mark, fsnotify_connp_t *connp,
+ unsigned int type, int allow_dups)
{
int ret;
struct fsnotify_group *group = mark->group;
mutex_lock(&group->mark_mutex);
- ret = fsnotify_add_mark_locked(mark, inode, mnt, allow_dups);
+ ret = fsnotify_add_mark_locked(mark, connp, type, allow_dups);
mutex_unlock(&group->mark_mutex);
return ret;
}
@@ -629,9 +637,8 @@ int fsnotify_add_mark(struct fsnotify_mark *mark, struct inode *inode,
* Given a list of marks, find the mark associated with given group. If found
* take a reference to that mark and return it, else return NULL.
*/
-struct fsnotify_mark *fsnotify_find_mark(
- struct fsnotify_mark_connector __rcu **connp,
- struct fsnotify_group *group)
+struct fsnotify_mark *fsnotify_find_mark(fsnotify_connp_t *connp,
+ struct fsnotify_group *group)
{
struct fsnotify_mark_connector *conn;
struct fsnotify_mark *mark;
@@ -697,8 +704,8 @@ clear:
}
}
-/* Destroy all marks attached to inode / vfsmount */
-void fsnotify_destroy_marks(struct fsnotify_mark_connector __rcu **connp)
+/* Destroy all marks attached to an object via connector */
+void fsnotify_destroy_marks(fsnotify_connp_t *connp)
{
struct fsnotify_mark_connector *conn;
struct fsnotify_mark *mark, *old_mark = NULL;