Skip to content

Commit 7548e1d

Browse files
Paulo Alcantarasmfrench
authored andcommitted
cifs: handle RESP_GET_DFS_REFERRAL.PathConsumed in reconnect
Use PathConsumed field when parsing prefixes of referral paths that either match a cache entry or are a complete prefix path of an existing entry. Signed-off-by: Paulo Alcantara (SUSE) <[email protected]> Reviewed-by: Aurelien Aptel <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent a529303 commit 7548e1d

File tree

5 files changed

+62
-29
lines changed

5 files changed

+62
-29
lines changed

fs/cifs/cifsproto.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -617,8 +617,7 @@ int smb2_parse_query_directory(struct cifs_tcon *tcon, struct kvec *rsp_iov,
617617

618618
struct super_block *cifs_get_tcp_super(struct TCP_Server_Info *server);
619619
void cifs_put_tcp_super(struct super_block *sb);
620-
int update_super_prepath(struct cifs_tcon *tcon, const char *prefix,
621-
size_t prefix_len);
620+
int update_super_prepath(struct cifs_tcon *tcon, char *prefix);
622621

623622
#ifdef CONFIG_CIFS_DFS_UPCALL
624623
static inline int get_dfs_path(const unsigned int xid, struct cifs_ses *ses,

fs/cifs/connect.c

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5547,6 +5547,7 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru
55475547
size_t tcp_host_len;
55485548
const char *dfs_host;
55495549
size_t dfs_host_len;
5550+
char *share = NULL, *prefix = NULL;
55505551

55515552
tree = kzalloc(MAX_TREE_SIZE, GFP_KERNEL);
55525553
if (!tree)
@@ -5569,11 +5570,12 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru
55695570
extract_unc_hostname(server->hostname, &tcp_host, &tcp_host_len);
55705571

55715572
for (it = dfs_cache_get_tgt_iterator(&tl); it; it = dfs_cache_get_next_tgt(&tl, it)) {
5572-
const char *share, *prefix;
5573-
size_t share_len, prefix_len;
55745573
bool target_match;
55755574

5576-
rc = dfs_cache_get_tgt_share(it, &share, &share_len, &prefix, &prefix_len);
5575+
kfree(share);
5576+
kfree(prefix);
5577+
5578+
rc = dfs_cache_get_tgt_share(tcon->dfs_path + 1, it, &share, &prefix);
55775579
if (rc) {
55785580
cifs_dbg(VFS, "%s: failed to parse target share %d\n",
55795581
__func__, rc);
@@ -5600,20 +5602,23 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru
56005602
}
56015603

56025604
if (tcon->ipc) {
5603-
scnprintf(tree, MAX_TREE_SIZE, "\\\\%.*s\\IPC$", (int)share_len, share);
5605+
scnprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$", share);
56045606
rc = ops->tree_connect(xid, tcon->ses, tree, tcon, nlsc);
56055607
} else {
5606-
scnprintf(tree, MAX_TREE_SIZE, "\\%.*s", (int)share_len, share);
5608+
scnprintf(tree, MAX_TREE_SIZE, "\\%s", share);
56075609
rc = ops->tree_connect(xid, tcon->ses, tree, tcon, nlsc);
56085610
if (!rc) {
5609-
rc = update_super_prepath(tcon, prefix, prefix_len);
5611+
rc = update_super_prepath(tcon, prefix);
56105612
break;
56115613
}
56125614
}
56135615
if (rc == -EREMOTE)
56145616
break;
56155617
}
56165618

5619+
kfree(share);
5620+
kfree(prefix);
5621+
56175622
if (!rc) {
56185623
if (it)
56195624
rc = dfs_cache_noreq_update_tgthint(tcon->dfs_path + 1, it);

fs/cifs/dfs_cache.c

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
struct cache_dfs_tgt {
3131
char *name;
32+
int path_consumed;
3233
struct list_head list;
3334
};
3435

@@ -350,7 +351,7 @@ static inline struct timespec64 get_expire_time(int ttl)
350351
}
351352

352353
/* Allocate a new DFS target */
353-
static struct cache_dfs_tgt *alloc_target(const char *name)
354+
static struct cache_dfs_tgt *alloc_target(const char *name, int path_consumed)
354355
{
355356
struct cache_dfs_tgt *t;
356357

@@ -362,6 +363,7 @@ static struct cache_dfs_tgt *alloc_target(const char *name)
362363
kfree(t);
363364
return ERR_PTR(-ENOMEM);
364365
}
366+
t->path_consumed = path_consumed;
365367
INIT_LIST_HEAD(&t->list);
366368
return t;
367369
}
@@ -384,7 +386,7 @@ static int copy_ref_data(const struct dfs_info3_param *refs, int numrefs,
384386
for (i = 0; i < numrefs; i++) {
385387
struct cache_dfs_tgt *t;
386388

387-
t = alloc_target(refs[i].node_name);
389+
t = alloc_target(refs[i].node_name, refs[i].path_consumed);
388390
if (IS_ERR(t)) {
389391
free_tgts(ce);
390392
return PTR_ERR(t);
@@ -830,6 +832,7 @@ static int get_targets(struct cache_entry *ce, struct dfs_cache_tgt_list *tl)
830832
rc = -ENOMEM;
831833
goto err_free_it;
832834
}
835+
it->it_path_consumed = t->path_consumed;
833836

834837
if (ce->tgthint == t)
835838
list_add(&it->it_list, head);
@@ -1320,23 +1323,26 @@ void dfs_cache_del_vol(const char *fullpath)
13201323
/**
13211324
* dfs_cache_get_tgt_share - parse a DFS target
13221325
*
1326+
* @path: DFS full path
13231327
* @it: DFS target iterator.
13241328
* @share: tree name.
1325-
* @share_len: length of tree name.
13261329
* @prefix: prefix path.
1327-
* @prefix_len: length of prefix path.
13281330
*
13291331
* Return zero if target was parsed correctly, otherwise non-zero.
13301332
*/
1331-
int dfs_cache_get_tgt_share(const struct dfs_cache_tgt_iterator *it,
1332-
const char **share, size_t *share_len,
1333-
const char **prefix, size_t *prefix_len)
1333+
int dfs_cache_get_tgt_share(char *path, const struct dfs_cache_tgt_iterator *it,
1334+
char **share, char **prefix)
13341335
{
1335-
char *s, sep;
1336+
char *s, sep, *p;
1337+
size_t len;
1338+
size_t plen1, plen2;
13361339

1337-
if (!it || !share || !share_len || !prefix || !prefix_len)
1340+
if (!it || !path || !share || !prefix || strlen(path) < it->it_path_consumed)
13381341
return -EINVAL;
13391342

1343+
*share = NULL;
1344+
*prefix = NULL;
1345+
13401346
sep = it->it_name[0];
13411347
if (sep != '\\' && sep != '/')
13421348
return -EINVAL;
@@ -1345,13 +1351,38 @@ int dfs_cache_get_tgt_share(const struct dfs_cache_tgt_iterator *it,
13451351
if (!s)
13461352
return -EINVAL;
13471353

1354+
/* point to prefix in target node */
13481355
s = strchrnul(s + 1, sep);
13491356

1350-
*share = it->it_name;
1351-
*share_len = s - it->it_name;
1352-
*prefix = *s ? s + 1 : s;
1353-
*prefix_len = &it->it_name[strlen(it->it_name)] - *prefix;
1357+
/* extract target share */
1358+
*share = kstrndup(it->it_name, s - it->it_name, GFP_KERNEL);
1359+
if (!*share)
1360+
return -ENOMEM;
13541361

1362+
/* skip separator */
1363+
if (*s)
1364+
s++;
1365+
/* point to prefix in DFS path */
1366+
p = path + it->it_path_consumed;
1367+
if (*p == sep)
1368+
p++;
1369+
1370+
/* merge prefix paths from DFS path and target node */
1371+
plen1 = it->it_name + strlen(it->it_name) - s;
1372+
plen2 = path + strlen(path) - p;
1373+
if (plen1 || plen2) {
1374+
len = plen1 + plen2 + 2;
1375+
*prefix = kmalloc(len, GFP_KERNEL);
1376+
if (!*prefix) {
1377+
kfree(*share);
1378+
*share = NULL;
1379+
return -ENOMEM;
1380+
}
1381+
if (plen1)
1382+
scnprintf(*prefix, len, "%.*s%c%.*s", (int)plen1, s, sep, (int)plen2, p);
1383+
else
1384+
strscpy(*prefix, p, len);
1385+
}
13551386
return 0;
13561387
}
13571388

fs/cifs/dfs_cache.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ struct dfs_cache_tgt_list {
1919

2020
struct dfs_cache_tgt_iterator {
2121
char *it_name;
22+
int it_path_consumed;
2223
struct list_head it_list;
2324
};
2425

@@ -48,10 +49,8 @@ extern int dfs_cache_add_vol(char *mntdata, struct smb_vol *vol,
4849
extern int dfs_cache_update_vol(const char *fullpath,
4950
struct TCP_Server_Info *server);
5051
extern void dfs_cache_del_vol(const char *fullpath);
51-
52-
extern int dfs_cache_get_tgt_share(const struct dfs_cache_tgt_iterator *it,
53-
const char **share, size_t *share_len,
54-
const char **prefix, size_t *prefix_len);
52+
extern int dfs_cache_get_tgt_share(char *path, const struct dfs_cache_tgt_iterator *it,
53+
char **share, char **prefix);
5554

5655
static inline struct dfs_cache_tgt_iterator *
5756
dfs_cache_get_next_tgt(struct dfs_cache_tgt_list *tl,

fs/cifs/misc.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1164,8 +1164,7 @@ static inline void cifs_put_tcon_super(struct super_block *sb)
11641164
}
11651165
#endif
11661166

1167-
int update_super_prepath(struct cifs_tcon *tcon, const char *prefix,
1168-
size_t prefix_len)
1167+
int update_super_prepath(struct cifs_tcon *tcon, char *prefix)
11691168
{
11701169
struct super_block *sb;
11711170
struct cifs_sb_info *cifs_sb;
@@ -1179,8 +1178,8 @@ int update_super_prepath(struct cifs_tcon *tcon, const char *prefix,
11791178

11801179
kfree(cifs_sb->prepath);
11811180

1182-
if (*prefix && prefix_len) {
1183-
cifs_sb->prepath = kstrndup(prefix, prefix_len, GFP_ATOMIC);
1181+
if (prefix && *prefix) {
1182+
cifs_sb->prepath = kstrndup(prefix, strlen(prefix), GFP_ATOMIC);
11841183
if (!cifs_sb->prepath) {
11851184
rc = -ENOMEM;
11861185
goto out;

0 commit comments

Comments
 (0)