diff --git a/fs/notify/mark.c b/fs/notify/mark.c index d17628580a57..cb07f42d3422 100644 --- a/fs/notify/mark.c +++ b/fs/notify/mark.c @@ -929,6 +929,11 @@ static int fsnotify_add_mark_list(struct fsnotify_mark *mark, void *obj, goto restart; } + if (conn->flags & FSNOTIFY_CONN_FLAG_DESTROYING) { + err = -ENOENT; + goto out_err; + } + /* is mark the first mark? */ if (hlist_empty(&conn->list)) { hlist_add_head_rcu(&mark->obj_list, &conn->list); @@ -1116,6 +1121,12 @@ void fsnotify_destroy_marks(fsnotify_connp_t *connp) conn = fsnotify_grab_connector(connp); if (!conn) return; + /* + * New marks could be inserted before our cursor and survive the final + * detachment of the connector from the object. Prevent additions to + * this connector before dropping its lock. + */ + conn->flags |= FSNOTIFY_CONN_FLAG_DESTROYING; /* * We have to be careful since we can race with e.g. * fsnotify_clear_marks_by_group() and once we drop the conn->lock, the diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index 618eed4d6d72..a6d5c1a89cff 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -566,6 +566,7 @@ struct fsnotify_mark_connector { unsigned char prio; /* Highest priority group */ #define FSNOTIFY_CONN_FLAG_IS_WATCHED 0x01 #define FSNOTIFY_CONN_FLAG_HAS_IREF 0x02 +#define FSNOTIFY_CONN_FLAG_DESTROYING 0x04 unsigned short flags; /* flags [lock] */ union { /* Object pointer [lock] */