diff options
Diffstat (limited to 'fs/notify/mark.c')
-rw-r--r-- | fs/notify/mark.c | 103 |
1 files changed, 55 insertions, 48 deletions
diff --git a/fs/notify/mark.c b/fs/notify/mark.c index 61f4c5fa34c7..59cdb27826de 100644 --- a/fs/notify/mark.c +++ b/fs/notify/mark.c @@ -109,25 +109,42 @@ 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; struct fsnotify_mark *mark; assert_spin_locked(&conn->lock); + /* We can get detached connector here when inode is getting unlinked. */ + if (!fsnotify_valid_obj_type(conn->type)) + return; hlist_for_each_entry(mark, &conn->list, obj_list) { 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; + *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; |