All of lore.kernel.org
 help / color / mirror / Atom feed
* [v2 1/4] CIFS: Simplify connection structure search calls
@ 2011-05-05  9:55 Pavel Shilovsky
       [not found] ` <1304589314-1147-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
  0 siblings, 1 reply; 9+ messages in thread
From: Pavel Shilovsky @ 2011-05-05  9:55 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Use separate functions for comparison between existing structure
and what we are requesting for to make server, session and tcon
search code easier to use on next superblock match call.

Reviewed-by: Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
 fs/cifs/connect.c |   90 +++++++++++++++++++++++++++++++++--------------------
 1 files changed, 56 insertions(+), 34 deletions(-)

diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 389dd9f..c19a110 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1650,6 +1650,25 @@ match_security(struct TCP_Server_Info *server, struct smb_vol *vol)
 	return true;
 }
 
+static int match_server(struct TCP_Server_Info *server, struct sockaddr *addr,
+			 struct smb_vol *vol)
+{
+	if (!net_eq(cifs_net_ns(server), current->nsproxy->net_ns))
+		return 0;
+
+	if (!match_address(server, addr,
+			   (struct sockaddr *)&vol->srcaddr))
+		return 0;
+
+	if (!match_port(server, addr))
+		return 0;
+
+	if (!match_security(server, vol))
+		return 0;
+
+	return 1;
+}
+
 static struct TCP_Server_Info *
 cifs_find_tcp_session(struct sockaddr *addr, struct smb_vol *vol)
 {
@@ -1657,17 +1676,7 @@ cifs_find_tcp_session(struct sockaddr *addr, struct smb_vol *vol)
 
 	spin_lock(&cifs_tcp_ses_lock);
 	list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
-		if (!net_eq(cifs_net_ns(server), current->nsproxy->net_ns))
-			continue;
-
-		if (!match_address(server, addr,
-				   (struct sockaddr *)&vol->srcaddr))
-			continue;
-
-		if (!match_port(server, addr))
-			continue;
-
-		if (!match_security(server, vol))
+		if (!match_server(server, addr, vol))
 			continue;
 
 		++server->srv_count;
@@ -1861,6 +1870,30 @@ out_err:
 	return ERR_PTR(rc);
 }
 
+static int match_session(struct cifsSesInfo *ses, struct smb_vol *vol)
+{
+	switch (ses->server->secType) {
+	case Kerberos:
+		if (vol->cred_uid != ses->cred_uid)
+			return 0;
+		break;
+	default:
+		/* anything else takes username/password */
+		if (ses->user_name == NULL)
+			return 0;
+		if (strncmp(ses->user_name, vol->username,
+			    MAX_USERNAME_SIZE))
+			return 0;
+		if (strlen(vol->username) != 0 &&
+		    ses->password != NULL &&
+		    strncmp(ses->password,
+			    vol->password ? vol->password : "",
+			    MAX_PASSWORD_SIZE))
+			return 0;
+	}
+	return 1;
+}
+
 static struct cifsSesInfo *
 cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol)
 {
@@ -1868,25 +1901,8 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol)
 
 	spin_lock(&cifs_tcp_ses_lock);
 	list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
-		switch (server->secType) {
-		case Kerberos:
-			if (vol->cred_uid != ses->cred_uid)
-				continue;
-			break;
-		default:
-			/* anything else takes username/password */
-			if (ses->user_name == NULL)
-				continue;
-			if (strncmp(ses->user_name, vol->username,
-				    MAX_USERNAME_SIZE))
-				continue;
-			if (strlen(vol->username) != 0 &&
-			    ses->password != NULL &&
-			    strncmp(ses->password,
-				    vol->password ? vol->password : "",
-				    MAX_PASSWORD_SIZE))
-				continue;
-		}
+		if (!match_session(ses, vol))
+			continue;
 		++ses->ses_count;
 		spin_unlock(&cifs_tcp_ses_lock);
 		return ses;
@@ -2029,6 +2045,15 @@ get_ses_fail:
 	return ERR_PTR(rc);
 }
 
+static int match_tcon(struct cifsTconInfo *tcon, const char *unc)
+{
+	if (tcon->tidStatus == CifsExiting)
+		return 0;
+	if (strncmp(tcon->treeName, unc, MAX_TREE_SIZE))
+		return 0;
+	return 1;
+}
+
 static struct cifsTconInfo *
 cifs_find_tcon(struct cifsSesInfo *ses, const char *unc)
 {
@@ -2038,11 +2063,8 @@ cifs_find_tcon(struct cifsSesInfo *ses, const char *unc)
 	spin_lock(&cifs_tcp_ses_lock);
 	list_for_each(tmp, &ses->tcon_list) {
 		tcon = list_entry(tmp, struct cifsTconInfo, tcon_list);
-		if (tcon->tidStatus == CifsExiting)
+		if (!match_tcon(tcon, unc))
 			continue;
-		if (strncmp(tcon->treeName, unc, MAX_TREE_SIZE))
-			continue;
-
 		++tcon->tc_count;
 		spin_unlock(&cifs_tcp_ses_lock);
 		return tcon;
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [v2 2/4] CIFS: Simplify mount code for further shared sb capability
       [not found] ` <1304589314-1147-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
@ 2011-05-05  9:55   ` Pavel Shilovsky
  2011-05-05  9:55   ` [v2 3/4] CIFS: Migrate from prefixpath logic Pavel Shilovsky
  2011-05-05  9:55   ` [v2 4/4] CIFS: Migrate to shared superblock model Pavel Shilovsky
  2 siblings, 0 replies; 9+ messages in thread
From: Pavel Shilovsky @ 2011-05-05  9:55 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Reorganize code to get mount option at first and when get a superblock.
This lets us use shared superblock model further for equal mounts.

Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
 fs/cifs/cifsfs.c    |   88 ++++++++++++++++++++++++++++++++------------------
 fs/cifs/cifsproto.h |    8 ++++-
 fs/cifs/connect.c   |   89 ++++++++++++++++++++++++++++----------------------
 3 files changed, 114 insertions(+), 71 deletions(-)

diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 2b8e47e..c422a0e 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -104,19 +104,16 @@ cifs_sb_deactive(struct super_block *sb)
 }
 
 static int
-cifs_read_super(struct super_block *sb, void *data,
-		const char *devname, int silent)
+cifs_read_super(struct super_block *sb, struct cifs_sb_info *cifs_sb,
+		void *data, struct smb_vol *volume_info, const char *devname,
+		int silent)
 {
 	struct inode *inode;
-	struct cifs_sb_info *cifs_sb;
 	int rc = 0;
 
 	/* BB should we make this contingent on mount parm? */
 	sb->s_flags |= MS_NODIRATIME | MS_NOATIME;
-	sb->s_fs_info = kzalloc(sizeof(struct cifs_sb_info), GFP_KERNEL);
-	cifs_sb = CIFS_SB(sb);
-	if (cifs_sb == NULL)
-		return -ENOMEM;
+	sb->s_fs_info = cifs_sb;
 
 	spin_lock_init(&cifs_sb->tlink_tree_lock);
 	cifs_sb->tlink_tree = RB_ROOT;
@@ -128,22 +125,10 @@ cifs_read_super(struct super_block *sb, void *data,
 	}
 	cifs_sb->bdi.ra_pages = default_backing_dev_info.ra_pages;
 
-	/*
-	 * Copy mount params to sb for use in submounts. Better to do
-	 * the copy here and deal with the error before cleanup gets
-	 * complicated post-mount.
-	 */
-	if (data) {
-		cifs_sb->mountdata = kstrndup(data, PAGE_SIZE, GFP_KERNEL);
-		if (cifs_sb->mountdata == NULL) {
-			bdi_destroy(&cifs_sb->bdi);
-			kfree(sb->s_fs_info);
-			sb->s_fs_info = NULL;
-			return -ENOMEM;
-		}
-	}
+	if (data)
+		cifs_sb->mountdata = data;
 
-	rc = cifs_mount(sb, cifs_sb, devname);
+	rc = cifs_mount(sb, cifs_sb, volume_info, devname);
 
 	if (rc) {
 		if (!silent)
@@ -561,27 +546,68 @@ static const struct super_operations cifs_super_ops = {
 
 static struct dentry *
 cifs_do_mount(struct file_system_type *fs_type,
-	    int flags, const char *dev_name, void *data)
+	      int flags, const char *dev_name, void *data)
 {
 	int rc;
 	struct super_block *sb;
-
-	sb = sget(fs_type, NULL, set_anon_super, NULL);
+	struct cifs_sb_info *cifs_sb;
+	struct smb_vol *volume_info;
+	struct dentry *root;
+	char *copied_data = NULL;
 
 	cFYI(1, "Devname: %s flags: %d ", dev_name, flags);
 
-	if (IS_ERR(sb))
-		return ERR_CAST(sb);
+	rc = cifs_setup_volume_info(&volume_info, (char *)data, dev_name);
+	if (rc)
+		return ERR_PTR(rc);
+
+	cifs_sb = kzalloc(sizeof(struct cifs_sb_info), GFP_KERNEL);
+	if (cifs_sb == NULL) {
+		root = ERR_PTR(-ENOMEM);
+		goto out;
+	}
+
+	cifs_setup_cifs_sb(volume_info, cifs_sb);
+
+	sb = sget(fs_type, NULL, set_anon_super, NULL);
+	if (IS_ERR(sb)) {
+		kfree(cifs_sb);
+		root = ERR_CAST(sb);
+		goto out;
+	}
 
 	sb->s_flags = flags;
 
-	rc = cifs_read_super(sb, data, dev_name, flags & MS_SILENT ? 1 : 0);
+	/*
+	 * Copy mount params for use in submounts. Better to do
+	 * the copy here and deal with the error before cleanup gets
+	 * complicated post-mount.
+	 */
+	copied_data = kstrndup(data, PAGE_SIZE, GFP_KERNEL);
+	if (copied_data == NULL) {
+		root = ERR_PTR(-ENOMEM);
+		goto err_out;
+	}
+
+	rc = cifs_read_super(sb, cifs_sb, copied_data, volume_info, dev_name,
+			     flags & MS_SILENT ? 1 : 0);
 	if (rc) {
-		deactivate_locked_super(sb);
-		return ERR_PTR(rc);
+		root = ERR_PTR(rc);
+		goto err_out;
 	}
+
 	sb->s_flags |= MS_ACTIVE;
-	return dget(sb->s_root);
+
+	root = dget(sb->s_root);
+out:
+	cifs_cleanup_volume_info(&volume_info);
+	return root;
+
+err_out:
+	kfree(cifs_sb);
+	deactivate_locked_super(sb);
+	cifs_cleanup_volume_info(&volume_info);
+	return root;
 }
 
 static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index a1c94d3..d2eec0d 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -148,8 +148,14 @@ extern struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *, struct inode *,
 extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *,
 				const char *);
 
+extern void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
+			       struct cifs_sb_info *cifs_sb);
+extern int cifs_match_super(struct super_block *, void *);
+extern void cifs_cleanup_volume_info(struct smb_vol **pvolume_info);
+extern int cifs_setup_volume_info(struct smb_vol **pvolume_info,
+				  char *mount_data, const char *devname);
 extern int cifs_mount(struct super_block *, struct cifs_sb_info *,
-			const char *);
+		      struct smb_vol *, const char *);
 extern int cifs_umount(struct super_block *, struct cifs_sb_info *);
 extern void cifs_dfs_release_automount_timer(void);
 void cifs_proc_init(void);
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index c19a110..d74e4cd 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -2622,8 +2622,8 @@ convert_delimiter(char *path, char delim)
 	}
 }
 
-static void setup_cifs_sb(struct smb_vol *pvolume_info,
-			  struct cifs_sb_info *cifs_sb)
+void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
+			struct cifs_sb_info *cifs_sb)
 {
 	INIT_DELAYED_WORK(&cifs_sb->prune_tlinks, cifs_prune_tlinks);
 
@@ -2679,6 +2679,7 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info,
 		cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode);
 
 	cifs_sb->actimeo = pvolume_info->actimeo;
+	cifs_sb->local_nls = pvolume_info->local_nls;
 
 	if (pvolume_info->noperm)
 		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
@@ -2750,8 +2751,8 @@ is_path_accessible(int xid, struct cifsTconInfo *tcon,
 	return rc;
 }
 
-static void
-cleanup_volume_info(struct smb_vol **pvolume_info)
+void
+cifs_cleanup_volume_info(struct smb_vol **pvolume_info)
 {
 	struct smb_vol *volume_info;
 
@@ -2857,40 +2858,13 @@ expand_dfs_referral(int xid, struct cifsSesInfo *pSesInfo,
 }
 #endif
 
-int
-cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
-		const char *devname)
+int cifs_setup_volume_info(struct smb_vol **pvolume_info, char *mount_data,
+			   const char *devname)
 {
-	int rc;
-	int xid;
 	struct smb_vol *volume_info;
-	struct cifsSesInfo *pSesInfo;
-	struct cifsTconInfo *tcon;
-	struct TCP_Server_Info *srvTcp;
-	char   *full_path;
-	struct tcon_link *tlink;
-#ifdef CONFIG_CIFS_DFS_UPCALL
-	int referral_walks_count = 0;
-try_mount_again:
-	/* cleanup activities if we're chasing a referral */
-	if (referral_walks_count) {
-		if (tcon)
-			cifs_put_tcon(tcon);
-		else if (pSesInfo)
-			cifs_put_smb_ses(pSesInfo);
-
-		cleanup_volume_info(&volume_info);
-		FreeXid(xid);
-	}
-#endif
-	rc = 0;
-	tcon = NULL;
-	pSesInfo = NULL;
-	srvTcp = NULL;
-	full_path = NULL;
-	tlink = NULL;
+	int rc = 0;
 
-	xid = GetXid();
+	*pvolume_info = NULL;
 
 	volume_info = kzalloc(sizeof(struct smb_vol), GFP_KERNEL);
 	if (!volume_info) {
@@ -2898,7 +2872,7 @@ try_mount_again:
 		goto out;
 	}
 
-	if (cifs_parse_mount_options(cifs_sb->mountdata, devname,
+	if (cifs_parse_mount_options(mount_data, devname,
 				     volume_info)) {
 		rc = -EINVAL;
 		goto out;
@@ -2931,7 +2905,46 @@ try_mount_again:
 			goto out;
 		}
 	}
-	cifs_sb->local_nls = volume_info->local_nls;
+
+	*pvolume_info = volume_info;
+	return rc;
+out:
+	cifs_cleanup_volume_info(&volume_info);
+	return rc;
+}
+
+int
+cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
+	   struct smb_vol *volume_info, const char *devname)
+{
+	int rc = 0;
+	int xid;
+	struct cifsSesInfo *pSesInfo;
+	struct cifsTconInfo *tcon;
+	struct TCP_Server_Info *srvTcp;
+	char   *full_path;
+	struct tcon_link *tlink;
+#ifdef CONFIG_CIFS_DFS_UPCALL
+	int referral_walks_count = 0;
+try_mount_again:
+	/* cleanup activities if we're chasing a referral */
+	if (referral_walks_count) {
+		if (tcon)
+			cifs_put_tcon(tcon);
+		else if (pSesInfo)
+			cifs_put_smb_ses(pSesInfo);
+
+		cifs_cleanup_volume_info(&volume_info);
+		FreeXid(xid);
+	}
+#endif
+	tcon = NULL;
+	pSesInfo = NULL;
+	srvTcp = NULL;
+	full_path = NULL;
+	tlink = NULL;
+
+	xid = GetXid();
 
 	/* get a reference to a tcp session */
 	srvTcp = cifs_get_tcp_session(volume_info);
@@ -2948,7 +2961,6 @@ try_mount_again:
 		goto mount_fail_check;
 	}
 
-	setup_cifs_sb(volume_info, cifs_sb);
 	if (pSesInfo->capabilities & CAP_LARGE_FILES)
 		sb->s_maxbytes = MAX_LFS_FILESIZE;
 	else
@@ -3104,7 +3116,6 @@ mount_fail_check:
 	password will be freed at unmount time) */
 out:
 	/* zero out password before freeing */
-	cleanup_volume_info(&volume_info);
 	FreeXid(xid);
 	return rc;
 }
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [v2 3/4] CIFS: Migrate from prefixpath logic
       [not found] ` <1304589314-1147-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
  2011-05-05  9:55   ` [v2 2/4] CIFS: Simplify mount code for further shared sb capability Pavel Shilovsky
@ 2011-05-05  9:55   ` Pavel Shilovsky
       [not found]     ` <1304589314-1147-3-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
  2011-05-05  9:55   ` [v2 4/4] CIFS: Migrate to shared superblock model Pavel Shilovsky
  2 siblings, 1 reply; 9+ messages in thread
