|
@@ -181,17 +181,20 @@ static void fsnotify_connector_destroy_workfn(struct work_struct *work)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-static struct inode *fsnotify_detach_connector_from_object(
|
|
|
|
- struct fsnotify_mark_connector *conn)
|
|
|
|
|
|
+static void *fsnotify_detach_connector_from_object(
|
|
|
|
+ struct fsnotify_mark_connector *conn,
|
|
|
|
+ unsigned int *type)
|
|
{
|
|
{
|
|
struct inode *inode = NULL;
|
|
struct inode *inode = NULL;
|
|
|
|
|
|
|
|
+ *type = conn->type;
|
|
if (conn->type == FSNOTIFY_OBJ_TYPE_DETACHED)
|
|
if (conn->type == FSNOTIFY_OBJ_TYPE_DETACHED)
|
|
return NULL;
|
|
return NULL;
|
|
|
|
|
|
if (conn->type == FSNOTIFY_OBJ_TYPE_INODE) {
|
|
if (conn->type == FSNOTIFY_OBJ_TYPE_INODE) {
|
|
inode = fsnotify_conn_inode(conn);
|
|
inode = fsnotify_conn_inode(conn);
|
|
inode->i_fsnotify_mask = 0;
|
|
inode->i_fsnotify_mask = 0;
|
|
|
|
+ atomic_long_inc(&inode->i_sb->s_fsnotify_inode_refs);
|
|
} else if (conn->type == FSNOTIFY_OBJ_TYPE_VFSMOUNT) {
|
|
} else if (conn->type == FSNOTIFY_OBJ_TYPE_VFSMOUNT) {
|
|
fsnotify_conn_mount(conn)->mnt_fsnotify_mask = 0;
|
|
fsnotify_conn_mount(conn)->mnt_fsnotify_mask = 0;
|
|
} else if (conn->type == FSNOTIFY_OBJ_TYPE_SB) {
|
|
} else if (conn->type == FSNOTIFY_OBJ_TYPE_SB) {
|
|
@@ -215,10 +218,29 @@ static void fsnotify_final_mark_destroy(struct fsnotify_mark *mark)
|
|
fsnotify_put_group(group);
|
|
fsnotify_put_group(group);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/* Drop object reference originally held by a connector */
|
|
|
|
+static void fsnotify_drop_object(unsigned int type, void *objp)
|
|
|
|
+{
|
|
|
|
+ struct inode *inode;
|
|
|
|
+ struct super_block *sb;
|
|
|
|
+
|
|
|
|
+ if (!objp)
|
|
|
|
+ return;
|
|
|
|
+ /* Currently only inode references are passed to be dropped */
|
|
|
|
+ if (WARN_ON_ONCE(type != FSNOTIFY_OBJ_TYPE_INODE))
|
|
|
|
+ return;
|
|
|
|
+ inode = objp;
|
|
|
|
+ sb = inode->i_sb;
|
|
|
|
+ iput(inode);
|
|
|
|
+ if (atomic_long_dec_and_test(&sb->s_fsnotify_inode_refs))
|
|
|
|
+ wake_up_var(&sb->s_fsnotify_inode_refs);
|
|
|
|
+}
|
|
|
|
+
|
|
void fsnotify_put_mark(struct fsnotify_mark *mark)
|
|
void fsnotify_put_mark(struct fsnotify_mark *mark)
|
|
{
|
|
{
|
|
struct fsnotify_mark_connector *conn;
|
|
struct fsnotify_mark_connector *conn;
|
|
- struct inode *inode = NULL;
|
|
|
|
|
|
+ void *objp = NULL;
|
|
|
|
+ unsigned int type = FSNOTIFY_OBJ_TYPE_DETACHED;
|
|
bool free_conn = false;
|
|
bool free_conn = false;
|
|
|
|
|
|
/* Catch marks that were actually never attached to object */
|
|
/* Catch marks that were actually never attached to object */
|
|
@@ -238,7 +260,7 @@ void fsnotify_put_mark(struct fsnotify_mark *mark)
|
|
conn = mark->connector;
|
|
conn = mark->connector;
|
|
hlist_del_init_rcu(&mark->obj_list);
|
|
hlist_del_init_rcu(&mark->obj_list);
|
|
if (hlist_empty(&conn->list)) {
|
|
if (hlist_empty(&conn->list)) {
|
|
- inode = fsnotify_detach_connector_from_object(conn);
|
|
|
|
|
|
+ objp = fsnotify_detach_connector_from_object(conn, &type);
|
|
free_conn = true;
|
|
free_conn = true;
|
|
} else {
|
|
} else {
|
|
__fsnotify_recalc_mask(conn);
|
|
__fsnotify_recalc_mask(conn);
|
|
@@ -246,7 +268,7 @@ void fsnotify_put_mark(struct fsnotify_mark *mark)
|
|
mark->connector = NULL;
|
|
mark->connector = NULL;
|
|
spin_unlock(&conn->lock);
|
|
spin_unlock(&conn->lock);
|
|
|
|
|
|
- iput(inode);
|
|
|
|
|
|
+ fsnotify_drop_object(type, objp);
|
|
|
|
|
|
if (free_conn) {
|
|
if (free_conn) {
|
|
spin_lock(&destroy_lock);
|
|
spin_lock(&destroy_lock);
|
|
@@ -713,7 +735,8 @@ void fsnotify_destroy_marks(fsnotify_connp_t *connp)
|
|
{
|
|
{
|
|
struct fsnotify_mark_connector *conn;
|
|
struct fsnotify_mark_connector *conn;
|
|
struct fsnotify_mark *mark, *old_mark = NULL;
|
|
struct fsnotify_mark *mark, *old_mark = NULL;
|
|
- struct inode *inode;
|
|
|
|
|
|
+ void *objp;
|
|
|
|
+ unsigned int type;
|
|
|
|
|
|
conn = fsnotify_grab_connector(connp);
|
|
conn = fsnotify_grab_connector(connp);
|
|
if (!conn)
|
|
if (!conn)
|
|
@@ -739,11 +762,11 @@ void fsnotify_destroy_marks(fsnotify_connp_t *connp)
|
|
* mark references get dropped. It would lead to strange results such
|
|
* mark references get dropped. It would lead to strange results such
|
|
* as delaying inode deletion or blocking unmount.
|
|
* as delaying inode deletion or blocking unmount.
|
|
*/
|
|
*/
|
|
- inode = fsnotify_detach_connector_from_object(conn);
|
|
|
|
|
|
+ objp = fsnotify_detach_connector_from_object(conn, &type);
|
|
spin_unlock(&conn->lock);
|
|
spin_unlock(&conn->lock);
|
|
if (old_mark)
|
|
if (old_mark)
|
|
fsnotify_put_mark(old_mark);
|
|
fsnotify_put_mark(old_mark);
|
|
- iput(inode);
|
|
|
|
|
|
+ fsnotify_drop_object(type, objp);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|