Skip to content

Commit ef605e8

Browse files
Paulo Alcantarasmfrench
authored andcommitted
cifs: skip trailing separators of prefix paths
During DFS failover, prefix paths may change, so make sure to not leave trailing separators when parsing thew in dfs_cache_get_tgt_share(). The separators of prefix paths are already handled by build_path_from_dentry_optional_prefix(). Consider the following DFS link: //dom/dfs/link: [\srv1\share\dir1, \srv2\share\dir1] Before commit: mount.cifs //dom/dfs/link tree connect to \\srv1\share; prefix_path=dir1 disconnect srv1; failover to srv2 tree connect to \\srv2\share; prefix_path=dir1\ mv foo bar ... SMB2 430 Create Request File: dir1\\foo;GetInfo Request FILE_INFO/SMB2_FILE_ALL_INFO;Close Request SMB2 582 Create Response File: dir1\\foo;GetInfo Response;Close Response SMB2 430 Create Request File: dir1\\bar;GetInfo Request FILE_INFO/SMB2_FILE_ALL_INFO;Close Request SMB2 286 Create Response, Error: STATUS_OBJECT_NAME_NOT_FOUND;GetInfo Response, Error: STATUS_OBJECT_NAME_NOT_FOUND;Close Response, Error: STATUS_OBJECT_NAME_NOT_FOUND SMB2 462 Create Request File: dir1\\foo;SetInfo Request FILE_INFO/SMB2_FILE_RENAME_INFO NewName:dir1\\bar;Close Request SMB2 478 Create Response File: dir1\\foo;SetInfo Response, Error: STATUS_OBJECT_NAME_INVALID;Close Response After commit: mount.cifs //dom/dfs/link tree connect to \\srv1\share; prefix_path=dir1 disconnect srv1; failover to srv2 tree connect to \\srv2\share; prefix_path=dir1 mv foo bar ... SMB2 430 Create Request File: dir1\foo;GetInfo Request FILE_INFO/SMB2_FILE_ALL_INFO;Close Request SMB2 582 Create Response File: dir1\foo;GetInfo Response;Close Response SMB2 430 Create Request File: dir1\bar;GetInfo Request FILE_INFO/SMB2_FILE_ALL_INFO;Close Request SMB2 286 Create Response, Error: STATUS_OBJECT_NAME_NOT_FOUND;GetInfo Response, Error: STATUS_OBJECT_NAME_NOT_FOUND;Close Response, Error: STATUS_OBJECT_NAME_NOT_FOUND SMB2 462 Create Request File: dir1\foo;SetInfo Request FILE_INFO/SMB2_FILE_RENAME_INFO NewName:dir1\bar;Close Request SMB2 478 Create Response File: dir1\foo;SetInfo Response;Close Response Signed-off-by: Paulo Alcantara (SUSE) <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent 096c956 commit ef605e8

File tree

1 file changed

+49
-36
lines changed

1 file changed

+49
-36
lines changed

fs/cifs/dfs_cache.c

Lines changed: 49 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1229,6 +1229,30 @@ void dfs_cache_put_refsrv_sessions(const uuid_t *mount_id)
12291229
kref_put(&mg->refcount, mount_group_release);
12301230
}
12311231

1232+
/* Extract share from DFS target and return a pointer to prefix path or NULL */
1233+
static const char *parse_target_share(const char *target, char **share)
1234+
{
1235+
const char *s, *seps = "/\\";
1236+
size_t len;
1237+
1238+
s = strpbrk(target + 1, seps);
1239+
if (!s)
1240+
return ERR_PTR(-EINVAL);
1241+
1242+
len = strcspn(s + 1, seps);
1243+
if (!len)
1244+
return ERR_PTR(-EINVAL);
1245+
s += len;
1246+
1247+
len = s - target + 1;
1248+
*share = kstrndup(target, len, GFP_KERNEL);
1249+
if (!*share)
1250+
return ERR_PTR(-ENOMEM);
1251+
1252+
s = target + len;
1253+
return s + strspn(s, seps);
1254+
}
1255+
12321256
/**
12331257
* dfs_cache_get_tgt_share - parse a DFS target
12341258
*
@@ -1242,56 +1266,45 @@ void dfs_cache_put_refsrv_sessions(const uuid_t *mount_id)
12421266
int dfs_cache_get_tgt_share(char *path, const struct dfs_cache_tgt_iterator *it, char **share,
12431267
char **prefix)
12441268
{
1245-
char *s, sep, *p;
1246-
size_t len;
1247-
size_t plen1, plen2;
1269+
char sep;
1270+
char *target_share, *ppath;
1271+
const char *target_ppath, *dfsref_ppath;
1272+
size_t target_pplen, dfsref_pplen;
1273+
size_t len, c;
12481274

12491275
if (!it || !path || !share || !prefix || strlen(path) < it->it_path_consumed)
12501276
return -EINVAL;
12511277

1252-
*share = NULL;
1253-
*prefix = NULL;
1254-
12551278
sep = it->it_name[0];
12561279
if (sep != '\\' && sep != '/')
12571280
return -EINVAL;
12581281

1259-
s = strchr(it->it_name + 1, sep);
1260-
if (!s)
1261-
return -EINVAL;
1282+
target_ppath = parse_target_share(it->it_name, &target_share);
1283+
if (IS_ERR(target_ppath))
1284+
return PTR_ERR(target_ppath);
12621285

1263-
/* point to prefix in target node */
1264-
s = strchrnul(s + 1, sep);
1286+
/* point to prefix in DFS referral path */
1287+
dfsref_ppath = path + it->it_path_consumed;
1288+
dfsref_ppath += strspn(dfsref_ppath, "/\\");
12651289

1266-
/* extract target share */
1267-
*share = kstrndup(it->it_name, s - it->it_name, GFP_KERNEL);
1268-
if (!*share)
1269-
return -ENOMEM;
1290+
target_pplen = strlen(target_ppath);
1291+
dfsref_pplen = strlen(dfsref_ppath);
12701292

1271-
/* skip separator */
1272-
if (*s)
1273-
s++;
1274-
/* point to prefix in DFS path */
1275-
p = path + it->it_path_consumed;
1276-
if (*p == sep)
1277-
p++;
1278-
1279-
/* merge prefix paths from DFS path and target node */
1280-
plen1 = it->it_name + strlen(it->it_name) - s;
1281-
plen2 = path + strlen(path) - p;
1282-
if (plen1 || plen2) {
1283-
len = plen1 + plen2 + 2;
1284-
*prefix = kmalloc(len, GFP_KERNEL);
1285-
if (!*prefix) {
1286-
kfree(*share);
1287-
*share = NULL;
1293+
/* merge prefix paths from DFS referral path and target node */
1294+
if (target_pplen || dfsref_pplen) {
1295+
len = target_pplen + dfsref_pplen + 2;
1296+
ppath = kzalloc(len, GFP_KERNEL);
1297+
if (!ppath) {
1298+
kfree(target_share);
12881299
return -ENOMEM;
12891300
}
1290-
if (plen1)
1291-
scnprintf(*prefix, len, "%.*s%c%.*s", (int)plen1, s, sep, (int)plen2, p);
1292-
else
1293-
strscpy(*prefix, p, len);
1301+
c = strscpy(ppath, target_ppath, len);
1302+
if (c && dfsref_pplen)
1303+
ppath[c] = sep;
1304+
strlcat(ppath, dfsref_ppath, len);
12941305
}
1306+
*share = target_share;
1307+
*prefix = ppath;
12951308
return 0;
12961309
}
12971310

0 commit comments

Comments
 (0)