From: Pavel Shilovsky @ 2011-05-05  9:55 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Now we point superblock to a server share root and set a root dentry
appropriately. This let us share superblock between mounts like
//server/sharename/foo/bar and //server/sharename/foo further.

Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
 fs/cifs/cifs_fs_sb.h |    2 -
 fs/cifs/cifsfs.c     |  103 ++++++++++++++++++++++++++++++++++++++-
 fs/cifs/cifsglob.h   |   76 +++++++++++++++++++++++++++++
 fs/cifs/cifsproto.h  |    5 +-
 fs/cifs/connect.c    |  129 ++------------------------------------------------
 fs/cifs/dir.c        |    7 +--
 fs/cifs/inode.c      |   19 ++-----
 7 files changed, 192 insertions(+), 149 deletions(-)

diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
index a9d5692..c96b44b 100644
--- a/fs/cifs/cifs_fs_sb.h
+++ b/fs/cifs/cifs_fs_sb.h
@@ -56,8 +56,6 @@ struct cifs_sb_info {
 	mode_t	mnt_file_mode;
 	mode_t	mnt_dir_mode;
 	unsigned int mnt_cifs_flags;
-	int	prepathlen;
-	char   *prepath; /* relative path under the share to mount to */
 	char   *mountdata; /* options received at mount time or via DFS refs */
 	struct backing_dev_info bdi;
 	struct delayed_work prune_tlinks;
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index c422a0e..446b5c2 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -429,8 +429,6 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m)
 		seq_printf(s, ",nocase");
 	if (tcon->retry)
 		seq_printf(s, ",hard");
-	if (cifs_sb->prepath)
-		seq_printf(s, ",prepath=%s", cifs_sb->prepath);
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
 		seq_printf(s, ",posixpaths");
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)
@@ -544,6 +542,100 @@ static const struct super_operations cifs_super_ops = {
 #endif
 };
 
+/*
+ * Get root dentry from superblock according to prefix path mount option.
+ * Return dentry with refcount + 1 on success and NULL otherwise.
+ */
+static struct dentry *
+cifs_get_root(struct smb_vol *vol, struct super_block *sb)
+{
+	int xid, rc;
+	struct inode *inode;
+	struct qstr name;
+	struct dentry *dparent = NULL, *dchild = NULL, *alias;
+	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+	unsigned int i, full_len, len;
+	char *full_path = NULL, *pstart;
+	char sep;
+
+	full_path = cifs_build_path_to_root(vol, cifs_sb,
+					    cifs_sb_master_tcon(cifs_sb));
+	if (full_path == NULL)
+		return NULL;
+
+	cFYI(1, "Get root dentry for %s", full_path);
+
+	xid = GetXid();
+	sep = CIFS_DIR_SEP(cifs_sb);
+	dparent = dget(sb->s_root);
+	full_len = strlen(full_path);
+	full_path[full_len] = sep;
+	pstart = full_path + 1;
+
+	for (i = 1, len = 0; i <= full_len; i++) {
+		if (full_path[i] != sep || !len) {
+			len++;
+			continue;
+		}
+
+		full_path[i] = 0;
+		cFYI(1, "get dentry for %s", pstart);
+
+		name.name = pstart;
+		name.len = len;
+		name.hash = full_name_hash(pstart, len);
+		dchild = d_lookup(dparent, &name);
+		if (dchild == NULL) {
+			cFYI(1, "not exists");
+			dchild = d_alloc(dparent, &name);
+			if (dchild == NULL) {
+				dput(dparent);
+				dparent = NULL;
+				goto out;
+			}
+		}
+
+		cFYI(1, "get inode");
+		if (dchild->d_inode == NULL) {
+			cFYI(1, "not exists");
+			inode = NULL;
+			if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext)
+				rc = cifs_get_inode_info_unix(&inode, full_path,
+							      sb, xid);
+			else
+				rc = cifs_get_inode_info(&inode, full_path,
+							 NULL, sb, xid, NULL);
+			if (rc) {
+				dput(dchild);
+				dput(dparent);
+				dparent = NULL;
+				goto out;
+			}
+			alias = d_materialise_unique(dchild, inode);
+			if (alias != NULL) {
+				dput(dchild);
+				if (IS_ERR(alias)) {
+					dput(dparent);
+					dparent = NULL;
+					goto out;
+				}
+				dchild = alias;
+			}
+		}
+		cFYI(1, "parent %p, child %p", dparent, dchild);
+
+		dput(dparent);
+		dparent = dchild;
+		len = 0;
+		pstart = full_path + i + 1;
+		full_path[i] = sep;
+	}
+out:
+	_FreeXid(xid);
+	kfree(full_path);
+	return dparent;
+}
+
 static struct dentry *
 cifs_do_mount(struct file_system_type *fs_type,
 	      int flags, const char *dev_name, void *data)
