From: Zizhi Wo wozizhi@huawei.com
hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IB5UKT
--------------------------------
When an erofs file system is mounted with ondemand mode, if the cache root directory bound to cachefiles named rootdir, the resulting directory structure is seen as follows, where different directories corresponded to the objects of different levels:
rootdir ____|____ | | cache(obj0) graveyard | domain_dir(obj1) | hash_dir | back_data.img(obj2)
In the current logic, if cull is executed on the cache directory, it first determines whether the object corresponding to the directory is the active node of cache. If yes, it cannot be executed. If the fscache_object lookup successfully, it is set to avtive node; and if the lookup fails or the object state machine goes into drop, it is set to inactive.
Currently cachefiles_daemon_cull() can execute on any directory or file which have not been called cachefiles_mark_object_active(), and we want to reduce the scope of this function. On the one hand, the user state needs to add relevant constraints; on the other hand, kernel mode also needs modified. This patch adds the restriction of filesystem-level isolation.
In addition, the top-level cache dir can be culled directly because obj0 is not added as active_node. This causes the entire cache directory to be renamed graveyard, even though the underlying objects are inuse state, and cannot be resolved by mounting it again. Fix it by marking it as active in cachefiles_daemon_add_cache().
Signed-off-by: Zizhi Wo wozizhi@huawei.com Signed-off-by: Baokun Li libaokun1@huawei.com --- fs/cachefiles/bind.c | 6 ++++++ fs/cachefiles/daemon.c | 6 ++++++ fs/cachefiles/internal.h | 2 ++ fs/cachefiles/namei.c | 4 ++-- 4 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/fs/cachefiles/bind.c b/fs/cachefiles/bind.c index 50ac68b0ad81..3a88bef9ed4b 100644 --- a/fs/cachefiles/bind.c +++ b/fs/cachefiles/bind.c @@ -232,6 +232,12 @@ static int cachefiles_daemon_add_cache(struct cachefiles_cache *cache) if (ret < 0) goto error_add_cache;
+ /* + * As the cache->daemon_mutex lock hold and the cache is set to + * CACHEFILES_READY, this function must not return an error. + */ + cachefiles_mark_object_active(cache, fsdef); + /* done */ set_bit(CACHEFILES_READY, &cache->flags); dput(root); diff --git a/fs/cachefiles/daemon.c b/fs/cachefiles/daemon.c index 50433c6024dd..c94b512da4b5 100644 --- a/fs/cachefiles/daemon.c +++ b/fs/cachefiles/daemon.c @@ -662,6 +662,12 @@ static int cachefiles_daemon_cull(struct cachefiles_cache *cache, char *args) if (!d_can_lookup(path.dentry)) goto notdir;
+ /* limit the scope of cull */ + if (cache->mnt != path.mnt) { + path_put(&path); + return -EOPNOTSUPP; + } + cachefiles_begin_secure(cache, &saved_cred); ret = cachefiles_cull(cache, path.dentry, args); cachefiles_end_secure(cache, saved_cred); diff --git a/fs/cachefiles/internal.h b/fs/cachefiles/internal.h index 349b1e6bb7cd..97c4b4c639b4 100644 --- a/fs/cachefiles/internal.h +++ b/fs/cachefiles/internal.h @@ -210,6 +210,8 @@ extern char *cachefiles_cook_key(struct cachefiles_object *object, extern void cachefiles_mark_object_inactive(struct cachefiles_cache *cache, struct cachefiles_object *object, blkcnt_t i_blocks); +extern int cachefiles_mark_object_active(struct cachefiles_cache *cache, + struct cachefiles_object *object); extern int cachefiles_delete_object(struct cachefiles_cache *cache, struct cachefiles_object *object); extern int cachefiles_walk_to_object(struct cachefiles_object *parent, diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c index 799b7671e5b1..281e53d63972 100644 --- a/fs/cachefiles/namei.c +++ b/fs/cachefiles/namei.c @@ -133,8 +133,8 @@ static void cachefiles_mark_object_buried(struct cachefiles_cache *cache, /* * record the fact that an object is now active */ -static int cachefiles_mark_object_active(struct cachefiles_cache *cache, - struct cachefiles_object *object) +int cachefiles_mark_object_active(struct cachefiles_cache *cache, + struct cachefiles_object *object) { struct cachefiles_object *xobject; struct rb_node **_p, *_parent = NULL;