Skip to content

Commit 5739375

Browse files
Paulo Alcantara (SUSE)Steve French
authored andcommitted
cifs: Fix mount options set in automount
Starting from 4a367dc, we must set the mount options based on the DFS full path rather than the resolved target, that is, cifs_mount() will be responsible for resolving the DFS link (cached) as well as performing failover to any other targets in the referral. Signed-off-by: Paulo Alcantara (SUSE) <[email protected]> Reported-by: Martijn de Gouw <[email protected]> Fixes: 4a367dc ("cifs: Add support for failover in cifs_mount()") Link: https://lore.kernel.org/linux-cifs/[email protected] Tested-by: Martijn de Gouw <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent 463a7b4 commit 5739375

File tree

1 file changed

+43
-54
lines changed

1 file changed

+43
-54
lines changed

fs/cifs/cifs_dfs_ref.c

Lines changed: 43 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -120,17 +120,17 @@ cifs_build_devname(char *nodename, const char *prepath)
120120

121121

122122
/**
123-
* cifs_compose_mount_options - creates mount options for refferral
123+
* cifs_compose_mount_options - creates mount options for referral
124124
* @sb_mountdata: parent/root DFS mount options (template)
125125
* @fullpath: full path in UNC format
126-
* @ref: server's referral
126+
* @ref: optional server's referral
127127
* @devname: optional pointer for saving device name
128128
*
129129
* creates mount options for submount based on template options sb_mountdata
130130
* and replacing unc,ip,prefixpath options with ones we've got form ref_unc.
131131
*
132132
* Returns: pointer to new mount options or ERR_PTR.
133-
* Caller is responcible for freeing retunrned value if it is not error.
133+
* Caller is responsible for freeing returned value if it is not error.
134134
*/
135135
char *cifs_compose_mount_options(const char *sb_mountdata,
136136
const char *fullpath,
@@ -150,18 +150,27 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
150150
if (sb_mountdata == NULL)
151151
return ERR_PTR(-EINVAL);
152152

153-
if (strlen(fullpath) - ref->path_consumed) {
154-
prepath = fullpath + ref->path_consumed;
155-
/* skip initial delimiter */
156-
if (*prepath == '/' || *prepath == '\\')
157-
prepath++;
158-
}
153+
if (ref) {
154+
if (strlen(fullpath) - ref->path_consumed) {
155+
prepath = fullpath + ref->path_consumed;
156+
/* skip initial delimiter */
157+
if (*prepath == '/' || *prepath == '\\')
158+
prepath++;
159+
}
159160

160-
name = cifs_build_devname(ref->node_name, prepath);
161-
if (IS_ERR(name)) {
162-
rc = PTR_ERR(name);
163-
name = NULL;
164-
goto compose_mount_options_err;
161+
name = cifs_build_devname(ref->node_name, prepath);
162+
if (IS_ERR(name)) {
163+
rc = PTR_ERR(name);
164+
name = NULL;
165+
goto compose_mount_options_err;
166+
}
167+
} else {
168+
name = cifs_build_devname((char *)fullpath, NULL);
169+
if (IS_ERR(name)) {
170+
rc = PTR_ERR(name);
171+
name = NULL;
172+
goto compose_mount_options_err;
173+
}
165174
}
166175

167176
rc = dns_resolve_server_name_to_ip(name, &srvIP);
@@ -225,6 +234,8 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
225234

226235
if (devname)
227236
*devname = name;
237+
else
238+
kfree(name);
228239

229240
/*cifs_dbg(FYI, "%s: parent mountdata: %s\n", __func__, sb_mountdata);*/
230241
/*cifs_dbg(FYI, "%s: submount mountdata: %s\n", __func__, mountdata );*/
@@ -241,23 +252,23 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
241252
}
242253

243254
/**
244-
* cifs_dfs_do_refmount - mounts specified path using provided refferal
255+
* cifs_dfs_do_mount - mounts specified path using DFS full path
256+
*
257+
* Always pass down @fullpath to smb3_do_mount() so we can use the root server
258+
* to perform failover in case we failed to connect to the first target in the
259+
* referral.
260+
*
245261
* @cifs_sb: parent/root superblock
246262
* @fullpath: full path in UNC format
247-
* @ref: server's referral
248263
*/
249-
static struct vfsmount *cifs_dfs_do_refmount(struct dentry *mntpt,
250-
struct cifs_sb_info *cifs_sb,
251-
const char *fullpath, const struct dfs_info3_param *ref)
264+
static struct vfsmount *cifs_dfs_do_mount(struct dentry *mntpt,
265+
struct cifs_sb_info *cifs_sb,
266+
const char *fullpath)
252267
{
253268
struct vfsmount *mnt;
254269
char *mountdata;
255270
char *devname;
256271

257-
/*
258-
* Always pass down the DFS full path to smb3_do_mount() so we
259-
* can use it later for failover.
260-
*/
261272
devname = kstrndup(fullpath, strlen(fullpath), GFP_KERNEL);
262273
if (!devname)
263274
return ERR_PTR(-ENOMEM);
@@ -266,7 +277,7 @@ static struct vfsmount *cifs_dfs_do_refmount(struct dentry *mntpt,
266277

267278
/* strip first '\' from fullpath */
268279
mountdata = cifs_compose_mount_options(cifs_sb->mountdata,
269-
fullpath + 1, ref, NULL);
280+
fullpath + 1, NULL, NULL);
270281
if (IS_ERR(mountdata)) {
271282
kfree(devname);
272283
return (struct vfsmount *)mountdata;
@@ -278,28 +289,16 @@ static struct vfsmount *cifs_dfs_do_refmount(struct dentry *mntpt,
278289
return mnt;
279290
}
280291

281-
static void dump_referral(const struct dfs_info3_param *ref)
282-
{
283-
cifs_dbg(FYI, "DFS: ref path: %s\n", ref->path_name);
284-
cifs_dbg(FYI, "DFS: node path: %s\n", ref->node_name);
285-
cifs_dbg(FYI, "DFS: fl: %d, srv_type: %d\n",
286-
ref->flags, ref->server_type);
287-
cifs_dbg(FYI, "DFS: ref_flags: %d, path_consumed: %d\n",
288-
ref->ref_flag, ref->path_consumed);
289-
}
290-
291292
/*
292293
* Create a vfsmount that we can automount
293294
*/
294295
static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
295296
{
296-
struct dfs_info3_param referral = {0};
297297
struct cifs_sb_info *cifs_sb;
298298
struct cifs_ses *ses;
299299
struct cifs_tcon *tcon;
300300
char *full_path, *root_path;
301301
unsigned int xid;
302-
int len;
303302
int rc;
304303
struct vfsmount *mnt;
305304

@@ -357,7 +356,7 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
357356
if (!rc) {
358357
rc = dfs_cache_find(xid, ses, cifs_sb->local_nls,
359358
cifs_remap(cifs_sb), full_path + 1,
360-
&referral, NULL);
359+
NULL, NULL);
361360
}
362361

363362
free_xid(xid);
@@ -366,26 +365,16 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
366365
mnt = ERR_PTR(rc);
367366
goto free_root_path;
368367
}
369-
370-
dump_referral(&referral);
371-
372-
len = strlen(referral.node_name);
373-
if (len < 2) {
374-
cifs_dbg(VFS, "%s: Net Address path too short: %s\n",
375-
__func__, referral.node_name);
376-
mnt = ERR_PTR(-EINVAL);
377-
goto free_dfs_ref;
378-
}
379368
/*
380-
* cifs_mount() will retry every available node server in case
381-
* of failures.
369+
* OK - we were able to get and cache a referral for @full_path.
370+
*
371+
* Now, pass it down to cifs_mount() and it will retry every available
372+
* node server in case of failures - no need to do it here.
382373
*/
383-
mnt = cifs_dfs_do_refmount(mntpt, cifs_sb, full_path, &referral);
384-
cifs_dbg(FYI, "%s: cifs_dfs_do_refmount:%s , mnt:%p\n", __func__,
385-
referral.node_name, mnt);
374+
mnt = cifs_dfs_do_mount(mntpt, cifs_sb, full_path);
375+
cifs_dbg(FYI, "%s: cifs_dfs_do_mount:%s , mnt:%p\n", __func__,
376+
full_path + 1, mnt);
386377

387-
free_dfs_ref:
388-
free_dfs_info_param(&referral);
389378
free_root_path:
390379
kfree(root_path);
391380
free_full_path:

0 commit comments

Comments
 (0)