diff options
author | Ronnie Sahlberg <lsahlber@redhat.com> | 2021-08-25 21:16:56 +1000 |
---|---|---|
committer | Steve French <stfrench@microsoft.com> | 2021-08-25 16:08:38 -0500 |
commit | 3998f0b8bc49ec784990971dc1f16bf367b19078 (patch) | |
tree | 46c557393299f2d0a2ec1e534de27240fa517e2e /fs/cifs | |
parent | 332c404a55ef3b39837e958284275622a2a4849d (diff) | |
download | linux-stable-3998f0b8bc49ec784990971dc1f16bf367b19078.tar.gz linux-stable-3998f0b8bc49ec784990971dc1f16bf367b19078.tar.bz2 linux-stable-3998f0b8bc49ec784990971dc1f16bf367b19078.zip |
cifs: Do not leak EDEADLK to dgetents64 for STATUS_USER_SESSION_DELETED
RHBZ: 1994393
If we hit a STATUS_USER_SESSION_DELETED for the Create part in the
Create/QueryDirectory compound that starts a directory scan
we will leak EDEADLK back to userspace and surprise glibc and the application.
Pick this up initiate_cifs_search() and retry a small number of tries before we
return an error to userspace.
Cc: stable@vger.kernel.org
Reported-by: Xiaoli Feng <xifeng@redhat.com>
Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Diffstat (limited to 'fs/cifs')
-rw-r--r-- | fs/cifs/readdir.c | 23 |
1 files changed, 22 insertions, 1 deletions
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index bfee176b901d..54d77c99e21c 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -369,7 +369,7 @@ int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb, */ static int -initiate_cifs_search(const unsigned int xid, struct file *file, +_initiate_cifs_search(const unsigned int xid, struct file *file, const char *full_path) { __u16 search_flags; @@ -451,6 +451,27 @@ error_exit: return rc; } +static int +initiate_cifs_search(const unsigned int xid, struct file *file, + const char *full_path) +{ + int rc, retry_count = 0; + + do { + rc = _initiate_cifs_search(xid, file, full_path); + /* + * If we don't have enough credits to start reading the + * directory just try again after short wait. + */ + if (rc != -EDEADLK) + break; + + usleep_range(512, 2048); + } while (retry_count++ < 5); + + return rc; +} + /* return length of unicode string in bytes */ static int cifs_unicode_bytelen(const char *str) { |