Skip to content

Commit be4fde7

Browse files
Paulo AlcantaraSteve French
authored andcommitted
cifs: fix dentry lookups in directory handle cache
Get rid of any prefix paths in @path before lookup_positive_unlocked() as it will call ->lookup() which already adds those prefix paths through build_path_from_dentry(). This has caused a performance regression when mounting shares with a prefix path where readdir(2) would end up retrying several times to open bad directory names that contained duplicate prefix paths. Fix this by skipping any prefix paths in @path before calling lookup_positive_unlocked(). Fixes: e4029e0 ("cifs: find and use the dentry for cached non-root directories also") Cc: stable@vger.kernel.org # 6.1+ Signed-off-by: Paulo Alcantara (SUSE) <pc@manguebit.com> Signed-off-by: Steve French <stfrench@microsoft.com>
1 parent 7e0e76d commit be4fde7

File tree

1 file changed

+34
-2
lines changed

1 file changed

+34
-2
lines changed

fs/cifs/cached_dir.c

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,23 @@ path_to_dentry(struct cifs_sb_info *cifs_sb, const char *path)
9999
return dentry;
100100
}
101101

102+
static const char *path_no_prefix(struct cifs_sb_info *cifs_sb,
103+
const char *path)
104+
{
105+
size_t len = 0;
106+
107+
if (!*path)
108+
return path;
109+
110+
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) &&
111+
cifs_sb->prepath) {
112+
len = strlen(cifs_sb->prepath) + 1;
113+
if (unlikely(len > strlen(path)))
114+
return ERR_PTR(-EINVAL);
115+
}
116+
return path + len;
117+
}
118+
102119
/*
103120
* Open the and cache a directory handle.
104121
* If error then *cfid is not initialized.
@@ -125,6 +142,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
125142
struct dentry *dentry = NULL;
126143
struct cached_fid *cfid;
127144
struct cached_fids *cfids;
145+
const char *npath;
128146

129147
if (tcon == NULL || tcon->cfids == NULL || tcon->nohandlecache ||
130148
is_smb1_server(tcon->ses->server))
@@ -160,6 +178,20 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
160178
return 0;
161179
}
162180

181+
/*
182+
* Skip any prefix paths in @path as lookup_positive_unlocked() ends up
183+
* calling ->lookup() which already adds those through
184+
* build_path_from_dentry(). Also, do it earlier as we might reconnect
185+
* below when trying to send compounded request and then potentially
186+
* having a different prefix path (e.g. after DFS failover).
187+
*/
188+
npath = path_no_prefix(cifs_sb, path);
189+
if (IS_ERR(npath)) {
190+
rc = PTR_ERR(npath);
191+
kfree(utf16_path);
192+
return rc;
193+
}
194+
163195
/*
164196
* We do not hold the lock for the open because in case
165197
* SMB2_open needs to reconnect.
@@ -252,10 +284,10 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
252284
(char *)&cfid->file_all_info))
253285
cfid->file_all_info_is_valid = true;
254286

255-
if (!path[0])
287+
if (!npath[0])
256288
dentry = dget(cifs_sb->root);
257289
else {
258-
dentry = path_to_dentry(cifs_sb, path);
290+
dentry = path_to_dentry(cifs_sb, npath);
259291
if (IS_ERR(dentry)) {
260292
rc = -ENOENT;
261293
goto oshr_free;

0 commit comments

Comments
 (0)