@@ -598,7 +690,12 @@ cifs_do_mount(struct file_system_type *fs_type,
 
 	sb->s_flags |= MS_ACTIVE;
 
-	root = dget(sb->s_root);
+	root = cifs_get_root(volume_info, sb);
+	if (root == NULL) {
+		kfree(copied_data);
+		goto err_out;
+	}
+	cFYI(1, "dentry root is: %p", root);
 out:
 	cifs_cleanup_volume_info(&volume_info);
 	return root;
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 76b4517..7ad7d69 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -155,6 +155,62 @@ struct cifs_cred {
  *****************************************************************
  */
 
+struct smb_vol {
+	char *username;
+	char *password;
+	char *domainname;
+	char *UNC;
+	char *UNCip;
+	char *iocharset;  /* local code page for mapping to and from Unicode */
+	char source_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* clnt nb name */
+	char target_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* srvr nb name */
+	uid_t cred_uid;
+	uid_t linux_uid;
+	gid_t linux_gid;
+	mode_t file_mode;
+	mode_t dir_mode;
+	unsigned secFlg;
+	bool retry:1;
+	bool intr:1;
+	bool setuids:1;
+	bool override_uid:1;
+	bool override_gid:1;
+	bool dynperm:1;
+	bool noperm:1;
+	bool no_psx_acl:1; /* set if posix acl support should be disabled */
+	bool cifs_acl:1;
+	bool no_xattr:1;   /* set if xattr (EA) support should be disabled*/
+	bool server_ino:1; /* use inode numbers from server ie UniqueId */
+	bool direct_io:1;
+	bool strict_io:1; /* strict cache behavior */
+	bool remap:1;      /* set to remap seven reserved chars in filenames */
+	bool posix_paths:1; /* unset to not ask for posix pathnames. */
+	bool no_linux_ext:1;
+	bool sfu_emul:1;
+	bool nullauth:1;   /* attempt to authenticate with null user */
+	bool nocase:1;     /* request case insensitive filenames */
+	bool nobrl:1;      /* disable sending byte range locks to srv */
+	bool mand_lock:1;  /* send mandatory not posix byte range lock reqs */
+	bool seal:1;       /* request transport encryption on share */
+	bool nodfs:1;      /* Do not request DFS, even if available */
+	bool local_lease:1; /* check leases only on local system, not remote */
+	bool noblocksnd:1;
+	bool noautotune:1;
+	bool nostrictsync:1; /* do not force expensive SMBflush on every sync */
+	bool fsc:1;	/* enable fscache */
+	bool mfsymlinks:1; /* use Minshall+French Symlinks */
+	bool multiuser:1;
+	bool use_smb2:1; /* force smb2 use on mount instead of cifs */
+	unsigned int rsize;
+	unsigned int wsize;
+	bool sockopt_tcp_nodelay:1;
+	unsigned short int port;
+	unsigned long actimeo; /* attribute cache timeout (jiffies) */
+	char *prepath;
+	struct sockaddr_storage srcaddr; /* allow binding to a local IP */
+	struct nls_table *local_nls;
+};
+
 struct TCP_Server_Info {
 	struct list_head tcp_ses_list;
 	struct list_head smb_ses_list;
@@ -509,6 +565,26 @@ static inline char CIFS_DIR_SEP(const struct cifs_sb_info *cifs_sb)
 		return '\\';
 }
 
+static inline void
+convert_delimiter(char *path, char delim)
+{
+	int i;
+	char old_delim;
+
+	if (path == NULL)
+		return;
+
+	if (delim == '/')
+		old_delim = '\\';
+	else
+		old_delim = '/';
+
+	for (i = 0; path[i] != '\0'; i++) {
+		if (path[i] == old_delim)
+			path[i] = delim;
+	}
+}
+
 #ifdef CONFIG_CIFS_STATS
 #define cifs_stats_inc atomic_inc
 
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index d2eec0d..65d5bf7 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -57,8 +57,9 @@ extern int init_cifs_idmap(void);
 extern void exit_cifs_idmap(void);
 extern void cifs_destroy_idmaptrees(void);
 extern char *build_path_from_dentry(struct dentry *);
-extern char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb,
-					struct cifsTconInfo *tcon);
+extern char *cifs_build_path_to_root(struct smb_vol *vol,
+				     struct cifs_sb_info *cifs_sb,
+				     struct cifsTconInfo *tcon);
 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,
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index d74e4cd..1cacfaa 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -57,62 +57,6 @@
 
 extern mempool_t *cifs_req_poolp;
 
-struct smb_vol {
-	char *username;
-	char *password;
-	char *domainname;
-	char *UNC;
-	char *UNCip;
-	char *iocharset;  /* local code page for mapping to and from Unicode */
-	char source_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* clnt nb name */
-	char target_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* srvr nb name */
-	uid_t cred_uid;
-	uid_t linux_uid;
-	gid_t linux_gid;
-	mode_t file_mode;
-	mode_t dir_mode;
-	unsigned secFlg;
-	bool retry:1;
-	bool intr:1;
-	bool setuids:1;
-	bool override_uid:1;
-	bool override_gid:1;
-	bool dynperm:1;
-	bool noperm:1;
-	bool no_psx_acl:1; /* set if posix acl support should be disabled */
-	bool cifs_acl:1;
-	bool no_xattr:1;   /* set if xattr (EA) support should be disabled*/
-	bool server_ino:1; /* use inode numbers from server ie UniqueId */
-	bool direct_io:1;
-	bool strict_io:1; /* strict cache behavior */
-	bool remap:1;      /* set to remap seven reserved chars in filenames */
-	bool posix_paths:1; /* unset to not ask for posix pathnames. */
-	bool no_linux_ext:1;
-	bool sfu_emul:1;
-	bool nullauth:1;   /* attempt to authenticate with null user */
-	bool nocase:1;     /* request case insensitive filenames */
-	bool nobrl:1;      /* disable sending byte range locks to srv */
-	bool mand_lock:1;  /* send mandatory not posix byte range lock reqs */
-	bool seal:1;       /* request transport encryption on share */
-	bool nodfs:1;      /* Do not request DFS, even if available */
-	bool local_lease:1; /* check leases only on local system, not remote */
-	bool noblocksnd:1;
-	bool noautotune:1;
-	bool nostrictsync:1; /* do not force expensive SMBflush on every sync */
-	bool fsc:1;	/* enable fscache */
-	bool mfsymlinks:1; /* use Minshall+French Symlinks */
-	bool multiuser:1;
-	bool use_smb2:1; /* force smb2 use on mount instead of cifs */
-	unsigned int rsize;
-	unsigned int wsize;
-	bool sockopt_tcp_nodelay:1;
-	unsigned short int port;
-	unsigned long actimeo; /* attribute cache timeout (jiffies) */
-	char *prepath;
-	struct sockaddr_storage srcaddr; /* allow binding to a local IP */
-	struct nls_table *local_nls;
-};
-
 /* FIXME: should these be tunable? */
 #define TLINK_ERROR_EXPIRE	(1 * HZ)
 #define TLINK_IDLE_EXPIRE	(600 * HZ)
@@ -2556,12 +2500,6 @@ void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
 					CIFS_MOUNT_POSIX_PATHS;
 		}
 
-		/* We might be setting the path sep back to a different
-		form if we are reconnecting and the server switched its
-		posix path capability for this share */
-		if (sb && (CIFS_SB(sb)->prepathlen > 0))
-			CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
-
 		if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) {
 			if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) {
 				CIFS_SB(sb)->rsize = 127 * 1024;
@@ -2602,26 +2540,6 @@ void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
 	}
 }
 
-static void
-convert_delimiter(char *path, char delim)
-{
-	int i;
-	char old_delim;
-
-	if (path == NULL)
-		return;
-
-	if (delim == '/')
-		old_delim = '\\';
-	else
-		old_delim = '/';
-
-	for (i = 0; path[i] != '\0'; i++) {
-		if (path[i] == old_delim)
-			path[i] = delim;
-	}
-}
-
 void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
 			struct cifs_sb_info *cifs_sb)
 {
@@ -2659,18 +2577,6 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
 		/* Windows ME may prefer this */
 		cFYI(1, "readsize set to minimum: 2048");
 	}
-	/* calculate prepath */
-	cifs_sb->prepath = pvolume_info->prepath;
-	if (cifs_sb->prepath) {
-		cifs_sb->prepathlen = strlen(cifs_sb->prepath);
-		/* we can not convert the / to \ in the path
-		separators in the prefixpath yet because we do not
-		know (until reset_cifs_unix_caps is called later)
-		whether POSIX PATH CAP is available. We normalize
-		the / to \ after reset_cifs_unix_caps is called */
-		pvolume_info->prepath = NULL;
-	} else
-		cifs_sb->prepathlen = 0;
 	cifs_sb->mnt_uid = pvolume_info->linux_uid;
 	cifs_sb->mnt_gid = pvolume_info->linux_gid;
 	cifs_sb->mnt_file_mode = pvolume_info->file_mode;
@@ -2782,24 +2688,13 @@ build_unc_path_to_root(const struct smb_vol *volume_info,
 	char *full_path;
 
 	int unc_len = strnlen(volume_info->UNC, MAX_TREE_SIZE + 1);
-	full_path = kmalloc(unc_len + cifs_sb->prepathlen + 1, GFP_KERNEL);
+	full_path = kmalloc(unc_len + 1, GFP_KERNEL);
 	if (full_path == NULL)
 		return ERR_PTR(-ENOMEM);
 
 	strncpy(full_path, volume_info->UNC, unc_len);
-	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
-		int i;
-		for (i = 0; i < unc_len; i++) {
-			if (full_path[i] == '\\')
-				full_path[i] = '/';
-		}
-	}
-
-	if (cifs_sb->prepathlen)
-		strncpy(full_path + unc_len, cifs_sb->prepath,
-				cifs_sb->prepathlen);
-
-	full_path[unc_len + cifs_sb->prepathlen] = 0; /* add trailing null */
+	full_path[unc_len] = 0; /* add trailing null */
+	convert_delimiter(full_path, CIFS_DIR_SEP(cifs_sb));
 	return full_path;
 }
 
@@ -2991,10 +2886,6 @@ try_mount_again:
 	else
 		tcon->unix_ext = 0; /* server does not support them */
 
-	/* convert forward to back slashes in prepath here if needed */
-	if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
-		convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb));
-
 	if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
 		cifs_sb->rsize = 1024 * 127;
 		cFYI(DBG2, "no very large read support, rsize now 127K");
@@ -3025,10 +2916,10 @@ remote_path_check:
 	}
 #endif
 
-	/* check if a whole path (including prepath) is not remote */
+	/* check if a whole path is not remote */
 	if (!rc && tcon) {
 		/* build_path_to_root works only when we have a valid tcon */
-		full_path = cifs_build_path_to_root(cifs_sb, tcon);
+		full_path = cifs_build_path_to_root(volume_info, cifs_sb, tcon);
 		if (full_path == NULL) {
 			rc = -ENOMEM;
 			goto mount_fail_check;
@@ -3054,10 +2945,6 @@ remote_path_check:
 			rc = -ELOOP;
 			goto mount_fail_check;
 		}
-		/* convert forward to back slashes in prepath here if needed */
-		if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
-			convert_delimiter(cifs_sb->prepath,
-					CIFS_DIR_SEP(cifs_sb));
 
 		rc = expand_dfs_referral(xid, pSesInfo, volume_info, cifs_sb,
 					 true);
@@ -3283,7 +3170,6 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
 	struct rb_root *root = &cifs_sb->tlink_tree;
 	struct rb_node *node;
 	struct tcon_link *tlink;
-	char *tmp;
 
 	cancel_delayed_work_sync(&cifs_sb->prune_tlinks);
 
@@ -3300,11 +3186,6 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
 	}
 	spin_unlock(&cifs_sb->tlink_tree_lock);
 
-	tmp = cifs_sb->prepath;
-	cifs_sb->prepathlen = 0;
-	cifs_sb->prepath = NULL;
-	kfree(tmp);
-
 	return 0;
 }
 
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 9ea65cf..c33446d 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -50,7 +50,6 @@ build_path_from_dentry(struct dentry *direntry)
 {
 	struct dentry *temp;
 	int namelen;
-	int pplen;
 	int dfsplen;
 	char *full_path;
 	char dirsep;
@@ -63,13 +62,12 @@ build_path_from_dentry(struct dentry *direntry)
 		when the server crashed */
 
 	dirsep = CIFS_DIR_SEP(cifs_sb);
-	pplen = cifs_sb->prepathlen;
 	if (tcon->Flags & SMB_SHARE_IS_IN_DFS)
 		dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1);
 	else
 		dfsplen = 0;
 cifs_bp_rename_retry:
-	namelen = pplen + dfsplen;
+	namelen = dfsplen;
 	for (temp = direntry; !IS_ROOT(temp);) {
 		namelen += (1 + temp->d_name.len);
 		temp = temp->d_parent;
@@ -100,7 +98,7 @@ cifs_bp_rename_retry:
 			return NULL;
 		}
 	}
-	if (namelen != pplen + dfsplen) {
+	if (namelen != dfsplen) {
 		cERROR(1, "did not end path lookup where expected namelen is %d",
 			namelen);
 		/* presumably this is only possible if racing with a rename
@@ -126,7 +124,6 @@ cifs_bp_rename_retry:
 			}
 		}
 	}
-	strncpy(full_path + dfsplen, CIFS_SB(direntry->d_sb)->prepath, pplen);
 	return full_path;
 }
 
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 0cc7edd..b08a416 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -735,10 +735,10 @@ static const struct inode_operations cifs_ipc_inode_ops = {
 	.lookup = cifs_lookup,
 };
 
-char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb,
-				struct cifsTconInfo *tcon)
+char *cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
+			      struct cifsTconInfo *tcon)
 {
-	int pplen = cifs_sb->prepathlen;
+	int pplen = vol->prepath ? strlen(vol->prepath) : 0;
 	int dfsplen;
 	char *full_path = NULL;
 
@@ -772,7 +772,7 @@ char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb,
 			}
 		}
 	}
-	strncpy(full_path + dfsplen, cifs_sb->prepath, pplen);
+	strncpy(full_path + dfsplen, vol->prepath, pplen);
 	full_path[dfsplen + pplen] = 0; /* add trailing null */
 	return full_path;
 }
@@ -884,19 +884,13 @@ struct inode *cifs_root_iget(struct super_block *sb)
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
 	struct inode *inode = NULL;
 	long rc;
-	char *full_path;
 	struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb);
 
-	full_path = cifs_build_path_to_root(cifs_sb, tcon);
-	if (full_path == NULL)
-		return ERR_PTR(-ENOMEM);
-
 	xid = GetXid();
 	if (tcon->unix_ext)
-		rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);
+		rc = cifs_get_inode_info_unix(&inode, "", sb, xid);
 	else
-		rc = cifs_get_inode_info(&inode, full_path, NULL, sb,
-						xid, NULL);
+		rc = cifs_get_inode_info(&inode, "", NULL, sb, xid, NULL);
 
 	if (!inode) {
 		inode = ERR_PTR(rc);
@@ -922,7 +916,6 @@ struct inode *cifs_root_iget(struct super_block *sb)
 	}
 
 out:
-	kfree(full_path);
 	/* can not call macro FreeXid here since in a void func
 	 * TODO: This is no longer true
 	 */
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [v2 4/4] CIFS: Migrate to shared superblock model
       [not found] ` <1304589314-1147-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
  2011-05-05  9:55   ` [v2 2/4] CIFS: Simplify mount code for further shared sb capability Pavel Shilovsky
  2011-05-05  9:55   ` [v2 3/4] CIFS: Migrate from prefixpath logic Pavel Shilovsky
@ 2011-05-05  9:55   ` Pavel Shilovsky
       [not found]     ` <1304589314-1147-4-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
  2 siblings, 1 reply; 9+ messages in thread
From: Pavel Shilovsky @ 2011-05-05  9:55 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Add cifs_match_super to use in sget to share superblock between mounts
that have the same //server/sharename, credentials and mount options.
It helps us to improve performance on work with future SMB2.1 leases.

Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
 fs/cifs/cifsfs.c   |   18 ++++++++++-
 fs/cifs/cifsglob.h |    5 +++
 fs/cifs/connect.c  |   90 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 112 insertions(+), 1 deletions(-)

diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 446b5c2..ba0b7ae 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -644,6 +644,7 @@ cifs_do_mount(struct file_system_type *fs_type,
 	struct super_block *sb;
 	struct cifs_sb_info *cifs_sb;
 	struct smb_vol *volume_info;
+	struct cifs_mnt_data mnt_data;
 	struct dentry *root;
 	char *copied_data = NULL;
 
@@ -661,13 +662,21 @@ cifs_do_mount(struct file_system_type *fs_type,
 
 	cifs_setup_cifs_sb(volume_info, cifs_sb);
 
-	sb = sget(fs_type, NULL, set_anon_super, NULL);
+	mnt_data.vol = volume_info;
+	mnt_data.cifs_sb = cifs_sb;
+
+	sb = sget(fs_type, cifs_match_super, set_anon_super, &mnt_data);
 	if (IS_ERR(sb)) {
 		kfree(cifs_sb);
 		root = ERR_CAST(sb);
 		goto out;
 	}
 
+	if (sb->s_fs_info) {
+		cFYI(1, "Use existing superblock");
+		goto out_shared;
+	}
+
 	sb->s_flags = flags;
 
 	/*
@@ -700,6 +709,13 @@ out:
 	cifs_cleanup_volume_info(&volume_info);
 	return root;
 
+out_shared:
+	root = cifs_get_root(volume_info, sb);
+	if (root)
+		cFYI(1, "dentry root is: %p", root);
+	cifs_cleanup_volume_info(&volume_info);
+	return root;
+
 err_out:
 	kfree(cifs_sb);
 	deactivate_locked_super(sb);
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 7ad7d69..55901b0 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -211,6 +211,11 @@ struct smb_vol {
 	struct nls_table *local_nls;
 };
 
+struct cifs_mnt_data {
+	struct cifs_sb_info *cifs_sb;
+	struct smb_vol *vol;
+};
+
 struct TCP_Server_Info {
 	struct list_head tcp_ses_list;
 	struct list_head smb_ses_list;
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 1cacfaa..1d39dcf 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -2135,6 +2135,96 @@ cifs_put_tlink(struct tcon_link *tlink)
 	return;
 }
 
+static inline struct tcon_link *
+cifs_sb_master_tlink(struct cifs_sb_info *cifs_sb);
+
+static const u32 ACTUAL_MOUNT_FLAGS = CIFS_MOUNT_NO_PERM | CIFS_MOUNT_SET_UID |
+	CIFS_MOUNT_SERVER_INUM | CIFS_MOUNT_DIRECT_IO | CIFS_MOUNT_NO_XATTR |
+	CIFS_MOUNT_MAP_SPECIAL_CHR | CIFS_MOUNT_UNX_EMUL | CIFS_MOUNT_NO_BRL |
+	CIFS_MOUNT_CIFS_ACL | CIFS_MOUNT_OVERR_UID | CIFS_MOUNT_OVERR_GID |
+	CIFS_MOUNT_DYNPERM | CIFS_MOUNT_NOPOSIXBRL | CIFS_MOUNT_NOSSYNC |
+	CIFS_MOUNT_FSCACHE | CIFS_MOUNT_MF_SYMLINKS | CIFS_MOUNT_MULTIUSER |
+	CIFS_MOUNT_STRICT_IO;
+
+static int
+compare_mount_options(struct cifs_sb_info *old, struct cifs_sb_info *new)
+{
+	if ((old->mnt_cifs_flags & ACTUAL_MOUNT_FLAGS) !=
+	    (new->mnt_cifs_flags & ACTUAL_MOUNT_FLAGS))
+		return 0;
+
+	if (old->rsize != new->rsize || old->wsize != new->wsize)
+		return 0;
+
+	if (old->mnt_uid != new->mnt_uid || old->mnt_gid != new->mnt_gid)
+		return 0;
+
+	if (old->mnt_file_mode != new->mnt_file_mode ||
+	    old->mnt_dir_mode != new->mnt_dir_mode)
+		return 0;
+
+	if (strcmp(old->local_nls->charset, new->local_nls->charset))
+		return 0;
+
+	if (old->actimeo != new->actimeo)
+		return 0;
+
+	return 1;
+}
+
+int
+cifs_match_super(struct super_block *sb, void *data)
+{
+	struct cifs_mnt_data *mnt_data = (struct cifs_mnt_data *)data;
+	struct smb_vol *volume_info;
+	struct cifs_sb_info *cifs_sb, *new_cifs_sb;
+	struct TCP_Server_Info *tcp_srv;
+	struct cifsSesInfo *ses;
+	struct cifsTconInfo *tcon;
+	struct tcon_link *tlink;
+	struct sockaddr_storage addr;
+	int rc = 0;
+
+	memset(&addr, 0, sizeof(struct sockaddr_storage));
+
+	spin_lock(&cifs_tcp_ses_lock);
+	cifs_sb = CIFS_SB(sb);
+	tlink = cifs_get_tlink(cifs_sb_master_tlink(cifs_sb));
+	if (IS_ERR(tlink)) {
+		spin_unlock(&cifs_tcp_ses_lock);
+		return rc;
+	}
+	tcon = tlink_tcon(tlink);
+	ses = tcon->ses;
+	tcp_srv = ses->server;
+
+	volume_info = mnt_data->vol;
+	new_cifs_sb = mnt_data->cifs_sb;
+
+	if (!volume_info->UNCip || !volume_info->UNC)
+		goto out;
+
+	rc = cifs_fill_sockaddr((struct sockaddr *)&addr,
+				volume_info->UNCip,
+				strlen(volume_info->UNCip),
+				volume_info->port);
+	if (!rc)
+		goto out;
+
+	if (!match_server(tcp_srv, (struct sockaddr *)&addr, volume_info) ||
+	    !match_session(ses, volume_info) ||
+	    !match_tcon(tcon, volume_info->UNC)) {
+		rc = 0;
+		goto out;
+	}
+
+	rc = compare_mount_options(cifs_sb, new_cifs_sb);
+out:
+	cifs_put_tlink(tlink);
+	spin_unlock(&cifs_tcp_ses_lock);
+	return rc;
+}
+
 int
 get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
 	     const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [v2 3/4] CIFS: Migrate from prefixpath logic
       [not found]     ` <1304589314-1147-3-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
