Commit abdb1742 authored by Paulo Alcantara's avatar Paulo Alcantara Committed by Steve French
Browse files

cifs: get rid of mount options string parsing



After switching to filesystem context support, we no longer need to
handle mount options string when chasing dfs referrals.  Now, we set
the new values directly into smb3_fs_context.

Start working on a separate source file to handle most dfs related
mount functions as connect.c has already became too big.  The
remaining functions will be moved gradually in follow-up patches.

Signed-off-by: default avatarPaulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 9fd29a5b
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -21,7 +21,7 @@ cifs-$(CONFIG_CIFS_XATTR) += xattr.o

cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o

cifs-$(CONFIG_CIFS_DFS_UPCALL) += cifs_dfs_ref.o dfs_cache.o
cifs-$(CONFIG_CIFS_DFS_UPCALL) += cifs_dfs_ref.o dfs_cache.o dfs.o

cifs-$(CONFIG_CIFS_SWN_UPCALL) += netlink.o cifs_swn.o

+1 −140
Original line number Diff line number Diff line
@@ -60,7 +60,7 @@ void cifs_dfs_release_automount_timer(void)
 * Returns pointer to the built string, or a ERR_PTR. Caller is responsible
 * for freeing the returned string.
 */
static char *
char *
cifs_build_devname(char *nodename, const char *prepath)
{
	size_t pplen;
@@ -119,145 +119,6 @@ cifs_build_devname(char *nodename, const char *prepath)
	return dev;
}


/**
 * cifs_compose_mount_options	-	creates mount options for referral
 * @sb_mountdata:	parent/root DFS mount options (template)
 * @fullpath:		full path in UNC format
 * @ref:		optional server's referral
 * @devname:		return the built cifs device name if passed pointer not NULL
 * creates mount options for submount based on template options sb_mountdata
 * and replacing unc,ip,prefixpath options with ones we've got form ref_unc.
 *
 * Returns: pointer to new mount options or ERR_PTR.
 * Caller is responsible for freeing returned value if it is not error.
 */
char *cifs_compose_mount_options(const char *sb_mountdata,
				 const char *fullpath,
				 const struct dfs_info3_param *ref,
				 char **devname)
{
	int rc;
	char *name;
	char *mountdata = NULL;
	const char *prepath = NULL;
	int md_len;
	char *tkn_e;
	char *srvIP = NULL;
	char sep = ',';
	int off, noff;

	if (sb_mountdata == NULL)
		return ERR_PTR(-EINVAL);

	if (ref) {
		if (WARN_ON_ONCE(!ref->node_name || ref->path_consumed < 0))
			return ERR_PTR(-EINVAL);

		if (strlen(fullpath) - ref->path_consumed) {
			prepath = fullpath + ref->path_consumed;
			/* skip initial delimiter */
			if (*prepath == '/' || *prepath == '\\')
				prepath++;
		}

		name = cifs_build_devname(ref->node_name, prepath);
		if (IS_ERR(name)) {
			rc = PTR_ERR(name);
			name = NULL;
			goto compose_mount_options_err;
		}
	} else {
		name = cifs_build_devname((char *)fullpath, NULL);
		if (IS_ERR(name)) {
			rc = PTR_ERR(name);
			name = NULL;
			goto compose_mount_options_err;
		}
	}

	rc = dns_resolve_server_name_to_ip(name, &srvIP, NULL);
	if (rc < 0) {
		cifs_dbg(FYI, "%s: Failed to resolve server part of %s to IP: %d\n",
			 __func__, name, rc);
		goto compose_mount_options_err;
	}

	/*
	 * In most cases, we'll be building a shorter string than the original,
	 * but we do have to assume that the address in the ip= option may be
	 * much longer than the original. Add the max length of an address
	 * string to the length of the original string to allow for worst case.
	 */
	md_len = strlen(sb_mountdata) + INET6_ADDRSTRLEN;
	mountdata = kzalloc(md_len + sizeof("ip=") + 1, GFP_KERNEL);
	if (mountdata == NULL) {
		rc = -ENOMEM;
		goto compose_mount_options_err;
	}

	/* copy all options except of unc,ip,prefixpath */
	off = 0;
	if (strncmp(sb_mountdata, "sep=", 4) == 0) {
			sep = sb_mountdata[4];
			strncpy(mountdata, sb_mountdata, 5);
			off += 5;
	}

	do {
		tkn_e = strchr(sb_mountdata + off, sep);
		if (tkn_e == NULL)
			noff = strlen(sb_mountdata + off);
		else
			noff = tkn_e - (sb_mountdata + off) + 1;

		if (strncasecmp(sb_mountdata + off, "cruid=", 6) == 0) {
			off += noff;
			continue;
		}
		if (strncasecmp(sb_mountdata + off, "unc=", 4) == 0) {
			off += noff;
			continue;
		}
		if (strncasecmp(sb_mountdata + off, "ip=", 3) == 0) {
			off += noff;
			continue;
		}
		if (strncasecmp(sb_mountdata + off, "prefixpath=", 11) == 0) {
			off += noff;
			continue;
		}
		strncat(mountdata, sb_mountdata + off, noff);
		off += noff;
	} while (tkn_e);
	strcat(mountdata, sb_mountdata + off);
	mountdata[md_len] = '\0';

	/* copy new IP and ref share name */
	if (mountdata[strlen(mountdata) - 1] != sep)
		strncat(mountdata, &sep, 1);
	strcat(mountdata, "ip=");
	strcat(mountdata, srvIP);

	if (devname)
		*devname = name;
	else
		kfree(name);

	/*cifs_dbg(FYI, "%s: parent mountdata: %s\n", __func__, sb_mountdata);*/
	/*cifs_dbg(FYI, "%s: submount mountdata: %s\n", __func__, mountdata );*/

compose_mount_options_out:
	kfree(srvIP);
	return mountdata;

compose_mount_options_err:
	kfree(mountdata);
	mountdata = ERR_PTR(rc);
	kfree(name);
	goto compose_mount_options_out;
}

