According to the investigation performed by Jacob Shivers at Red Hat, cifs_lookup and cifs_readdir leak EAGAIN when the user session is deleted on the server. Fix this issue by implementing a retry with limits, as is implemented in cifs_revalidate_dentry_attr. Signed-off-by: Thiago Rafael Becker <trbecker@xxxxxxxxx> --- fs/cifs/dir.c | 4 ++++ fs/cifs/readdir.c | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 6bcd3e8f7cda..7c641f9a3dac 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -630,6 +630,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct inode *newInode = NULL; const char *full_path; void *page; + int retry_count = 0; xid = get_xid(); @@ -673,6 +674,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, cifs_dbg(FYI, "Full path: %s inode = 0x%p\n", full_path, d_inode(direntry)); +again: if (pTcon->posix_extensions) rc = smb311_posix_get_inode_info(&newInode, full_path, parent_dir_inode->i_sb, xid); else if (pTcon->unix_ext) { @@ -687,6 +689,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, /* since paths are not looked up by component - the parent directories are presumed to be good here */ renew_parental_timestamps(direntry); + } else if (rc == -EAGAIN && retry_count++ < 10) { + goto again; } else if (rc == -ENOENT) { cifs_set_time(direntry, jiffies); newInode = NULL; diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 63bfc533c9fb..01e6d41e387f 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -844,9 +844,15 @@ static int cifs_filldir(char *find_entry, struct file *file, struct qstr name; int rc = 0; ino_t ino; + int retry_count = 0; +again: rc = cifs_fill_dirent(&de, find_entry, file_info->srch_inf.info_level, file_info->srch_inf.unicode); + + if (rc == -EAGAIN && retry_count++ < 10) + goto again; + if (rc) return rc; -- 2.31.1