struct super_block *cifs_get_tcp_super(struct TCP_Server_Info *server);
void cifs_put_tcp_super(struct super_block *sb);
-int update_super_prepath(struct cifs_tcon *tcon, const char *prefix,
- size_t prefix_len);
+int update_super_prepath(struct cifs_tcon *tcon, char *prefix);
#ifdef CONFIG_CIFS_DFS_UPCALL
static inline int get_dfs_path(const unsigned int xid, struct cifs_ses *ses,
size_t tcp_host_len;
const char *dfs_host;
size_t dfs_host_len;
+ char *share = NULL, *prefix = NULL;
tree = kzalloc(MAX_TREE_SIZE, GFP_KERNEL);
if (!tree)
extract_unc_hostname(server->hostname, &tcp_host, &tcp_host_len);
for (it = dfs_cache_get_tgt_iterator(&tl); it; it = dfs_cache_get_next_tgt(&tl, it)) {
- const char *share, *prefix;
- size_t share_len, prefix_len;
bool target_match;
- rc = dfs_cache_get_tgt_share(it, &share, &share_len, &prefix, &prefix_len);
+ kfree(share);
+ kfree(prefix);
+
+ rc = dfs_cache_get_tgt_share(tcon->dfs_path + 1, it, &share, &prefix);
if (rc) {
cifs_dbg(VFS, "%s: failed to parse target share %d\n",
__func__, rc);
}
if (tcon->ipc) {
- scnprintf(tree, MAX_TREE_SIZE, "\\\\%.*s\\IPC$", (int)share_len, share);
+ scnprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$", share);
rc = ops->tree_connect(xid, tcon->ses, tree, tcon, nlsc);
} else {
- scnprintf(tree, MAX_TREE_SIZE, "\\%.*s", (int)share_len, share);
+ scnprintf(tree, MAX_TREE_SIZE, "\\%s", share);
rc = ops->tree_connect(xid, tcon->ses, tree, tcon, nlsc);
if (!rc) {
- rc = update_super_prepath(tcon, prefix, prefix_len);
+ rc = update_super_prepath(tcon, prefix);
break;
}
}
break;
}
+ kfree(share);
+ kfree(prefix);
+
if (!rc) {
if (it)
rc = dfs_cache_noreq_update_tgthint(tcon->dfs_path + 1, it);
struct cache_dfs_tgt {
char *name;
+ int path_consumed;
struct list_head list;
};
}
/* Allocate a new DFS target */
-static struct cache_dfs_tgt *alloc_target(const char *name)
+static struct cache_dfs_tgt *alloc_target(const char *name, int path_consumed)
{
struct cache_dfs_tgt *t;
kfree(t);
return ERR_PTR(-ENOMEM);
}
+ t->path_consumed = path_consumed;
INIT_LIST_HEAD(&t->list);
return t;
}
for (i = 0; i < numrefs; i++) {
struct cache_dfs_tgt *t;
- t = alloc_target(refs[i].node_name);
+ t = alloc_target(refs[i].node_name, refs[i].path_consumed);
if (IS_ERR(t)) {
free_tgts(ce);
return PTR_ERR(t);
rc = -ENOMEM;
goto err_free_it;
}
+ it->it_path_consumed = t->path_consumed;
if (ce->tgthint == t)
list_add(&it->it_list, head);
/**
* dfs_cache_get_tgt_share - parse a DFS target
*
+ * @path: DFS full path
* @it: DFS target iterator.
* @share: tree name.
- * @share_len: length of tree name.
* @prefix: prefix path.
- * @prefix_len: length of prefix path.
*
* Return zero if target was parsed correctly, otherwise non-zero.
*/
-int dfs_cache_get_tgt_share(const struct dfs_cache_tgt_iterator *it,
- const char **share, size_t *share_len,
- const char **prefix, size_t *prefix_len)
+int dfs_cache_get_tgt_share(char *path, const struct dfs_cache_tgt_iterator *it,
+ char **share, char **prefix)
{
- char *s, sep;
+ char *s, sep, *p;
+ size_t len;
+ size_t plen1, plen2;
- if (!it || !share || !share_len || !prefix || !prefix_len)
+ if (!it || !path || !share || !prefix || strlen(path) < it->it_path_consumed)
return -EINVAL;
+ *share = NULL;
+ *prefix = NULL;
+
sep = it->it_name[0];
if (sep != '\\' && sep != '/')
return -EINVAL;
if (!s)
return -EINVAL;
+ /* point to prefix in target node */
s = strchrnul(s + 1, sep);
- *share = it->it_name;
- *share_len = s - it->it_name;
- *prefix = *s ? s + 1 : s;
- *prefix_len = &it->it_name[strlen(it->it_name)] - *prefix;
+ /* extract target share */
+ *share = kstrndup(it->it_name, s - it->it_name, GFP_KERNEL);
+ if (!*share)
+ return -ENOMEM;
+ /* skip separator */
+ if (*s)
+ s++;
+ /* point to prefix in DFS path */
+ p = path + it->it_path_consumed;
+ if (*p == sep)
+ p++;
+
+ /* merge prefix paths from DFS path and target node */
+ plen1 = it->it_name + strlen(it->it_name) - s;
+ plen2 = path + strlen(path) - p;
+ if (plen1 || plen2) {
+ len = plen1 + plen2 + 2;
+ *prefix = kmalloc(len, GFP_KERNEL);
+ if (!*prefix) {
+ kfree(*share);
+ *share = NULL;
+ return -ENOMEM;
+ }
+ if (plen1)
+ scnprintf(*prefix, len, "%.*s%c%.*s", (int)plen1, s, sep, (int)plen2, p);
+ else
+ strscpy(*prefix, p, len);
+ }
return 0;
}
struct dfs_cache_tgt_iterator {
char *it_name;
+ int it_path_consumed;
struct list_head it_list;
};
extern int dfs_cache_update_vol(const char *fullpath,
struct TCP_Server_Info *server);
extern void dfs_cache_del_vol(const char *fullpath);
-
-extern int dfs_cache_get_tgt_share(const struct dfs_cache_tgt_iterator *it,
- const char **share, size_t *share_len,
- const char **prefix, size_t *prefix_len);
+extern int dfs_cache_get_tgt_share(char *path, const struct dfs_cache_tgt_iterator *it,
+ char **share, char **prefix);
static inline struct dfs_cache_tgt_iterator *
dfs_cache_get_next_tgt(struct dfs_cache_tgt_list *tl,
}
#endif
-int update_super_prepath(struct cifs_tcon *tcon, const char *prefix,
- size_t prefix_len)
+int update_super_prepath(struct cifs_tcon *tcon, char *prefix)
{
struct super_block *sb;
struct cifs_sb_info *cifs_sb;
kfree(cifs_sb->prepath);
- if (*prefix && prefix_len) {
- cifs_sb->prepath = kstrndup(prefix, prefix_len, GFP_ATOMIC);
+ if (prefix && *prefix) {
+ cifs_sb->prepath = kstrndup(prefix, strlen(prefix), GFP_ATOMIC);
if (!cifs_sb->prepath) {
rc = -ENOMEM;
goto out;