/*
 * Create a vfsmount that we can automount
 */
+0 −6
Original line number Diff line number Diff line
@@ -896,12 +896,6 @@ cifs_smb3_do_mount(struct file_system_type *fs_type,
		goto out;
	}

	rc = cifs_setup_volume_info(cifs_sb->ctx, NULL, NULL);
	if (rc) {
		root = ERR_PTR(rc);
		goto out;
	}

	rc = cifs_setup_cifs_sb(cifs_sb);
	if (rc) {
		root = ERR_PTR(rc);
+1 −6
Original line number Diff line number Diff line
@@ -75,9 +75,7 @@ extern char *cifs_build_path_to_root(struct smb3_fs_context *ctx,
				     struct cifs_tcon *tcon,
				     int add_treename);
extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
extern char *cifs_compose_mount_options(const char *sb_mountdata,
		const char *fullpath, const struct dfs_info3_param *ref,
		char **devname);
char *cifs_build_devname(char *nodename, const char *prepath);
extern void delete_mid(struct mid_q_entry *mid);
extern void release_mid(struct mid_q_entry *mid);
extern void cifs_wake_up_task(struct mid_q_entry *mid);
@@ -561,9 +559,6 @@ extern int check_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
extern int E_md4hash(const unsigned char *passwd, unsigned char *p16,
			const struct nls_table *codepage);

extern int
cifs_setup_volume_info(struct smb3_fs_context *ctx, const char *mntopts, const char *devname);

extern struct TCP_Server_Info *
cifs_find_tcp_session(struct smb3_fs_context *ctx);

+6 −94
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@
#include "smbdirect.h"
#include "dns_resolve.h"
#ifdef CONFIG_CIFS_DFS_UPCALL
#include "dfs.h"
#include "dfs_cache.h"
#endif
#include "fs_context.h"
@@ -3397,95 +3398,8 @@ build_unc_path_to_root(const struct smb3_fs_context *ctx,
	cifs_dbg(FYI, "%s: full_path=%s\n", __func__, full_path);
	return full_path;
}

/*
 * expand_dfs_referral - Update cifs_sb from dfs referral path
 *
 * cifs_sb->ctx->mount_options will be (re-)allocated to a string containing updated options for the
 * submount.  Otherwise it will be left untouched.
 */
static int expand_dfs_referral(struct mount_ctx *mnt_ctx, const char *full_path,
			       struct dfs_info3_param *referral)
{
	int rc;
	struct cifs_sb_info *cifs_sb = mnt_ctx->cifs_sb;
	struct smb3_fs_context *ctx = mnt_ctx->fs_ctx;
	char *fake_devname = NULL, *mdata = NULL;

	mdata = cifs_compose_mount_options(cifs_sb->ctx->mount_options, full_path + 1, referral,
					   &fake_devname);
	if (IS_ERR(mdata)) {
		rc = PTR_ERR(mdata);
		mdata = NULL;
	} else {
		/*
		 * We can not clear out the whole structure since we no longer have an explicit
		 * function to parse a mount-string. Instead we need to clear out the individual
		 * fields that are no longer valid.
		 */
		kfree(ctx->prepath);
		ctx->prepath = NULL;
		rc = cifs_setup_volume_info(ctx, mdata, fake_devname);
	}
	kfree(fake_devname);
	kfree(cifs_sb->ctx->mount_options);
	cifs_sb->ctx->mount_options = mdata;

	return rc;
}
#endif

/* TODO: all callers to this are broken. We are not parsing mount_options here
 * we should pass a clone of the original context?
 */
int
cifs_setup_volume_info(struct smb3_fs_context *ctx, const char *mntopts, const char *devname)
{
	int rc;

	if (devname) {
		cifs_dbg(FYI, "%s: devname=%s\n", __func__, devname);
		rc = smb3_parse_devname(devname, ctx);
		if (rc) {
			cifs_dbg(VFS, "%s: failed to parse %s: %d\n", __func__, devname, rc);
			return rc;
		}
	}

	if (mntopts) {
		char *ip;

		rc = smb3_parse_opt(mntopts, "ip", &ip);
		if (rc) {
			cifs_dbg(VFS, "%s: failed to parse ip options: %d\n", __func__, rc);
			return rc;
		}

		rc = cifs_convert_address((struct sockaddr *)&ctx->dstaddr, ip, strlen(ip));
		kfree(ip);
		if (!rc) {
			cifs_dbg(VFS, "%s: failed to convert ip address\n", __func__);
			return -EINVAL;
		}
	}

	if (ctx->nullauth) {
		cifs_dbg(FYI, "Anonymous login\n");
		kfree(ctx->username);
		ctx->username = NULL;
	} else if (ctx->username) {
		/* BB fixme parse for domain name here */
		cifs_dbg(FYI, "Username: %s\n", ctx->username);
	} else {
		cifs_dbg(VFS, "No username specified\n");
	/* In userspace mount helper we can get user name from alternate
	   locations such as env variables and files on disk */
		return -EINVAL;
	}

	return 0;
}

static int
cifs_are_all_path_components_accessible(struct TCP_Server_Info *server,
					unsigned int xid,
@@ -3630,7 +3544,6 @@ static int connect_dfs_target(struct mount_ctx *mnt_ctx, const char *full_path,
	int rc;
	struct dfs_info3_param ref = {};
	struct cifs_sb_info *cifs_sb = mnt_ctx->cifs_sb;
	char *oldmnt = cifs_sb->ctx->mount_options;

	cifs_dbg(FYI, "%s: full_path=%s ref_path=%s target=%s\n", __func__, full_path, ref_path,
		 dfs_cache_get_tgt_name(tit));
@@ -3639,15 +3552,14 @@ static int connect_dfs_target(struct mount_ctx *mnt_ctx, const char *full_path,
	if (rc)
		goto out;

	rc = expand_dfs_referral(mnt_ctx, full_path, &ref);
	rc = dfs_parse_target_referral(full_path + 1, &ref, mnt_ctx->fs_ctx);
	if (rc)
		goto out;

	/* Connect to new target only if we were redirected (e.g. mount options changed) */
	if (oldmnt != cifs_sb->ctx->mount_options) {
	/* XXX: maybe check if we were actually redirected and avoid reconnecting? */
	mount_put_conns(mnt_ctx);
	rc = mount_get_dfs_conns(mnt_ctx);
	}

	if (!rc) {
		if (cifs_is_referral_server(mnt_ctx->tcon, &ref))
			set_root_ses(mnt_ctx);
Loading