hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IB5UKT
--------------------------------
If the daemon performs an action that acquires the parent dir inode lock (e.g., statfs/cull/inuse) while processing an open request, it will result in an AA deadlock because the lock was already captured when the open request was issued.
This is avoided by issuing and processing open requests outside of the lock in advance. Although an anonymous fd has been acquired by the daemon, it cannot be used until object->file has been assigned a value, before which -ENOBUFS is returned.
Signed-off-by: Baokun Li libaokun1@huawei.com --- fs/cachefiles/namei.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-)
diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c index 88afa4a80dfb..799b7671e5b1 100644 --- a/fs/cachefiles/namei.c +++ b/fs/cachefiles/namei.c @@ -522,6 +522,20 @@ int cachefiles_walk_to_object(struct cachefiles_object *parent, key = NULL;
lookup_again: + + /* + * Process the open request before acquiring the dir inode lock to + * avoid AA deadlocks caused by the daemon acquiring the dir inode + * lock while processing the open request. Although the daemon gets + * an anonymous fd, it can't be used until object->file has been + * assigned a value. + */ + if (!key) { + ret = cachefiles_ondemand_init_object(object); + if (ret < 0) + goto error_out2; + } + /* search the current directory for the element name */ _debug("lookup '%s'", name);
@@ -592,10 +606,6 @@ int cachefiles_walk_to_object(struct cachefiles_object *parent, if (ret < 0) goto no_space_error;
- ret = cachefiles_ondemand_init_object(object); - if (ret < 0) - goto create_error; - path.dentry = dir; ret = security_path_mknod(&path, next, S_IFREG, 0); if (ret < 0) @@ -640,12 +650,6 @@ int cachefiles_walk_to_object(struct cachefiles_object *parent, if (!object->new) { _debug("validate '%pd'", next);
- ret = cachefiles_ondemand_init_object(object); - if (ret < 0) { - object->dentry = NULL; - goto error; - } - ret = cachefiles_check_object_xattr(object, auxdata); if (ret == -ESTALE) { /* delete the object (the deleter drops the directory