@ 2011-05-24 11:11       ` Jeff Layton
  0 siblings, 0 replies; 9+ messages in thread
From: Jeff Layton @ 2011-05-24 11:11 UTC (permalink / raw)
  To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA

On Thu,  5 May 2011 13:55:13 +0400
Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:

> Now we point superblock to a server share root and set a root dentry
> appropriately. This let us share superblock between mounts like
> //server/sharename/foo/bar and //server/sharename/foo further.
> 
> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
> ---
>  fs/cifs/cifs_fs_sb.h |    2 -
>  fs/cifs/cifsfs.c     |  103 ++++++++++++++++++++++++++++++++++++++-
>  fs/cifs/cifsglob.h   |   76 +++++++++++++++++++++++++++++
>  fs/cifs/cifsproto.h  |    5 +-
>  fs/cifs/connect.c    |  129 ++------------------------------------------------
>  fs/cifs/dir.c        |    7 +--
>  fs/cifs/inode.c      |   19 ++-----
>  7 files changed, 192 insertions(+), 149 deletions(-)
> 
> diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
> index a9d5692..c96b44b 100644
> --- a/fs/cifs/cifs_fs_sb.h
> +++ b/fs/cifs/cifs_fs_sb.h
> @@ -56,8 +56,6 @@ struct cifs_sb_info {
>  	mode_t	mnt_file_mode;
>  	mode_t	mnt_dir_mode;
>  	unsigned int mnt_cifs_flags;
> -	int	prepathlen;
> -	char   *prepath; /* relative path under the share to mount to */
>  	char   *mountdata; /* options received at mount time or via DFS refs */
>  	struct backing_dev_info bdi;
>  	struct delayed_work prune_tlinks;
> diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
> index c422a0e..446b5c2 100644
> --- a/fs/cifs/cifsfs.c
> +++ b/fs/cifs/cifsfs.c
> @@ -429,8 +429,6 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m)
>  		seq_printf(s, ",nocase");
>  	if (tcon->retry)
>  		seq_printf(s, ",hard");
> -	if (cifs_sb->prepath)
> -		seq_printf(s, ",prepath=%s", cifs_sb->prepath);

	You're removing the display of the prepath in /proc/mounts, but
	leaving the option parsing for this in place. That seems
	wrong...

	Ultimately, I think the right answer is to eventually get rid
	of the UNC= and prepath= mount options and simply parse the
	"device" string, but that's really a separate project since it
	may require some coordination with mount.cifs changes.

>  	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
>  		seq_printf(s, ",posixpaths");
>  	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)
> @@ -544,6 +542,100 @@ static const struct super_operations cifs_super_ops = {
>  #endif
>  };
>  
> +/*
> + * Get root dentry from superblock according to prefix path mount option.
> + * Return dentry with refcount + 1 on success and NULL otherwise.
> + */
> +static struct dentry *
> +cifs_get_root(struct smb_vol *vol, struct super_block *sb)
> +{
> +	int xid, rc;
> +	struct inode *inode;
> +	struct qstr name;
> +	struct dentry *dparent = NULL, *dchild = NULL, *alias;
> +	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
> +	unsigned int i, full_len, len;
> +	char *full_path = NULL, *pstart;
> +	char sep;
> +
> +	full_path = cifs_build_path_to_root(vol, cifs_sb,
> +					    cifs_sb_master_tcon(cifs_sb));
> +	if (full_path == NULL)
> +		return NULL;
> +
> +	cFYI(1, "Get root dentry for %s", full_path);
> +
> +	xid = GetXid();
> +	sep = CIFS_DIR_SEP(cifs_sb);
> +	dparent = dget(sb->s_root);
> +	full_len = strlen(full_path);
> +	full_path[full_len] = sep;
> +	pstart = full_path + 1;
> +
> +	for (i = 1, len = 0; i <= full_len; i++) {
> +		if (full_path[i] != sep || !len) {
> +			len++;
> +			continue;
> +		}
> +
> +		full_path[i] = 0;
> +		cFYI(1, "get dentry for %s", pstart);
> +
> +		name.name = pstart;
> +		name.len = len;
> +		name.hash = full_name_hash(pstart, len);
> +		dchild = d_lookup(dparent, &name);
> +		if (dchild == NULL) {
> +			cFYI(1, "not exists");
> +			dchild = d_alloc(dparent, &name);
> +			if (dchild == NULL) {
> +				dput(dparent);
> +				dparent = NULL;
> +				goto out;
> +			}
> +		}
> +
> +		cFYI(1, "get inode");
> +		if (dchild->d_inode == NULL) {
> +			cFYI(1, "not exists");
> +			inode = NULL;
> +			if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext)
> +				rc = cifs_get_inode_info_unix(&inode, full_path,
> +							      sb, xid);
> +			else
> +				rc = cifs_get_inode_info(&inode, full_path,
> +							 NULL, sb, xid, NULL);
> +			if (rc) {
> +				dput(dchild);
> +				dput(dparent);
> +				dparent = NULL;
> +				goto out;
> +			}
> +			alias = d_materialise_unique(dchild, inode);
> +			if (alias != NULL) {
> +				dput(dchild);
> +				if (IS_ERR(alias)) {
> +					dput(dparent);
> +					dparent = NULL;
> +					goto out;
> +				}
> +				dchild = alias;
> +			}
> +		}
> +		cFYI(1, "parent %p, child %p", dparent, dchild);
> +
> +		dput(dparent);
> +		dparent = dchild;
> +		len = 0;
> +		pstart = full_path + i + 1;
> +		full_path[i] = sep;
> +	}
> +out:
> +	_FreeXid(xid);
> +	kfree(full_path);
> +	return dparent;
> +}
> +
>  static struct dentry *
>  cifs_do_mount(struct file_system_type *fs_type,
>  	      int flags, const char *dev_name, void *data)
> @@ -598,7 +690,12 @@ cifs_do_mount(struct file_system_type *fs_type,
>  
>  	sb->s_flags |= MS_ACTIVE;
>  
> -	root = dget(sb->s_root);
> +	root = cifs_get_root(volume_info, sb);
> +	if (root == NULL) {
> +		kfree(copied_data);
> +		goto err_out;
> +	}
> +	cFYI(1, "dentry root is: %p", root);
>  out:
>  	cifs_cleanup_volume_info(&volume_info);
>  	return root;
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index 76b4517..7ad7d69 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -155,6 +155,62 @@ struct cifs_cred {
>   *****************************************************************
>   */
>  
> +struct smb_vol {
> +	char *username;
> +	char *password;
> +	char *domainname;
> +	char *UNC;
> +	char *UNCip;
> +	char *iocharset;  /* local code page for mapping to and from Unicode */
> +	char source_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* clnt nb name */
> +	char target_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* srvr nb name */
> +	uid_t cred_uid;
> +	uid_t linux_uid;
> +	gid_t linux_gid;
> +	mode_t file_mode;
> +	mode_t dir_mode;
> +	unsigned secFlg;
> +	bool retry:1;
> +	bool intr:1;
> +	bool setuids:1;
> +	bool override_uid:1;
> +	bool override_gid:1;
> +	bool dynperm:1;
> +	bool noperm:1;
> +	bool no_psx_acl:1; /* set if posix acl support should be disabled */
> +	bool cifs_acl:1;
> +	bool no_xattr:1;   /* set if xattr (EA) support should be disabled*/
> +	bool server_ino:1; /* use inode numbers from server ie UniqueId */
> +	bool direct_io:1;
> +	bool strict_io:1; /* strict cache behavior */
> +	bool remap:1;      /* set to remap seven reserved chars in filenames */
> +	bool posix_paths:1; /* unset to not ask for posix pathnames. */
> +	bool no_linux_ext:1;
> +	bool sfu_emul:1;
> +	bool nullauth:1;   /* attempt to authenticate with null user */
> +	bool nocase:1;     /* request case insensitive filenames */
> +	bool nobrl:1;      /* disable sending byte range locks to srv */
> +	bool mand_lock:1;  /* send mandatory not posix byte range lock reqs */
> +	bool seal:1;       /* request transport encryption on share */
> +	bool nodfs:1;      /* Do not request DFS, even if available */
> +	bool local_lease:1; /* check leases only on local system, not remote */
> +	bool noblocksnd:1;
> +	bool noautotune:1;
> +	bool nostrictsync:1; /* do not force expensive SMBflush on every sync */
> +	bool fsc:1;	/* enable fscache */
> +	bool mfsymlinks:1; /* use Minshall+French Symlinks */
> +	bool multiuser:1;
> +	bool use_smb2:1; /* force smb2 use on mount instead of cifs */
> +	unsigned int rsize;
> +	unsigned int wsize;
> +	bool sockopt_tcp_nodelay:1;
> +	unsigned short int port;
> +	unsigned long actimeo; /* attribute cache timeout (jiffies) */
> +	char *prepath;
> +	struct sockaddr_storage srcaddr; /* allow binding to a local IP */
> +	struct nls_table *local_nls;
> +};
> +
>  struct TCP_Server_Info {
>  	struct list_head tcp_ses_list;
>  	struct list_head smb_ses_list;
> @@ -509,6 +565,26 @@ static inline char CIFS_DIR_SEP(const struct cifs_sb_info *cifs_sb)
>  		return '\\';
>  }
>  
> +static inline void
> +convert_delimiter(char *path, char delim)
> +{
> +	int i;
> +	char old_delim;
> +
> +	if (path == NULL)
> +		return;
> +
> +	if (delim == '/')
> +		old_delim = '\\';
> +	else
> +		old_delim = '/';
> +
> +	for (i = 0; path[i] != '\0'; i++) {
> +		if (path[i] == old_delim)
> +			path[i] = delim;
> +	}
> +}
> +
>  #ifdef CONFIG_CIFS_STATS
>  #define cifs_stats_inc atomic_inc
>  
> diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
> index d2eec0d..65d5bf7 100644
> --- a/fs/cifs/cifsproto.h
> +++ b/fs/cifs/cifsproto.h
> @@ -57,8 +57,9 @@ extern int init_cifs_idmap(void);
>  extern void exit_cifs_idmap(void);
>  extern void cifs_destroy_idmaptrees(void);
>  extern char *build_path_from_dentry(struct dentry *);
> -extern char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb,
> -					struct cifsTconInfo *tcon);
> +extern char *cifs_build_path_to_root(struct smb_vol *vol,
> +				     struct cifs_sb_info *cifs_sb,
> +				     struct cifsTconInfo *tcon);
>  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,
> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
> index d74e4cd..1cacfaa 100644
> --- a/fs/cifs/connect.c
> +++ b/fs/cifs/connect.c
> @@ -57,62 +57,6 @@
>  
>  extern mempool_t *cifs_req_poolp;
>  
> -struct smb_vol {
> -	char *username;
> -	char *password;
> -	char *domainname;
> -	char *UNC;
> -	char *UNCip;
> -	char *iocharset;  /* local code page for mapping to and from Unicode */
> -	char source_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* clnt nb name */
> -	char target_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* srvr nb name */
> -	uid_t cred_uid;
> -	uid_t linux_uid;
> -	gid_t linux_gid;
> -	mode_t file_mode;
> -	mode_t dir_mode;
> -	unsigned secFlg;
> -	bool retry:1;
> -	bool intr:1;
> -	bool setuids:1;
> -	bool override_uid:1;
> -	bool override_gid:1;
> -	bool dynperm:1;
> -	bool noperm:1;
> -	bool no_psx_acl:1; /* set if posix acl support should be disabled */
> -	bool cifs_acl:1;
> -	bool no_xattr:1;   /* set if xattr (EA) support should be disabled*/
> -	bool server_ino:1; /* use inode numbers from server ie UniqueId */
> -	bool direct_io:1;
> -	bool strict_io:1; /* strict cache behavior */
> -	bool remap:1;      /* set to remap seven reserved chars in filenames */
> -	bool posix_paths:1; /* unset to not ask for posix pathnames. */
> -	bool no_linux_ext:1;
> -	bool sfu_emul:1;
> -	bool nullauth:1;   /* attempt to authenticate with null user */
> -	bool nocase:1;     /* request case insensitive filenames */
> -	bool nobrl:1;      /* disable sending byte range locks to srv */
> -	bool mand_lock:1;  /* send mandatory not posix byte range lock reqs */
> -	bool seal:1;       /* request transport encryption on share */
> -	bool nodfs:1;      /* Do not request DFS, even if available */
> -	bool local_lease:1; /* check leases only on local system, not remote */
> -	bool noblocksnd:1;
> -	bool noautotune:1;
> -	bool nostrictsync:1; /* do not force expensive SMBflush on every sync */
> -	bool fsc:1;	/* enable fscache */
> -	bool mfsymlinks:1; /* use Minshall+French Symlinks */
> -	bool multiuser:1;
> -	bool use_smb2:1; /* force smb2 use on mount instead of cifs */
> -	unsigned int rsize;
> -	unsigned int wsize;
> -	bool sockopt_tcp_nodelay:1;
> -	unsigned short int port;
> -	unsigned long actimeo; /* attribute cache timeout (jiffies) */
> -	char *prepath;
> -	struct sockaddr_storage srcaddr; /* allow binding to a local IP */
> -	struct nls_table *local_nls;
> -};
> -
>  /* FIXME: should these be tunable? */
>  #define TLINK_ERROR_EXPIRE	(1 * HZ)
>  #define TLINK_IDLE_EXPIRE	(600 * HZ)
> @@ -2556,12 +2500,6 @@ void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
>  					CIFS_MOUNT_POSIX_PATHS;
>  		}
>  
> -		/* We might be setting the path sep back to a different
> -		form if we are reconnecting and the server switched its
> -		posix path capability for this share */
> -		if (sb && (CIFS_SB(sb)->prepathlen > 0))
> -			CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
> -
>  		if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) {
>  			if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) {
>  				CIFS_SB(sb)->rsize = 127 * 1024;
> @@ -2602,26 +2540,6 @@ void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
>  	}
>  }
>  
> -static void
> -convert_delimiter(char *path, char delim)
> -{
> -	int i;
> -	char old_delim;
> -
> -	if (path == NULL)
> -		return;
> -
> -	if (delim == '/')
> -		old_delim = '\\';
> -	else
> -		old_delim = '/';
> -
> -	for (i = 0; path[i] != '\0'; i++) {
> -		if (path[i] == old_delim)
> -			path[i] = delim;
> -	}
> -}
> -
>  void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
>  			struct cifs_sb_info *cifs_sb)
>  {
> @@ -2659,18 +2577,6 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
>  		/* Windows ME may prefer this */
>  		cFYI(1, "readsize set to minimum: 2048");
>  	}
> -	/* calculate prepath */
> -	cifs_sb->prepath = pvolume_info->prepath;
> -	if (cifs_sb->prepath) {
> -		cifs_sb->prepathlen = strlen(cifs_sb->prepath);
> -		/* we can not convert the / to \ in the path
> -		separators in the prefixpath yet because we do not
> -		know (until reset_cifs_unix_caps is called later)
> -		whether POSIX PATH CAP is available. We normalize
> -		the / to \ after reset_cifs_unix_caps is called */
> -		pvolume_info->prepath = NULL;
> -	} else
> -		cifs_sb->prepathlen = 0;
>  	cifs_sb->mnt_uid = pvolume_info->linux_uid;
>  	cifs_sb->mnt_gid = pvolume_info->linux_gid;
>  	cifs_sb->mnt_file_mode = pvolume_info->file_mode;
> @@ -2782,24 +2688,13 @@ build_unc_path_to_root(const struct smb_vol *volume_info,
>  	char *full_path;
>  
>  	int unc_len = strnlen(volume_info->UNC, MAX_TREE_SIZE + 1);
> -	full_path = kmalloc(unc_len + cifs_sb->prepathlen + 1, GFP_KERNEL);
> +	full_path = kmalloc(unc_len + 1, GFP_KERNEL);
>  	if (full_path == NULL)
>  		return ERR_PTR(-ENOMEM);
>  
>  	strncpy(full_path, volume_info->UNC, unc_len);
> -	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
> -		int i;
> -		for (i = 0; i < unc_len; i++) {
> -			if (full_path[i] == '\\')
> -				full_path[i] = '/';
> -		}
> -	}
> -
> -	if (cifs_sb->prepathlen)
> -		strncpy(full_path + unc_len, cifs_sb->prepath,
> -				cifs_sb->prepathlen);
> -
> -	full_path[unc_len + cifs_sb->prepathlen] = 0; /* add trailing null */
> +	full_path[unc_len] = 0; /* add trailing null */
> +	convert_delimiter(full_path, CIFS_DIR_SEP(cifs_sb));
>  	return full_path;
>  }
>  
> @@ -2991,10 +2886,6 @@ try_mount_again:
>  	else
>  		tcon->unix_ext = 0; /* server does not support them */
>  
> -	/* convert forward to back slashes in prepath here if needed */
> -	if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
> -		convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb));
> -
>  	if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
>  		cifs_sb->rsize = 1024 * 127;
>  		cFYI(DBG2, "no very large read support, rsize now 127K");
> @@ -3025,10 +2916,10 @@ remote_path_check:
>  	}
>  #endif
>  
> -	/* check if a whole path (including prepath) is not remote */
> +	/* check if a whole path is not remote */
>  	if (!rc && tcon) {
>  		/* build_path_to_root works only when we have a valid tcon */
> -		full_path = cifs_build_path_to_root(cifs_sb, tcon);
> +		full_path = cifs_build_path_to_root(volume_info, cifs_sb, tcon);
>  		if (full_path == NULL) {
>  			rc = -ENOMEM;
>  			goto mount_fail_check;
> @@ -3054,10 +2945,6 @@ remote_path_check:
>  			rc = -ELOOP;
>  			goto mount_fail_check;
>  		}
> -		/* convert forward to back slashes in prepath here if needed */
> -		if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
> -			convert_delimiter(cifs_sb->prepath,
> -					CIFS_DIR_SEP(cifs_sb));
>  
>  		rc = expand_dfs_referral(xid, pSesInfo, volume_info, cifs_sb,
>  					 true);
> @@ -3283,7 +3170,6 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
>  	struct rb_root *root = &cifs_sb->tlink_tree;
>  	struct rb_node *node;
>  	struct tcon_link *tlink;
> -	char *tmp;
>  
>  	cancel_delayed_work_sync(&cifs_sb->prune_tlinks);
>  
> @@ -3300,11 +3186,6 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
>  	}
>  	spin_unlock(&cifs_sb->tlink_tree_lock);
>  
> -	tmp = cifs_sb->prepath;
> -	cifs_sb->prepathlen = 0;
> -	cifs_sb->prepath = NULL;
> -	kfree(tmp);
> -
>  	return 0;
>  }
>  
> diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
> index 9ea65cf..c33446d 100644
> --- a/fs/cifs/dir.c
> +++ b/fs/cifs/dir.c
> @@ -50,7 +50,6 @@ build_path_from_dentry(struct dentry *direntry)
>  {
>  	struct dentry *temp;
>  	int namelen;
> -	int pplen;
>  	int dfsplen;
>  	char *full_path;
>  	char dirsep;
> @@ -63,13 +62,12 @@ build_path_from_dentry(struct dentry *direntry)
>  		when the server crashed */
>  
>  	dirsep = CIFS_DIR_SEP(cifs_sb);
> -	pplen = cifs_sb->prepathlen;
>  	if (tcon->Flags & SMB_SHARE_IS_IN_DFS)
>  		dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1);
>  	else
>  		dfsplen = 0;
>  cifs_bp_rename_retry:
> -	namelen = pplen + dfsplen;
> +	namelen = dfsplen;
>  	for (temp = direntry; !IS_ROOT(temp);) {
>  		namelen += (1 + temp->d_name.len);
>  		temp = temp->d_parent;
> @@ -100,7 +98,7 @@ cifs_bp_rename_retry:
>  			return NULL;
>  		}
>  	}
> -	if (namelen != pplen + dfsplen) {
> +	if (namelen != dfsplen) {
>  		cERROR(1, "did not end path lookup where expected namelen is %d",
>  			namelen);
>  		/* presumably this is only possible if racing with a rename
> @@ -126,7 +124,6 @@ cifs_bp_rename_retry:
>  			}
>  		}
>  	}
> -	strncpy(full_path + dfsplen, CIFS_SB(direntry->d_sb)->prepath, pplen);
>  	return full_path;
>  }
>  
> diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
> index 0cc7edd..b08a416 100644
> --- a/fs/cifs/inode.c
> +++ b/fs/cifs/inode.c
> @@ -735,10 +735,10 @@ static const struct inode_operations cifs_ipc_inode_ops = {
>  	.lookup = cifs_lookup,
>  };
>  
> -char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb,
> -				struct cifsTconInfo *tcon)
> +char *cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
> +			      struct cifsTconInfo *tcon)
>  {
> -	int pplen = cifs_sb->prepathlen;
> +	int pplen = vol->prepath ? strlen(vol->prepath) : 0;
>  	int dfsplen;
>  	char *full_path = NULL;
>  
> @@ -772,7 +772,7 @@ char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb,
>  			}
>  		}
>  	}
> -	strncpy(full_path + dfsplen, cifs_sb->prepath, pplen);
> +	strncpy(full_path + dfsplen, vol->prepath, pplen);
>  	full_path[dfsplen + pplen] = 0; /* add trailing null */
>  	return full_path;
>  }
> @@ -884,19 +884,13 @@ struct inode *cifs_root_iget(struct super_block *sb)
>  	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
>  	struct inode *inode = NULL;
>  	long rc;
> -	char *full_path;
>  	struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb);
>  
> -	full_path = cifs_build_path_to_root(cifs_sb, tcon);
> -	if (full_path == NULL)
> -		return ERR_PTR(-ENOMEM);
> -
>  	xid = GetXid();
>  	if (tcon->unix_ext)
> -		rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);
> +		rc = cifs_get_inode_info_unix(&inode, "", sb, xid);
>  	else
> -		rc = cifs_get_inode_info(&inode, full_path, NULL, sb,
> -						xid, NULL);
> +		rc = cifs_get_inode_info(&inode, "", NULL, sb, xid, NULL);
>  
>  	if (!inode) {
>  		inode = ERR_PTR(rc);
> @@ -922,7 +916,6 @@ struct inode *cifs_root_iget(struct super_block *sb)
>  	}
>  
>  out:
> -	kfree(full_path);
>  	/* can not call macro FreeXid here since in a void func
>  	 * TODO: This is no longer true
>  	 */

Other than the nit above about /proc/mounts, this seems fine. I suggest
we go ahead and put this in for the merge window, and Pavel can do a
patch to fix /proc/mounts afterward. Sound reasonable?

Reviewed-by: Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [v2 4/4] CIFS: Migrate to shared superblock model
       [not found]     ` <1304589314-1147-4-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
