aboutsummaryrefslogtreecommitdiff
path: root/fs/cifs
diff options
context:
space:
mode:
authorJeff Layton2012-12-10 06:10:46 -0500
committerSteve French2012-12-11 11:48:50 -0600
commitd387a5c50bca619d56f276a69627c2e1c6e5c548 (patch)
tree86bc043af2734f67fabc1a3a1031a69e8ac31eaa /fs/cifs
parent839db3d10a5ba792d6533b8bb3380f52ac877344 (diff)
cifs: parse the device name into UNC and prepath
This should fix a regression that was introduced when the new mount option parser went in. Also, when the unc= and prefixpath= options are provided, check their values against the ones we parsed from the device string. If they differ, then throw a warning that tells the user that we're using the values from the unc= option for now, but that that will change in 3.10. Pavel Shilovsky <piastry@etersoft.ru> Signed-off-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Steve French <smfrench@gmail.com>
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/connect.c95
1 files changed, 88 insertions, 7 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 94c4484c9ea3..7635b5db26a7 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1096,6 +1096,52 @@ cifs_parse_smb_version(char *value, struct smb_vol *vol)
return 0;
}
+/*
+ * Parse a devname into substrings and populate the vol->UNC and vol->prepath
+ * fields with the result. Returns 0 on success and an error otherwise.
+ */
+static int
+cifs_parse_devname(const char *devname, struct smb_vol *vol)
+{
+ char *pos;
+ const char *delims = "/\\";
+ size_t len;
+
+ /* make sure we have a valid UNC double delimiter prefix */
+ len = strspn(devname, delims);
+ if (len != 2)
+ return -EINVAL;
+
+ /* find delimiter between host and sharename */
+ pos = strpbrk(devname + 2, delims);
+ if (!pos)
+ return -EINVAL;
+
+ /* skip past delimiter */
+ ++pos;
+
+ /* now go until next delimiter or end of string */
+ len = strcspn(pos, delims);
+
+ /* move "pos" up to delimiter or NULL */
+ pos += len;
+ vol->UNC = kstrndup(devname, pos - devname, GFP_KERNEL);
+ if (!vol->UNC)
+ return -ENOMEM;
+
+ convert_delimiter(vol->UNC, '\\');
+
+ /* If pos is NULL, or is a bogus trailing delimiter then no prepath */
+ if (!*pos++ || !*pos)
+ return 0;
+
+ vol->prepath = kstrdup(pos, GFP_KERNEL);
+ if (!vol->prepath)
+ return -ENOMEM;
+
+ return 0;
+}
+
static int
cifs_parse_mount_options(const char *mountdata, const char *devname,
struct smb_vol *vol)
@@ -1181,6 +1227,16 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
vol->backupuid_specified = false; /* no backup intent for a user */
vol->backupgid_specified = false; /* no backup intent for a group */
+ /*
+ * For now, we ignore -EINVAL errors under the assumption that the
+ * unc= and prefixpath= options will be usable.
+ */
+ if (cifs_parse_devname(devname, vol) == -ENOMEM) {
+ printk(KERN_ERR "CIFS: Unable to allocate memory to parse "
+ "device string.\n");
+ goto out_nomem;
+ }
+
while ((data = strsep(&options, separator)) != NULL) {
substring_t args[MAX_OPT_ARGS];
unsigned long option;
@@ -1566,18 +1622,31 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
got_ip = true;
break;
case Opt_unc:
- kfree(vol->UNC);
+ string = vol->UNC;
vol->UNC = match_strdup(args);
- if (vol->UNC == NULL)
+ if (vol->UNC == NULL) {
+ kfree(string);
goto out_nomem;
+ }
convert_delimiter(vol->UNC, '\\');
if (vol->UNC[0] != '\\' || vol->UNC[1] != '\\') {
- printk(KERN_WARNING "CIFS: UNC Path does not "
+ kfree(string);
+ printk(KERN_ERR "CIFS: UNC Path does not "
"begin with // or \\\\\n");
goto cifs_parse_mount_err;
}
+ /* Compare old unc= option to new one */
+ if (!string || strcmp(string, vol->UNC))
+ printk(KERN_WARNING "CIFS: the value of the "
+ "unc= mount option does not match the "
+ "device string. Using the unc= option "
+ "for now. In 3.10, that option will "
+ "be ignored and the contents of the "
+ "device string will be used "
+ "instead. (%s != %s)\n", string,
+ vol->UNC);
break;
case Opt_domain:
string = match_strdup(args);
@@ -1616,10 +1685,22 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
if (*args[0].from == '/' || *args[0].from == '\\')
args[0].from++;
- kfree(vol->prepath);
+ string = vol->prepath;
vol->prepath = match_strdup(args);
- if (vol->prepath == NULL)
+ if (vol->prepath == NULL) {
+ kfree(string);
goto out_nomem;
+ }
+ /* Compare old prefixpath= option to new one */
+ if (!string || strcmp(string, vol->prepath))
+ printk(KERN_WARNING "CIFS: the value of the "
+ "prefixpath= mount option does not "
+ "match the device string. Using the "
+ "prefixpath= option for now. In 3.10, "
+ "that option will be ignored and the "
+ "contents of the device string will be "
+ "used instead.(%s != %s)\n", string,
+ vol->prepath);
break;
case Opt_iocharset:
string = match_strdup(args);
@@ -1777,8 +1858,8 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
}
#endif
if (!vol->UNC) {
- cERROR(1, "CIFS mount error: No UNC path (e.g. -o "
- "unc=\\\\192.168.1.100\\public) specified");
+ cERROR(1, "CIFS mount error: No usable UNC path provided in "
+ "device string or in unc= option!");
goto cifs_parse_mount_err;
}