Skip to content

Commit 2e5de42

Browse files
Paulo Alcantarasmfrench
authored andcommitted
cifs: reduce number of referral requests in DFS link lookups
When looking up the DFS cache with a referral path that has more than two path components, and is a complete prefix of an existing cache entry, do not request another referral and just return the matched entry as specified in MS-DFSC 3.2.5.5 Receiving a Root Referral Request or Link Referral Request. Signed-off-by: Paulo Alcantara (SUSE) <[email protected]> Reviewed-by: Aurelien Aptel <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent 565674d commit 2e5de42

File tree

1 file changed

+68
-11
lines changed

1 file changed

+68
-11
lines changed

fs/cifs/dfs_cache.c

Lines changed: 68 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -490,16 +490,7 @@ static int add_cache_entry(const char *path, unsigned int hash,
490490
return 0;
491491
}
492492

493-
/*
494-
* Find a DFS cache entry in hash table and optionally check prefix path against
495-
* @path.
496-
* Use whole path components in the match.
497-
* Must be called with htable_rw_lock held.
498-
*
499-
* Return ERR_PTR(-ENOENT) if the entry is not found.
500-
*/
501-
static struct cache_entry *lookup_cache_entry(const char *path,
502-
unsigned int *hash)
493+
static struct cache_entry *__lookup_cache_entry(const char *path)
503494
{
504495
struct cache_entry *ce;
505496
unsigned int h;
@@ -517,9 +508,75 @@ static struct cache_entry *lookup_cache_entry(const char *path,
517508

518509
if (!found)
519510
ce = ERR_PTR(-ENOENT);
511+
return ce;
512+
}
513+
514+
/*
515+
* Find a DFS cache entry in hash table and optionally check prefix path against
516+
* @path.
517+
* Use whole path components in the match.
518+
* Must be called with htable_rw_lock held.
519+
*
520+
* Return ERR_PTR(-ENOENT) if the entry is not found.
521+
*/
522+
static struct cache_entry *lookup_cache_entry(const char *path, unsigned int *hash)
523+
{
524+
struct cache_entry *ce = ERR_PTR(-ENOENT);
525+
unsigned int h;
526+
int cnt = 0;
527+
char *npath;
528+
char *s, *e;
529+
char sep;
530+
531+
npath = kstrndup(path, strlen(path), GFP_KERNEL);
532+
if (!npath)
533+
return ERR_PTR(-ENOMEM);
534+
535+
s = npath;
536+
sep = *npath;
537+
while ((s = strchr(s, sep)) && ++cnt < 3)
538+
s++;
539+
540+
if (cnt < 3) {
541+
h = cache_entry_hash(path, strlen(path));
542+
ce = __lookup_cache_entry(path);
543+
goto out;
544+
}
545+
/*
546+
* Handle paths that have more than two path components and are a complete prefix of the DFS
547+
* referral request path (@path).
548+
*
549+
* See MS-DFSC 3.2.5.5 "Receiving a Root Referral Request or Link Referral Request".
550+
*/
551+
h = cache_entry_hash(npath, strlen(npath));
552+
e = npath + strlen(npath) - 1;
553+
while (e > s) {
554+
char tmp;
555+
556+
/* skip separators */
557+
while (e > s && *e == sep)
558+
e--;
559+
if (e == s)
560+
goto out;
561+
562+
tmp = *(e+1);
563+
*(e+1) = 0;
564+
565+
ce = __lookup_cache_entry(npath);
566+
if (!IS_ERR(ce)) {
567+
h = cache_entry_hash(npath, strlen(npath));
568+
break;
569+
}
570+
571+
*(e+1) = tmp;
572+
/* backward until separator */
573+
while (e > s && *e != sep)
574+
e--;
575+
}
576+
out:
520577
if (hash)
521578
*hash = h;
522-
579+
kfree(npath);
523580
return ce;
524581
}
525582

0 commit comments

Comments
 (0)