@ 2011-05-24 11:22       ` Jeff Layton
       [not found]         ` <20110524072250.7337d434-4QP7MXygkU+dMjc06nkz3ljfA9RmPOcC@public.gmane.org>
  0 siblings, 1 reply; 9+ messages in thread
From: Jeff Layton @ 2011-05-24 11:22 UTC (permalink / raw)
  To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA

On Thu,  5 May 2011 13:55:14 +0400
Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:

> Add cifs_match_super to use in sget to share superblock between mounts
> that have the same //server/sharename, credentials and mount options.
> It helps us to improve performance on work with future SMB2.1 leases.
> 
> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
> ---
>  fs/cifs/cifsfs.c   |   18 ++++++++++-
>  fs/cifs/cifsglob.h |    5 +++
>  fs/cifs/connect.c  |   90 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 112 insertions(+), 1 deletions(-)
> 
> diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
> index 446b5c2..ba0b7ae 100644
> --- a/fs/cifs/cifsfs.c
> +++ b/fs/cifs/cifsfs.c
> @@ -644,6 +644,7 @@ cifs_do_mount(struct file_system_type *fs_type,
>  	struct super_block *sb;
>  	struct cifs_sb_info *cifs_sb;
>  	struct smb_vol *volume_info;
> +	struct cifs_mnt_data mnt_data;
>  	struct dentry *root;
>  	char *copied_data = NULL;
>  
> @@ -661,13 +662,21 @@ cifs_do_mount(struct file_system_type *fs_type,
>  
>  	cifs_setup_cifs_sb(volume_info, cifs_sb);
>  
> -	sb = sget(fs_type, NULL, set_anon_super, NULL);
> +	mnt_data.vol = volume_info;
> +	mnt_data.cifs_sb = cifs_sb;
> +
> +	sb = sget(fs_type, cifs_match_super, set_anon_super, &mnt_data);
>  	if (IS_ERR(sb)) {
>  		kfree(cifs_sb);
>  		root = ERR_CAST(sb);
>  		goto out;
>  	}
>  
> +	if (sb->s_fs_info) {
> +		cFYI(1, "Use existing superblock");
> +		goto out_shared;
> +	}
> +
>  	sb->s_flags = flags;
>  
>  	/*
> @@ -700,6 +709,13 @@ out:
>  	cifs_cleanup_volume_info(&volume_info);
>  	return root;
>  
> +out_shared:
> +	root = cifs_get_root(volume_info, sb);
> +	if (root)
> +		cFYI(1, "dentry root is: %p", root);
> +	cifs_cleanup_volume_info(&volume_info);
> +	return root;
> +
>  err_out:
>  	kfree(cifs_sb);
>  	deactivate_locked_super(sb);
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index 7ad7d69..55901b0 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -211,6 +211,11 @@ struct smb_vol {
>  	struct nls_table *local_nls;
>  };
>  
> +struct cifs_mnt_data {
> +	struct cifs_sb_info *cifs_sb;
> +	struct smb_vol *vol;
> +};
> +
>  struct TCP_Server_Info {
>  	struct list_head tcp_ses_list;
>  	struct list_head smb_ses_list;
> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
> index 1cacfaa..1d39dcf 100644
> --- a/fs/cifs/connect.c
> +++ b/fs/cifs/connect.c
> @@ -2135,6 +2135,96 @@ cifs_put_tlink(struct tcon_link *tlink)
>  	return;
>  }
>  
> +static inline struct tcon_link *
> +cifs_sb_master_tlink(struct cifs_sb_info *cifs_sb);
> +
> +static const u32 ACTUAL_MOUNT_FLAGS = CIFS_MOUNT_NO_PERM | CIFS_MOUNT_SET_UID |
> +	CIFS_MOUNT_SERVER_INUM | CIFS_MOUNT_DIRECT_IO | CIFS_MOUNT_NO_XATTR |
> +	CIFS_MOUNT_MAP_SPECIAL_CHR | CIFS_MOUNT_UNX_EMUL | CIFS_MOUNT_NO_BRL |
> +	CIFS_MOUNT_CIFS_ACL | CIFS_MOUNT_OVERR_UID | CIFS_MOUNT_OVERR_GID |
> +	CIFS_MOUNT_DYNPERM | CIFS_MOUNT_NOPOSIXBRL | CIFS_MOUNT_NOSSYNC |
> +	CIFS_MOUNT_FSCACHE | CIFS_MOUNT_MF_SYMLINKS | CIFS_MOUNT_MULTIUSER |
> +	CIFS_MOUNT_STRICT_IO;
> +
> +static int
> +compare_mount_options(struct cifs_sb_info *old, struct cifs_sb_info *new)
> +{
> +	if ((old->mnt_cifs_flags & ACTUAL_MOUNT_FLAGS) !=
> +	    (new->mnt_cifs_flags & ACTUAL_MOUNT_FLAGS))
> +		return 0;
> +
> +	if (old->rsize != new->rsize || old->wsize != new->wsize)
> +		return 0;
> +
		^^^^^^^^^^
The rsize and wsize are negotiated -- you can't know what this is until
you talk to the server. Doesn't this check always fail?

The wsize at least is never negotiated up. We only ever negotiate down,
so what may be best is to see whether the wsize was actually specified
in the mount options and if it's smaller than the existing one. If it
is then don't match.

I plan to fix the rsize negotiation in a similar fashion once I do a
readpages overhaul.

> +	if (old->mnt_uid != new->mnt_uid || old->mnt_gid != new->mnt_gid)
> +		return 0;
> +
> +	if (old->mnt_file_mode != new->mnt_file_mode ||
> +	    old->mnt_dir_mode != new->mnt_dir_mode)
> +		return 0;
> +
> +	if (strcmp(old->local_nls->charset, new->local_nls->charset))
> +		return 0;
> +
> +	if (old->actimeo != new->actimeo)
> +		return 0;
> +
> +	return 1;
> +}
> +
> +int
> +cifs_match_super(struct super_block *sb, void *data)
> +{
> +	struct cifs_mnt_data *mnt_data = (struct cifs_mnt_data *)data;
> +	struct smb_vol *volume_info;
> +	struct cifs_sb_info *cifs_sb, *new_cifs_sb;
> +	struct TCP_Server_Info *tcp_srv;
> +	struct cifsSesInfo *ses;
> +	struct cifsTconInfo *tcon;
> +	struct tcon_link *tlink;
> +	struct sockaddr_storage addr;
> +	int rc = 0;
> +
> +	memset(&addr, 0, sizeof(struct sockaddr_storage));
> +
> +	spin_lock(&cifs_tcp_ses_lock);
> +	cifs_sb = CIFS_SB(sb);
> +	tlink = cifs_get_tlink(cifs_sb_master_tlink(cifs_sb));
> +	if (IS_ERR(tlink)) {
> +		spin_unlock(&cifs_tcp_ses_lock);
> +		return rc;
> +	}
> +	tcon = tlink_tcon(tlink);
> +	ses = tcon->ses;
> +	tcp_srv = ses->server;
> +
> +	volume_info = mnt_data->vol;
> +	new_cifs_sb = mnt_data->cifs_sb;
> +
> +	if (!volume_info->UNCip || !volume_info->UNC)
> +		goto out;
> +
> +	rc = cifs_fill_sockaddr((struct sockaddr *)&addr,
> +				volume_info->UNCip,
> +				strlen(volume_info->UNCip),
> +				volume_info->port);
> +	if (!rc)
> +		goto out;
> +
> +	if (!match_server(tcp_srv, (struct sockaddr *)&addr, volume_info) ||
> +	    !match_session(ses, volume_info) ||
> +	    !match_tcon(tcon, volume_info->UNC)) {
> +		rc = 0;
> +		goto out;
> +	}
> +
> +	rc = compare_mount_options(cifs_sb, new_cifs_sb);
> +out:
> +	cifs_put_tlink(tlink);
> +	spin_unlock(&cifs_tcp_ses_lock);
> +	return rc;
> +}
> +
>  int
>  get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
>  	     const struct nls_table *nls_codepage, unsigned int *pnum_referrals,


Other than the problem with the rsize/wsize, this looks ok. I don't see
that as a show-stopper either, so I suggest we merge this and let Pavel
fix that after the merge window closes.

Reviewed-by: Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [v2 4/4] CIFS: Migrate to shared superblock model
       [not found]         ` <20110524072250.7337d434-4QP7MXygkU+dMjc06nkz3ljfA9RmPOcC@public.gmane.org>
@ 2011-05-25 19:10           ` Pavel Shilovsky
       [not found]             ` <BANLkTi=Y8qx_d4S5YJev61mtavZKtr0B7w-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 9+ messages in thread
From: Pavel Shilovsky @ 2011-05-25 19:10 UTC (permalink / raw)
  To: Jeff Layton; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA

2011/5/24 Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>:
> On Thu,  5 May 2011 13:55:14 +0400
> Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
>
>> Add cifs_match_super to use in sget to share superblock between mounts
>> that have the same //server/sharename, credentials and mount options.
>> It helps us to improve performance on work with future SMB2.1 leases.
>>
>> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
>> ---
>>  fs/cifs/cifsfs.c   |   18 ++++++++++-
>>  fs/cifs/cifsglob.h |    5 +++
>>  fs/cifs/connect.c  |   90 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 112 insertions(+), 1 deletions(-)
>>
>> diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
>> index 446b5c2..ba0b7ae 100644
>> --- a/fs/cifs/cifsfs.c
>> +++ b/fs/cifs/cifsfs.c
>> @@ -644,6 +644,7 @@ cifs_do_mount(struct file_system_type *fs_type,
>>       struct super_block *sb;
>>       struct cifs_sb_info *cifs_sb;
>>       struct smb_vol *volume_info;
>> +     struct cifs_mnt_data mnt_data;
>>       struct dentry *root;
>>       char *copied_data = NULL;
>>
>> @@ -661,13 +662,21 @@ cifs_do_mount(struct file_system_type *fs_type,
>>
>>       cifs_setup_cifs_sb(volume_info, cifs_sb);
>>
>> -     sb = sget(fs_type, NULL, set_anon_super, NULL);
>> +     mnt_data.vol = volume_info;
>> +     mnt_data.cifs_sb = cifs_sb;
>> +
>> +     sb = sget(fs_type, cifs_match_super, set_anon_super, &mnt_data);
>>       if (IS_ERR(sb)) {
>>               kfree(cifs_sb);
>>               root = ERR_CAST(sb);
>>               goto out;
>>       }
>>
>> +     if (sb->s_fs_info) {
>> +             cFYI(1, "Use existing superblock");
>> +             goto out_shared;
>> +     }
>> +
>>       sb->s_flags = flags;
>>
>>       /*
>> @@ -700,6 +709,13 @@ out:
>>       cifs_cleanup_volume_info(&volume_info);
>>       return root;
>>
>> +out_shared:
>> +     root = cifs_get_root(volume_info, sb);
>> +     if (root)
>> +             cFYI(1, "dentry root is: %p", root);
>> +     cifs_cleanup_volume_info(&volume_info);
>> +     return root;
>> +
>>  err_out:
>>       kfree(cifs_sb);
>>       deactivate_locked_super(sb);
>> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
>> index 7ad7d69..55901b0 100644
>> --- a/fs/cifs/cifsglob.h
>> +++ b/fs/cifs/cifsglob.h
>> @@ -211,6 +211,11 @@ struct smb_vol {
>>       struct nls_table *local_nls;
>>  };
>>
>> +struct cifs_mnt_data {
>> +     struct cifs_sb_info *cifs_sb;
>> +     struct smb_vol *vol;
>> +};
>> +
>>  struct TCP_Server_Info {
>>       struct list_head tcp_ses_list;
>>       struct list_head smb_ses_list;
>> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
>> index 1cacfaa..1d39dcf 100644
>> --- a/fs/cifs/connect.c
>> +++ b/fs/cifs/connect.c
>> @@ -2135,6 +2135,96 @@ cifs_put_tlink(struct tcon_link *tlink)
>>       return;
>>  }
>>
>> +static inline struct tcon_link *
>> +cifs_sb_master_tlink(struct cifs_sb_info *cifs_sb);
>> +
>> +static const u32 ACTUAL_MOUNT_FLAGS = CIFS_MOUNT_NO_PERM | CIFS_MOUNT_SET_UID |
>> +     CIFS_MOUNT_SERVER_INUM | CIFS_MOUNT_DIRECT_IO | CIFS_MOUNT_NO_XATTR |
>> +     CIFS_MOUNT_MAP_SPECIAL_CHR | CIFS_MOUNT_UNX_EMUL | CIFS_MOUNT_NO_BRL |
>> +     CIFS_MOUNT_CIFS_ACL | CIFS_MOUNT_OVERR_UID | CIFS_MOUNT_OVERR_GID |
>> +     CIFS_MOUNT_DYNPERM | CIFS_MOUNT_NOPOSIXBRL | CIFS_MOUNT_NOSSYNC |
>> +     CIFS_MOUNT_FSCACHE | CIFS_MOUNT_MF_SYMLINKS | CIFS_MOUNT_MULTIUSER |
>> +     CIFS_MOUNT_STRICT_IO;
>> +
>> +static int
>> +compare_mount_options(struct cifs_sb_info *old, struct cifs_sb_info *new)
>> +{
>> +     if ((old->mnt_cifs_flags & ACTUAL_MOUNT_FLAGS) !=
>> +         (new->mnt_cifs_flags & ACTUAL_MOUNT_FLAGS))
>> +             return 0;
>> +
>> +     if (old->rsize != new->rsize || old->wsize != new->wsize)
>> +             return 0;
>> +
>                ^^^^^^^^^^
> The rsize and wsize are negotiated -- you can't know what this is until
> you talk to the server. Doesn't this check always fail?

If we don't specify wsize and rsize they are set to default values
(16384 and 57344) in both mounts, this check succeed.

>
> The wsize at least is never negotiated up. We only ever negotiate down,
> so what may be best is to see whether the wsize was actually specified
> in the mount options and if it's smaller than the existing one. If it
> is then don't match.
>
> I plan to fix the rsize negotiation in a similar fashion once I do a
> readpages overhaul.

Ok, when it is done, we can change compare_mount_options appropriately.

>
>> +     if (old->mnt_uid != new->mnt_uid || old->mnt_gid != new->mnt_gid)
>> +             return 0;
>> +
>> +     if (old->mnt_file_mode != new->mnt_file_mode ||
>> +         old->mnt_dir_mode != new->mnt_dir_mode)
>> +             return 0;
>> +
>> +     if (strcmp(old->local_nls->charset, new->local_nls->charset))
>> +             return 0;
>> +
>> +     if (old->actimeo != new->actimeo)
>> +             return 0;
>> +
>> +     return 1;
>> +}
>> +
>> +int
>> +cifs_match_super(struct super_block *sb, void *data)
>> +{
>> +     struct cifs_mnt_data *mnt_data = (struct cifs_mnt_data *)data;
>> +     struct smb_vol *volume_info;
>> +     struct cifs_sb_info *cifs_sb, *new_cifs_sb;
>> +     struct TCP_Server_Info *tcp_srv;
>> +     struct cifsSesInfo *ses;
>> +     struct cifsTconInfo *tcon;
>> +     struct tcon_link *tlink;
>> +     struct sockaddr_storage addr;
>> +     int rc = 0;
>> +
>> +     memset(&addr, 0, sizeof(struct sockaddr_storage));
>> +
>> +     spin_lock(&cifs_tcp_ses_lock);
>> +     cifs_sb = CIFS_SB(sb);
>> +     tlink = cifs_get_tlink(cifs_sb_master_tlink(cifs_sb));
>> +     if (IS_ERR(tlink)) {
>> +             spin_unlock(&cifs_tcp_ses_lock);
>> +             return rc;
>> +     }
>> +     tcon = tlink_tcon(tlink);
>> +     ses = tcon->ses;
>> +     tcp_srv = ses->server;
>> +
>> +     volume_info = mnt_data->vol;
>> +     new_cifs_sb = mnt_data->cifs_sb;
>> +
>> +     if (!volume_info->UNCip || !volume_info->UNC)
>> +             goto out;
>> +
>> +     rc = cifs_fill_sockaddr((struct sockaddr *)&addr,
>> +                             volume_info->UNCip,
>> +                             strlen(volume_info->UNCip),
>> +                             volume_info->port);
>> +     if (!rc)
>> +             goto out;
>> +
>> +     if (!match_server(tcp_srv, (struct sockaddr *)&addr, volume_info) ||
>> +         !match_session(ses, volume_info) ||
>> +         !match_tcon(tcon, volume_info->UNC)) {
>> +             rc = 0;
>> +             goto out;
>> +     }
>> +
>> +     rc = compare_mount_options(cifs_sb, new_cifs_sb);
>> +out:
>> +     cifs_put_tlink(tlink);
>> +     spin_unlock(&cifs_tcp_ses_lock);
>> +     return rc;
>> +}
>> +
>>  int
>>  get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
>>            const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
>
>
> Other than the problem with the rsize/wsize, this looks ok. I don't see
> that as a show-stopper either, so I suggest we merge this and let Pavel
> fix that after the merge window closes.
>
> Reviewed-by: Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
>



-- 
Best regards,
Pavel Shilovsky.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [v2 4/4] CIFS: Migrate to shared superblock model
       [not found]             ` <BANLkTi=Y8qx_d4S5YJev61mtavZKtr0B7w-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2011-05-25 19:36               ` Jeff Layton
       [not found]                 ` <20110525153626.294d2c89-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
  0 siblings, 1 reply; 9+ messages in thread
From: Jeff Layton @ 2011-05-25 19:36 UTC (permalink / raw)
  To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA

On Wed, 25 May 2011 23:10:33 +0400
Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:

> 2011/5/24 Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>:
> > On Thu,  5 May 2011 13:55:14 +0400
> > Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> >
> >> Add cifs_match_super to use in sget to share superblock between mounts
> >> that have the same //server/sharename, credentials and mount options.
> >> It helps us to improve performance on work with future SMB2.1 leases.
> >>
> >> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
> >> ---
> >>  fs/cifs/cifsfs.c   |   18 ++++++++++-
> >>  fs/cifs/cifsglob.h |    5 +++
> >>  fs/cifs/connect.c  |   90 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> >>  3 files changed, 112 insertions(+), 1 deletions(-)
> >>
> >> diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
> >> index 446b5c2..ba0b7ae 100644
> >> --- a/fs/cifs/cifsfs.c
> >> +++ b/fs/cifs/cifsfs.c
> >> @@ -644,6 +644,7 @@ cifs_do_mount(struct file_system_type *fs_type,
> >>       struct super_block *sb;
> >>       struct cifs_sb_info *cifs_sb;
> >>       struct smb_vol *volume_info;
> >> +     struct cifs_mnt_data mnt_data;
> >>       struct dentry *root;
> >>       char *copied_data = NULL;
> >>
> >> @@ -661,13 +662,21 @@ cifs_do_mount(struct file_system_type *fs_type,
> >>
> >>       cifs_setup_cifs_sb(volume_info, cifs_sb);
> >>
> >> -     sb = sget(fs_type, NULL, set_anon_super, NULL);
> >> +     mnt_data.vol = volume_info;
> >> +     mnt_data.cifs_sb = cifs_sb;
> >> +
> >> +     sb = sget(fs_type, cifs_match_super, set_anon_super, &mnt_data);
> >>       if (IS_ERR(sb)) {
> >>               kfree(cifs_sb);
> >>               root = ERR_CAST(sb);
> >>               goto out;
> >>       }
> >>
> >> +     if (sb->s_fs_info) {
> >> +             cFYI(1, "Use existing superblock");
> >> +             goto out_shared;
> >> +     }
> >> +
> >>       sb->s_flags = flags;
> >>
> >>       /*
> >> @@ -700,6 +709,13 @@ out:
> >>       cifs_cleanup_volume_info(&volume_info);
> >>       return root;
> >>
> >> +out_shared:
> >> +     root = cifs_get_root(volume_info, sb);
> >> +     if (root)
> >> +             cFYI(1, "dentry root is: %p", root);
> >> +     cifs_cleanup_volume_info(&volume_info);
> >> +     return root;
> >> +
> >>  err_out:
> >>       kfree(cifs_sb);
> >>       deactivate_locked_super(sb);
> >> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> >> index 7ad7d69..55901b0 100644
> >> --- a/fs/cifs/cifsglob.h
> >> +++ b/fs/cifs/cifsglob.h
> >> @@ -211,6 +211,11 @@ struct smb_vol {
> >>       struct nls_table *local_nls;
> >>  };
> >>
> >> +struct cifs_mnt_data {
> >> +     struct cifs_sb_info *cifs_sb;
> >> +     struct smb_vol *vol;
> >> +};
> >> +
> >>  struct TCP_Server_Info {
> >>       struct list_head tcp_ses_list;
> >>       struct list_head smb_ses_list;
> >> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
> >> index 1cacfaa..1d39dcf 100644
> >> --- a/fs/cifs/connect.c
> >> +++ b/fs/cifs/connect.c
> >> @@ -2135,6 +2135,96 @@ cifs_put_tlink(struct tcon_link *tlink)
> >>       return;
> >>  }
> >>
> >> +static inline struct tcon_link *
> >> +cifs_sb_master_tlink(struct cifs_sb_info *cifs_sb);
> >> +
> >> +static const u32 ACTUAL_MOUNT_FLAGS = CIFS_MOUNT_NO_PERM | CIFS_MOUNT_SET_UID |
> >> +     CIFS_MOUNT_SERVER_INUM | CIFS_MOUNT_DIRECT_IO | CIFS_MOUNT_NO_XATTR |
> >> +     CIFS_MOUNT_MAP_SPECIAL_CHR | CIFS_MOUNT_UNX_EMUL | CIFS_MOUNT_NO_BRL |
> >> +     CIFS_MOUNT_CIFS_ACL | CIFS_MOUNT_OVERR_UID | CIFS_MOUNT_OVERR_GID |
> >> +     CIFS_MOUNT_DYNPERM | CIFS_MOUNT_NOPOSIXBRL | CIFS_MOUNT_NOSSYNC |
> >> +     CIFS_MOUNT_FSCACHE | CIFS_MOUNT_MF_SYMLINKS | CIFS_MOUNT_MULTIUSER |
> >> +     CIFS_MOUNT_STRICT_IO;
> >> +
> >> +static int
> >> +compare_mount_options(struct cifs_sb_info *old, struct cifs_sb_info *new)
> >> +{
> >> +     if ((old->mnt_cifs_flags & ACTUAL_MOUNT_FLAGS) !=
> >> +         (new->mnt_cifs_flags & ACTUAL_MOUNT_FLAGS))
> >> +             return 0;
> >> +
> >> +     if (old->rsize != new->rsize || old->wsize != new->wsize)
> >> +             return 0;
> >> +
> >                ^^^^^^^^^^
> > The rsize and wsize are negotiated -- you can't know what this is until
> > you talk to the server. Doesn't this check always fail?
> 
> If we don't specify wsize and rsize they are set to default values
> (16384 and 57344) in both mounts, this check succeed.
> 

Ahh then this will likely be broken if/when the wsize negotiation patch
goes in. I suppose we'll have to see which patch (if any) Steve decides
to commit first and then try to fix this up afterward.

The brokenness shouldn't be too bad, you just won't be able to actually
share superblocks until it's fixed.

-- 
Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [v2 4/4] CIFS: Migrate to shared superblock model
       [not found]                 ` <20110525153626.294d2c89-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
@ 2011-05-26  6:06                   ` Pavel Shilovsky
  0 siblings, 0 replies; 9+ messages in thread
From: Pavel Shilovsky @ 2011-05-26  6:06 UTC (permalink / raw)
  To: Jeff Layton; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA

2011/5/25 Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>:
> On Wed, 25 May 2011 23:10:33 +0400
> Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
>
>> 2011/5/24 Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>:
>> > On Thu,  5 May 2011 13:55:14 +0400
>> > Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
>> >
>> >> Add cifs_match_super to use in sget to share superblock between mounts
>> >> that have the same //server/sharename, credentials and mount options.
>> >> It helps us to improve performance on work with future SMB2.1 leases.
>> >>
>> >> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
>> >> ---
>> >>  fs/cifs/cifsfs.c   |   18 ++++++++++-
>> >>  fs/cifs/cifsglob.h |    5 +++
>> >>  fs/cifs/connect.c  |   90 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>> >>  3 files changed, 112 insertions(+), 1 deletions(-)
>> >>
>> >> diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
>> >> index 446b5c2..ba0b7ae 100644
>> >> --- a/fs/cifs/cifsfs.c
>> >> +++ b/fs/cifs/cifsfs.c
>> >> @@ -644,6 +644,7 @@ cifs_do_mount(struct file_system_type *fs_type,
>> >>       struct super_block *sb;
>> >>       struct cifs_sb_info *cifs_sb;
>> >>       struct smb_vol *volume_info;
>> >> +     struct cifs_mnt_data mnt_data;
>> >>       struct dentry *root;
>> >>       char *copied_data = NULL;
>> >>
>> >> @@ -661,13 +662,21 @@ cifs_do_mount(struct file_system_type *fs_type,
>> >>
>> >>       cifs_setup_cifs_sb(volume_info, cifs_sb);
>> >>
>> >> -     sb = sget(fs_type, NULL, set_anon_super, NULL);
>> >> +     mnt_data.vol = volume_info;
>> >> +     mnt_data.cifs_sb = cifs_sb;
>> >> +
>> >> +     sb = sget(fs_type, cifs_match_super, set_anon_super, &mnt_data);
>> >>       if (IS_ERR(sb)) {
>> >>               kfree(cifs_sb);
>> >>               root = ERR_CAST(sb);
>> >>               goto out;
>> >>       }
>> >>
>> >> +     if (sb->s_fs_info) {
>> >> +             cFYI(1, "Use existing superblock");
>> >> +             goto out_shared;
>> >> +     }
>> >> +
>> >>       sb->s_flags = flags;
>> >>
>> >>       /*
>> >> @@ -700,6 +709,13 @@ out:
>> >>       cifs_cleanup_volume_info(&volume_info);
>> >>       return root;
>> >>
>> >> +out_shared:
>> >> +     root = cifs_get_root(volume_info, sb);
>> >> +     if (root)
>> >> +             cFYI(1, "dentry root is: %p", root);
>> >> +     cifs_cleanup_volume_info(&volume_info);
>> >> +     return root;
>> >> +
>> >>  err_out:
>> >>       kfree(cifs_sb);
>> >>       deactivate_locked_super(sb);
>> >> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
>> >> index 7ad7d69..55901b0 100644
>> >> --- a/fs/cifs/cifsglob.h
>> >> +++ b/fs/cifs/cifsglob.h
>> >> @@ -211,6 +211,11 @@ struct smb_vol {
>> >>       struct nls_table *local_nls;
>> >>  };
>> >>
>> >> +struct cifs_mnt_data {
>> >> +     struct cifs_sb_info *cifs_sb;
>> >> +     struct smb_vol *vol;
>> >> +};
>> >> +
>> >>  struct TCP_Server_Info {
>> >>       struct list_head tcp_ses_list;
>> >>       struct list_head smb_ses_list;
>> >> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
>> >> index 1cacfaa..1d39dcf 100644
>> >> --- a/fs/cifs/connect.c
>> >> +++ b/fs/cifs/connect.c
>> >> @@ -2135,6 +2135,96 @@ cifs_put_tlink(struct tcon_link *tlink)
>> >>       return;
>> >>  }
>> >>
>> >> +static inline struct tcon_link *
>> >> +cifs_sb_master_tlink(struct cifs_sb_info *cifs_sb);
>> >> +
>> >> +static const u32 ACTUAL_MOUNT_FLAGS = CIFS_MOUNT_NO_PERM | CIFS_MOUNT_SET_UID |
>> >> +     CIFS_MOUNT_SERVER_INUM | CIFS_MOUNT_DIRECT_IO | CIFS_MOUNT_NO_XATTR |
>> >> +     CIFS_MOUNT_MAP_SPECIAL_CHR | CIFS_MOUNT_UNX_EMUL | CIFS_MOUNT_NO_BRL |
>> >> +     CIFS_MOUNT_CIFS_ACL | CIFS_MOUNT_OVERR_UID | CIFS_MOUNT_OVERR_GID |
>> >> +     CIFS_MOUNT_DYNPERM | CIFS_MOUNT_NOPOSIXBRL | CIFS_MOUNT_NOSSYNC |
>> >> +     CIFS_MOUNT_FSCACHE | CIFS_MOUNT_MF_SYMLINKS | CIFS_MOUNT_MULTIUSER |
>> >> +     CIFS_MOUNT_STRICT_IO;
>> >> +
>> >> +static int
>> >> +compare_mount_options(struct cifs_sb_info *old, struct cifs_sb_info *new)
>> >> +{
>> >> +     if ((old->mnt_cifs_flags & ACTUAL_MOUNT_FLAGS) !=
>> >> +         (new->mnt_cifs_flags & ACTUAL_MOUNT_FLAGS))
>> >> +             return 0;
>> >> +
>> >> +     if (old->rsize != new->rsize || old->wsize != new->wsize)
>> >> +             return 0;
>> >> +
>> >                ^^^^^^^^^^
>> > The rsize and wsize are negotiated -- you can't know what this is until
>> > you talk to the server. Doesn't this check always fail?
>>
>> If we don't specify wsize and rsize they are set to default values
>> (16384 and 57344) in both mounts, this check succeed.
>>
>
> Ahh then this will likely be broken if/when the wsize negotiation patch
> goes in. I suppose we'll have to see which patch (if any) Steve decides
> to commit first and then try to fix this up afterward.
>
> The brokenness shouldn't be too bad, you just won't be able to actually
> share superblocks until it's fixed.
>
> --
> Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
>

Updated patch 4/4 with wsize changes and posted to the list.

-- 
Best regards,
Pavel Shilovsky.

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2011-05-26  6:06 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-05-05  9:55 [v2 1/4] CIFS: Simplify connection structure search calls Pavel Shilovsky
     [not found] ` <1304589314-1147-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2011-05-05  9:55   ` [v2 2/4] CIFS: Simplify mount code for further shared sb capability Pavel Shilovsky
2011-05-05  9:55   ` [v2 3/4] CIFS: Migrate from prefixpath logic Pavel Shilovsky
     [not found]     ` <1304589314-1147-3-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2011-05-24 11:11       ` Jeff Layton
2011-05-05  9:55   ` [v2 4/4] CIFS: Migrate to shared superblock model Pavel Shilovsky
     [not found]     ` <1304589314-1147-4-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2011-05-24 11:22       ` Jeff Layton
     [not found]         ` <20110524072250.7337d434-4QP7MXygkU+dMjc06nkz3ljfA9RmPOcC@public.gmane.org>
2011-05-25 19:10           ` Pavel Shilovsky
     [not found]             ` <BANLkTi=Y8qx_d4S5YJev61mtavZKtr0B7w-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2011-05-25 19:36               ` Jeff Layton
     [not found]                 ` <20110525153626.294d2c89-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
2011-05-26  6:06                   ` Pavel Shilovsky

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.