From: Zizhi Wo wozizhi@huawei.com
Offering: HULK hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IB5UKT
--------------------------------
In the current erofs read on demand scenario, fd will hold a reference to object and object will also hold a reference to cookie. The cookie's reference count is subtracted only when the object reference count is 0. And only when the reference count of the cookie is 0 will the cookie be unhashed, that the next mounted cookie with the same fsid does not report duplicate cookie error.
However, the release of fd depends on the operation of user mode. If the user is abnormal, does not receive the close message or handle the message incorrectly, the reference count of the object will not be released, resulting in the cookie can not be unhashed.
Therefore, this patch adds another unhash cookie mechanism. Do unhash cookies in fscache_drop_object() as well. Because object has been cleared from the linked list of cookies at this time, and object->file has been NULL after calling cachefiles_drop_object(), even if fd is not turned off in user state, it cannot be used to write. The next time a cookie with the same fsid is mounted, there will be no write concurrency issues.
Of course, the unhash_cookie process in the original fscache_cookie_put() can not be deleted because the cookie has been added to the hash table in fscache_hash_cookie(). Note that fscache_alloc_object() may fail to start the object state machine, and the corresponding cookie unhash still needs to be done through its own process.
Signed-off-by: Zizhi Wo wozizhi@huawei.com Signed-off-by: Baokun Li libaokun1@huawei.com --- fs/fscache/cookie.c | 12 ++++++++---- fs/fscache/internal.h | 1 + fs/fscache/object.c | 3 +++ 3 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/fs/fscache/cookie.c b/fs/fscache/cookie.c index 422248fa55ca..c6e6d166cdb1 100644 --- a/fs/fscache/cookie.c +++ b/fs/fscache/cookie.c @@ -882,7 +882,6 @@ void __fscache_relinquish_cookie(struct fscache_cookie *cookie,
/* Clear pointers back to the netfs */ cookie->netfs_data = NULL; - cookie->def = NULL; BUG_ON(!radix_tree_empty(&cookie->stores));
if (cookie->parent) { @@ -902,19 +901,24 @@ EXPORT_SYMBOL(__fscache_relinquish_cookie); /* * Remove a cookie from the hash table. */ -static void fscache_unhash_cookie(struct fscache_cookie *cookie) +void fscache_unhash_cookie(struct fscache_cookie *cookie) { struct hlist_bl_head *h; unsigned int bucket;
+ if (hlist_bl_unhashed(&cookie->hash_link)) + return; + bucket = cookie->key_hash & (ARRAY_SIZE(fscache_cookie_hash) - 1); h = &fscache_cookie_hash[bucket];
hlist_bl_lock(h); - hlist_bl_del(&cookie->hash_link); - if (cookie->collision) + hlist_bl_del_init(&cookie->hash_link); + if (cookie->collision) { clear_and_wake_up_bit(FSCACHE_COOKIE_ACQUIRE_PENDING, &cookie->collision->flags); + cookie->collision = NULL; + } hlist_bl_unlock(h); }
diff --git a/fs/fscache/internal.h b/fs/fscache/internal.h index 64aa552b296d..533c4b4586d8 100644 --- a/fs/fscache/internal.h +++ b/fs/fscache/internal.h @@ -55,6 +55,7 @@ extern struct fscache_cookie *fscache_alloc_cookie(struct fscache_cookie *, extern struct fscache_cookie *fscache_hash_cookie(struct fscache_cookie *); extern void fscache_cookie_put(struct fscache_cookie *, enum fscache_cookie_trace); +extern void fscache_unhash_cookie(struct fscache_cookie *cookie);
/* * fsdef.c diff --git a/fs/fscache/object.c b/fs/fscache/object.c index 0375f448afc4..375b9b34f005 100644 --- a/fs/fscache/object.c +++ b/fs/fscache/object.c @@ -745,6 +745,9 @@ static const struct fscache_state *fscache_drop_object(struct fscache_object *ob cache->ops->drop_object(object); fscache_stat_d(&fscache_n_cop_drop_object);
+ if (volume_new_version(cookie) || data_new_version(cookie)) + fscache_unhash_cookie(cookie); + /* The parent object wants to know when all it dependents have gone */ if (parent) { _debug("release parent OBJ%x {%d}",