All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/11] cifs: implement multisession mounts (try #2)
@ 2010-04-20 20:07 Jeff Layton
  2010-04-20 20:07 ` [PATCH 01/11] cifs: add function to get a tcon from cifs_sb Jeff Layton
                   ` (12 more replies)
  0 siblings, 13 replies; 24+ messages in thread
From: Jeff Layton @ 2010-04-20 20:07 UTC (permalink / raw)
  To: linux-cifs-client, linux-fsdevel; +Cc: smfrench

This is a second pass at implementing multisession mounts for CIFS. The
main change since the last one is that I've broken out a series of
preliminary patches into a separate set and posted them separately. This
set is based on those changes:

    http://lists.samba.org/archive/linux-cifs-client/2010-April/005830.html

Thus, this set is a bit smaller than the last one. Hopefully that will
make it easier to review.

This patchset is intended to allow CIFS to behave as a truly multiuser
filesystem. The idea here is to have the kernel transparently spawn a
new session with the server whenever one is needed. Obviously, we can't
prompt for a password from the kernel, so for now this is limited to
using krb5 authentication. We could extend this to other authtypes, but
we'll need a way to stash username and password or NTLM hashes in the
kernel keyring.

To use this, you'll need to have root mount the server using sec=krb5 or
krb5i. Then, any user who wants to access the mount will need a valid
krb5 ticket. If they don't have one, then they'll probably get back an
-ENOKEY error on the syscall.

The patchset is pretty usable now, but there are still a number of
to-do items:

- add a way to prune idle sessions and tcons: not too hard to do,
  just need to settle on a mechanism to scan for these on a recurring
  basis and close them out

- allow the establishment of an anonymous session and allow users
  without creds to use that instead of being denied access. This
  requires some cleanup to make NTLMSSP work correctly. We may also
  need mount options to control that behavior, etc.

- fix the error return so that -ENOKEY and similar errors don't bubble
  up on syscalls that don't expect it

...and probably plenty of other stuff. The near term goal is to get the
preliminary patchset in place. Once that's done, I'll start feeding
these to Steve for inclusion. I'm posting these to try and get early
feedback and in the hopes that people who need this functionality will
be willing to help test it out.

Jeff Layton (11):
  cifs: add function to get a tcon from cifs_sb
  cifs: add tcon field to cifsFileInfo struct
  cifs: make various routines use the cifsFileInfo->tcon pointer
  cifs: have find_readable/writable_file filter by fsuid
  cifs: fix cifs_show_options to show "username=" or "multises"
  cifs: have cifs_new_fileinfo take a tcon arg
  cifs: allow for cifs_sb_tcon() to return an error
  cifs: fix handling of signing with writepages
  cifs: add routines to build sessions and tcons on the fly
  cifs: on multises mount, set ownership to current_fsuid/current_fsgid
  cifs: add "multises" mount option

 fs/cifs/cifs_dfs_ref.c |   10 ++-
 fs/cifs/cifs_fs_sb.h   |   10 ++-
 fs/cifs/cifsacl.c      |   36 ++++++--
 fs/cifs/cifsfs.c       |   85 ++++++++-----------
 fs/cifs/cifsglob.h     |    1 +
 fs/cifs/cifsproto.h    |    9 ++-
 fs/cifs/connect.c      |  215 ++++++++++++++++++++++++++++++++++++++++++++++--
 fs/cifs/dir.c          |   71 ++++++++++------
 fs/cifs/file.c         |  154 +++++++++++++++++++---------------
 fs/cifs/inode.c        |  168 ++++++++++++++++++++++++++++---------
 fs/cifs/ioctl.c        |   19 +----
 fs/cifs/link.c         |   19 ++++-
 fs/cifs/misc.c         |    2 +-
 fs/cifs/readdir.c      |   30 ++++----
 fs/cifs/xattr.c        |   29 ++++++-
 15 files changed, 605 insertions(+), 253 deletions(-)

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

* [PATCH 01/11] cifs: add function to get a tcon from cifs_sb
  2010-04-20 20:07 [PATCH 00/11] cifs: implement multisession mounts (try #2) Jeff Layton
@ 2010-04-20 20:07 ` Jeff Layton
  2010-04-20 20:07 ` [PATCH 02/11] cifs: add tcon field to cifsFileInfo struct Jeff Layton
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 24+ messages in thread
From: Jeff Layton @ 2010-04-20 20:07 UTC (permalink / raw)
  To: linux-cifs-client, linux-fsdevel; +Cc: smfrench

When we convert cifs to do multiple sessions per mount, we'll need more
than one tcon per superblock. At that point "cifs_sb->tcon" will make
no sense. Add a new accessor function that gets a tcon given a cifs_sb.
For now, it just returns cifs_sb->tcon. Later it'll do more.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/cifs/cifs_dfs_ref.c |    2 +-
 fs/cifs/cifsacl.c      |   16 +++++++-------
 fs/cifs/cifsfs.c       |   20 ++++++++--------
 fs/cifs/cifsglob.h     |    6 +++++
 fs/cifs/connect.c      |    4 +-
 fs/cifs/dir.c          |   18 ++++++++--------
 fs/cifs/file.c         |   34 +++++++++++++++---------------
 fs/cifs/inode.c        |   54 ++++++++++++++++++++++++------------------------
 fs/cifs/ioctl.c        |    2 +-
 fs/cifs/link.c         |    6 ++--
 fs/cifs/misc.c         |    2 +-
 fs/cifs/readdir.c      |   10 ++++----
 fs/cifs/xattr.c        |    8 +++---
 13 files changed, 94 insertions(+), 88 deletions(-)

diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c
index 78e4d2a..fc7035a 100644
--- a/fs/cifs/cifs_dfs_ref.c
+++ b/fs/cifs/cifs_dfs_ref.c
@@ -323,7 +323,7 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
 	nd->path.dentry = dget(dentry);
 
 	cifs_sb = CIFS_SB(dentry->d_inode->i_sb);
-	ses = cifs_sb->tcon->ses;
+	ses = cifs_sb_tcon(cifs_sb)->ses;
 
 	if (!ses) {
 		rc = -EINVAL;
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
index 9b716d0..b8dd664 100644
--- a/fs/cifs/cifsacl.c
+++ b/fs/cifs/cifsacl.c
@@ -559,7 +559,7 @@ static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
 	int xid, rc;
 
 	xid = GetXid();
-	rc = CIFSSMBGetCIFSACL(xid, cifs_sb->tcon, fid, &pntsd, pacllen);
+	rc = CIFSSMBGetCIFSACL(xid, cifs_sb_tcon(cifs_sb), fid, &pntsd, pacllen);
 	FreeXid(xid);
 
 
@@ -577,7 +577,7 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
 
 	xid = GetXid();
 
-	rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN, READ_CONTROL, 0,
+	rc = CIFSSMBOpen(xid, cifs_sb_tcon(cifs_sb), path, FILE_OPEN, READ_CONTROL, 0,
 			 &fid, &oplock, NULL, cifs_sb->local_nls,
 			 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 	if (rc) {
@@ -585,10 +585,10 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
 		goto out;
 	}
 
-	rc = CIFSSMBGetCIFSACL(xid, cifs_sb->tcon, fid, &pntsd, pacllen);
+	rc = CIFSSMBGetCIFSACL(xid, cifs_sb_tcon(cifs_sb), fid, &pntsd, pacllen);
 	cFYI(1, ("GetCIFSACL rc = %d ACL len %d", rc, *pacllen));
 
-	CIFSSMBClose(xid, cifs_sb->tcon, fid);
+	CIFSSMBClose(xid, cifs_sb_tcon(cifs_sb), fid);
  out:
 	FreeXid(xid);
 	return pntsd;
@@ -618,7 +618,7 @@ static int set_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, __u16 fid,
 	int xid, rc;
 
 	xid = GetXid();
-	rc = CIFSSMBSetCIFSACL(xid, cifs_sb->tcon, fid, pnntsd, acllen);
+	rc = CIFSSMBSetCIFSACL(xid, cifs_sb_tcon(cifs_sb), fid, pnntsd, acllen);
 	FreeXid(xid);
 
 	cFYI(DBG2, ("SetCIFSACL rc = %d", rc));
@@ -634,7 +634,7 @@ static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path,
 
 	xid = GetXid();
 
-	rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN, WRITE_DAC, 0,
+	rc = CIFSSMBOpen(xid, cifs_sb_tcon(cifs_sb), path, FILE_OPEN, WRITE_DAC, 0,
 			 &fid, &oplock, NULL, cifs_sb->local_nls,
 			 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 	if (rc) {
@@ -642,10 +642,10 @@ static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path,
 		goto out;
 	}
 
-	rc = CIFSSMBSetCIFSACL(xid, cifs_sb->tcon, fid, pnntsd, acllen);
+	rc = CIFSSMBSetCIFSACL(xid, cifs_sb_tcon(cifs_sb), fid, pnntsd, acllen);
 	cFYI(DBG2, ("SetCIFSACL rc = %d", rc));
 
-	CIFSSMBClose(xid, cifs_sb->tcon, fid);
+	CIFSSMBClose(xid, cifs_sb_tcon(cifs_sb), fid);
  out:
 	FreeXid(xid);
 	return rc;
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 09e9783..211dcbf 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -135,9 +135,9 @@ cifs_read_super(struct super_block *sb, void *data,
 
 	sb->s_magic = CIFS_MAGIC_NUMBER;
 	sb->s_op = &cifs_super_ops;
-/*	if (cifs_sb->tcon->ses->server->maxBuf > MAX_CIFS_HDR_SIZE + 512)
+/*	if (cifs_sb_tcon(cifs_sb)->ses->server->maxBuf > MAX_CIFS_HDR_SIZE + 512)
 	    sb->s_blocksize =
-		cifs_sb->tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; */
+		cifs_sb_tcon(cifs_sb)->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; */
 #ifdef CONFIG_CIFS_QUOTA
 	sb->s_qcop = &cifs_quotactl_ops;
 #endif
@@ -224,7 +224,7 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
 	struct super_block *sb = dentry->d_sb;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
-	struct cifsTconInfo *tcon = cifs_sb->tcon;
+	struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb);
 	int rc = -EOPNOTSUPP;
 	int xid;
 
@@ -359,7 +359,7 @@ static int
 cifs_show_options(struct seq_file *s, struct vfsmount *m)
 {
 	struct cifs_sb_info *cifs_sb = CIFS_SB(m->mnt_sb);
-	struct cifsTconInfo *tcon = cifs_sb->tcon;
+	struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb);
 
 	seq_printf(s, ",unc=%s", tcon->treeName);
 	if (tcon->ses->userName)
@@ -432,7 +432,7 @@ int cifs_xquota_set(struct super_block *sb, int quota_type, qid_t qid,
 	struct cifsTconInfo *pTcon;
 
 	if (cifs_sb)
-		pTcon = cifs_sb->tcon;
+		pTcon = cifs_sb_tcon(cifs_sb);
 	else
 		return -EIO;
 
@@ -456,7 +456,7 @@ int cifs_xquota_get(struct super_block *sb, int quota_type, qid_t qid,
 	struct cifsTconInfo *pTcon;
 
 	if (cifs_sb)
-		pTcon = cifs_sb->tcon;
+		pTcon = cifs_sb_tcon(cifs_sb);
 	else
 		return -EIO;
 
@@ -478,7 +478,7 @@ int cifs_xstate_set(struct super_block *sb, unsigned int flags, int operation)
 	struct cifsTconInfo *pTcon;
 
 	if (cifs_sb)
-		pTcon = cifs_sb->tcon;
+		pTcon = cifs_sb_tcon(cifs_sb);
 	else
 		return -EIO;
 
@@ -500,7 +500,7 @@ int cifs_xstate_get(struct super_block *sb, struct fs_quota_stat *qstats)
 	struct cifsTconInfo *pTcon;
 
 	if (cifs_sb)
-		pTcon = cifs_sb->tcon;
+		pTcon = cifs_sb_tcon(cifs_sb);
 	else
 		return -EIO;
 
@@ -530,7 +530,7 @@ static void cifs_umount_begin(struct super_block *sb)
 	if (cifs_sb == NULL)
 		return;
 
-	tcon = cifs_sb->tcon;
+	tcon = cifs_sb_tcon(cifs_sb);
 	if (tcon == NULL)
 		return;
 
@@ -662,7 +662,7 @@ static int cifs_setlease(struct file *file, long arg, struct file_lock **lease)
 	    ((arg == F_WRLCK) &&
 		(CIFS_I(inode)->clientCanCacheAll)))
 		return generic_setlease(file, arg, lease);
-	else if (CIFS_SB(inode->i_sb)->tcon->local_lease &&
+	else if (cifs_sb_tcon(CIFS_SB(inode->i_sb))->local_lease &&
 			!CIFS_I(inode)->clientCanCacheRead)
 		/* If the server claims to support oplock on this
 		   file, then we still need to check oplock even
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 4f24590..79a75c4 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -400,6 +400,12 @@ CIFS_SB(struct super_block *sb)
 	return sb->s_fs_info;
 }
 
+static inline struct cifsTconInfo *
+cifs_sb_tcon(struct cifs_sb_info *cifs_sb)
+{
+	return cifs_sb->tcon;
+}
+
 static inline char CIFS_DIR_SEP(const struct cifs_sb_info *cifs_sb)
 {
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index c3cce2e..09a1216 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -3044,8 +3044,8 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
 	int rc = 0;
 	char *tmp;
 
-	if (cifs_sb->tcon)
-		cifs_put_tcon(cifs_sb->tcon);
+	if (cifs_sb_tcon(cifs_sb))
+		cifs_put_tcon(cifs_sb_tcon(cifs_sb));
 
 	cifs_sb->tcon = NULL;
 	tmp = cifs_sb->prepath;
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index e9f7ecc..572d31c 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -63,8 +63,8 @@ build_path_from_dentry(struct dentry *direntry)
 	cifs_sb = CIFS_SB(direntry->d_sb);
 	dirsep = CIFS_DIR_SEP(cifs_sb);
 	pplen = cifs_sb->prepathlen;
-	if (cifs_sb->tcon && (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS))
-		dfsplen = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE + 1);
+	if (cifs_sb_tcon(cifs_sb) && (cifs_sb_tcon(cifs_sb)->Flags & SMB_SHARE_IS_IN_DFS))
+		dfsplen = strnlen(cifs_sb_tcon(cifs_sb)->treeName, MAX_TREE_SIZE + 1);
 	else
 		dfsplen = 0;
 cifs_bp_rename_retry:
@@ -117,7 +117,7 @@ cifs_bp_rename_retry:
 	/* BB test paths to Windows with '/' in the midst of prepath */
 
 	if (dfsplen) {
-		strncpy(full_path, cifs_sb->tcon->treeName, dfsplen);
+		strncpy(full_path, cifs_sb_tcon(cifs_sb)->treeName, dfsplen);
 		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
 			int i;
 			for (i = 0; i < dfsplen; i++) {
@@ -160,7 +160,7 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle,
 	slow_work_init(&pCifsFile->oplock_break, &cifs_oplock_break_ops);
 
 	write_lock(&GlobalSMBSeslock);
-	list_add(&pCifsFile->tlist, &cifs_sb->tcon->openFileList);
+	list_add(&pCifsFile->tlist, &cifs_sb_tcon(cifs_sb)->openFileList);
 	pCifsInode = CIFS_I(newinode);
 	if (pCifsInode) {
 		/* if readable file instance put first in list*/
@@ -225,7 +225,7 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
 		posix_flags |= SMB_O_DIRECT;
 
 	mode &= ~current_umask();
-	rc = CIFSPOSIXCreate(xid, cifs_sb->tcon, posix_flags, mode,
+	rc = CIFSPOSIXCreate(xid, cifs_sb_tcon(cifs_sb), posix_flags, mode,
 			pnetfid, presp_data, poplock, full_path,
 			cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
 					CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -300,7 +300,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
 	xid = GetXid();
 
 	cifs_sb = CIFS_SB(inode->i_sb);
-	tcon = cifs_sb->tcon;
+	tcon = cifs_sb_tcon(cifs_sb);
 
 	full_path = build_path_from_dentry(direntry);
 	if (full_path == NULL) {
@@ -378,7 +378,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
 	if (!tcon->unix_ext && (mode & S_IWUGO) == 0)
 		create_options |= CREATE_OPTION_READONLY;
 
-	if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
+	if (cifs_sb_tcon(cifs_sb)->ses->capabilities & CAP_NT_SMBS)
 		rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
 			 desiredAccess, create_options,
 			 &fileHandle, &oplock, buf, cifs_sb->local_nls,
@@ -490,7 +490,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
 	xid = GetXid();
 
 	cifs_sb = CIFS_SB(inode->i_sb);
-	pTcon = cifs_sb->tcon;
+	pTcon = cifs_sb_tcon(cifs_sb);
 
 	full_path = build_path_from_dentry(direntry);
 	if (full_path == NULL)
@@ -622,7 +622,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
 	/* check whether path exists */
 
 	cifs_sb = CIFS_SB(parent_dir_inode->i_sb);
-	pTcon = cifs_sb->tcon;
+	pTcon = cifs_sb_tcon(cifs_sb);
 
 	/*
 	 * Don't allow the separator character in a path component.
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 031ccae..2e4771f 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -268,7 +268,7 @@ int cifs_open(struct inode *inode, struct file *file)
 	xid = GetXid();
 
 	cifs_sb = CIFS_SB(inode->i_sb);
-	tcon = cifs_sb->tcon;
+	tcon = cifs_sb_tcon(cifs_sb);
 
 	pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
 	pCifsFile = cifs_fill_filedata(file);
@@ -370,7 +370,7 @@ int cifs_open(struct inode *inode, struct file *file)
 		goto out;
 	}
 
-	if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
+	if (cifs_sb_tcon(cifs_sb)->ses->capabilities & CAP_NT_SMBS)
 		rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
 			 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
 			 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
@@ -484,7 +484,7 @@ static int cifs_reopen_file(struct file *file, bool can_flush)
 	}
 
 	cifs_sb = CIFS_SB(inode->i_sb);
-	tcon = cifs_sb->tcon;
+	tcon = cifs_sb_tcon(cifs_sb);
 
 /* can not grab rename sem here because various ops, including
    those that already have the rename sem can end up causing writepage
@@ -599,7 +599,7 @@ int cifs_close(struct inode *inode, struct file *file)
 	xid = GetXid();
 
 	cifs_sb = CIFS_SB(inode->i_sb);
-	pTcon = cifs_sb->tcon;
+	pTcon = cifs_sb_tcon(cifs_sb);
 	if (pSMBFile) {
 		struct cifsLockInfo *li, *tmp;
 		write_lock(&GlobalSMBSeslock);
@@ -683,7 +683,7 @@ int cifs_closedir(struct inode *inode, struct file *file)
 		struct cifs_sb_info *cifs_sb =
 			CIFS_SB(file->f_path.dentry->d_sb);
 
-		pTcon = cifs_sb->tcon;
+		pTcon = cifs_sb_tcon(cifs_sb);
 
 		cFYI(1, ("Freeing private data in close dir"));
 		write_lock(&GlobalSMBSeslock);
@@ -793,7 +793,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
 		cFYI(1, ("Unknown type of lock"));
 
 	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
-	tcon = cifs_sb->tcon;
+	tcon = cifs_sb_tcon(cifs_sb);
 
 	if (file->private_data == NULL) {
 		rc = -EBADF;
@@ -986,7 +986,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
 
 	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
 
-	pTcon = cifs_sb->tcon;
+	pTcon = cifs_sb_tcon(cifs_sb);
 
 	/* cFYI(1,
 	   (" write %d bytes to offset %lld of %s", write_size,
@@ -1089,7 +1089,7 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
 
 	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
 
-	pTcon = cifs_sb->tcon;
+	pTcon = cifs_sb_tcon(cifs_sb);
 
 	cFYI(1, ("write %zd bytes to offset %lld of %s", write_size,
 	   *poffset, file->f_path.dentry->d_name.name));
@@ -1317,7 +1317,7 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
 
 	inode = page->mapping->host;
 	cifs_sb = CIFS_SB(inode->i_sb);
-	pTcon = cifs_sb->tcon;
+	pTcon = cifs_sb_tcon(cifs_sb);
 
 	offset += (loff_t)from;
 	write_data = kmap(page);
@@ -1392,7 +1392,7 @@ static int cifs_writepages(struct address_space *mapping,
 	if (cifs_sb->wsize < PAGE_CACHE_SIZE)
 		return generic_writepages(mapping, wbc);
 
-	if (cifs_sb->tcon->ses->sign && !experimEnabled)
+	if (cifs_sb_tcon(cifs_sb)->ses->sign && !experimEnabled)
 		return generic_writepages(mapping, wbc);
 
 	iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL);
@@ -1523,7 +1523,7 @@ retry:
 				rc = -EBADF;
 			} else {
 				long_op = cifs_write_timeout(cifsi, offset);
-				rc = CIFSSMBWrite2(xid, cifs_sb->tcon,
+				rc = CIFSSMBWrite2(xid, cifs_sb_tcon(cifs_sb),
 						   open_file->netfid,
 						   bytes_to_write, offset,
 						   &bytes_written, iov, n_iov,
@@ -1541,7 +1541,7 @@ retry:
 					else
 						set_bit(AS_EIO, &mapping->flags);
 				} else {
-					cifs_stats_bytes_written(cifs_sb->tcon,
+					cifs_stats_bytes_written(cifs_sb_tcon(cifs_sb),
 								 bytes_written);
 				}
 			}
@@ -1687,7 +1687,7 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
 	if (rc == 0) {
 		rc = CIFS_I(inode)->write_behind_rc;
 		CIFS_I(inode)->write_behind_rc = 0;
-		tcon = CIFS_SB(inode->i_sb)->tcon;
+		tcon = cifs_sb_tcon(CIFS_SB(inode->i_sb));
 		if (!rc && tcon && smbfile &&
 		   !(CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
 			rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
@@ -1772,7 +1772,7 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
 
 	xid = GetXid();
 	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
-	pTcon = cifs_sb->tcon;
+	pTcon = cifs_sb_tcon(cifs_sb);
 
 	if (file->private_data == NULL) {
 		rc = -EBADF;
@@ -1853,7 +1853,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
 
 	xid = GetXid();
 	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
-	pTcon = cifs_sb->tcon;
+	pTcon = cifs_sb_tcon(cifs_sb);
 
 	if (file->private_data == NULL) {
 		rc = -EBADF;
@@ -1996,7 +1996,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
 	}
 	open_file = (struct cifsFileInfo *)file->private_data;
 	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
-	pTcon = cifs_sb->tcon;
+	pTcon = cifs_sb_tcon(cifs_sb);
 
 	pagevec_init(&lru_pvec, 0);
 	cFYI(DBG2, ("rpages: num pages %d", num_pages));
@@ -2330,7 +2330,7 @@ cifs_oplock_break(struct slow_work *work)
 	 * disconnected since oplock already released by the server
 	 */
 	if (!cfile->closePend && !cfile->oplock_break_cancelled) {
-		rc = CIFSSMBLock(0, cifs_sb->tcon, cfile->netfid, 0, 0, 0, 0,
+		rc = CIFSSMBLock(0, cifs_sb_tcon(cifs_sb), cfile->netfid, 0, 0, 0, 0,
 				 LOCKING_ANDX_OPLOCK_RELEASE, false);
 		cFYI(1, ("Oplock release rc = %d", rc));
 	}
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 35ec117..cc473d5 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -51,7 +51,7 @@ static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral)
 
 
 		/* check if server can support readpages */
-		if (cifs_sb->tcon->ses->server->maxBuf <
+		if (cifs_sb_tcon(cifs_sb)->ses->server->maxBuf <
 				PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
 			inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
 		else
@@ -277,7 +277,7 @@ int cifs_get_file_info_unix(struct file *filp)
 	struct cifs_fattr fattr;
 	struct inode *inode = filp->f_path.dentry->d_inode;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
-	struct cifsTconInfo *tcon = cifs_sb->tcon;
+	struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb);
 	struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data;
 
 	xid = GetXid();
@@ -304,7 +304,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
 	struct cifsTconInfo *tcon;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
 
-	tcon = cifs_sb->tcon;
+	tcon = cifs_sb_tcon(cifs_sb);
 	cFYI(1, ("Getting info on %s", full_path));
 
 	/* could have done a find first instead but this returns more info */
@@ -341,7 +341,7 @@ cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path,
 	int rc;
 	int oplock = 0;
 	__u16 netfid;
-	struct cifsTconInfo *pTcon = cifs_sb->tcon;
+	struct cifsTconInfo *pTcon = cifs_sb_tcon(cifs_sb);
 	char buf[24];
 	unsigned int bytes_read;
 	char *pbuf;
@@ -430,7 +430,7 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path,
 	char ea_value[4];
 	__u32 mode;
 
-	rc = CIFSSMBQAllEAs(xid, cifs_sb->tcon, path, "SETFILEBITS",
+	rc = CIFSSMBQAllEAs(xid, cifs_sb_tcon(cifs_sb), path, "SETFILEBITS",
 			    ea_value, 4 /* size of buf */, cifs_sb->local_nls,
 			    cifs_sb->mnt_cifs_flags &
 				CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -470,8 +470,8 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
 	fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);
 
 	if (adjust_tz) {
-		fattr->cf_ctime.tv_sec += cifs_sb->tcon->ses->server->timeAdj;
-		fattr->cf_mtime.tv_sec += cifs_sb->tcon->ses->server->timeAdj;
+		fattr->cf_ctime.tv_sec += cifs_sb_tcon(cifs_sb)->ses->server->timeAdj;
+		fattr->cf_mtime.tv_sec += cifs_sb_tcon(cifs_sb)->ses->server->timeAdj;
 	}
 
 	fattr->cf_eof = le64_to_cpu(info->EndOfFile);
@@ -503,7 +503,7 @@ int cifs_get_file_info(struct file *filp)
 	struct cifs_fattr fattr;
 	struct inode *inode = filp->f_path.dentry->d_inode;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
-	struct cifsTconInfo *tcon = cifs_sb->tcon;
+	struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb);
 	struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data;
 
 	xid = GetXid();
@@ -547,7 +547,7 @@ int cifs_get_inode_info(struct inode **pinode,
 	bool adjustTZ = false;
 	struct cifs_fattr fattr;
 
-	pTcon = cifs_sb->tcon;
+	pTcon = cifs_sb_tcon(cifs_sb);
 	cFYI(1, ("Getting info on %s", full_path));
 
 	if ((pfindData == NULL) && (*pinode != NULL)) {
@@ -680,8 +680,8 @@ char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb)
 		return full_path;
 	}
 
-	if (cifs_sb->tcon && (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS))
-		dfsplen = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE + 1);
+	if (cifs_sb_tcon(cifs_sb) && (cifs_sb_tcon(cifs_sb)->Flags & SMB_SHARE_IS_IN_DFS))
+		dfsplen = strnlen(cifs_sb_tcon(cifs_sb)->treeName, MAX_TREE_SIZE + 1);
 	else
 		dfsplen = 0;
 
@@ -690,7 +690,7 @@ char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb)
 		return full_path;
 
 	if (dfsplen) {
-		strncpy(full_path, cifs_sb->tcon->treeName, dfsplen);
+		strncpy(full_path, cifs_sb_tcon(cifs_sb)->treeName, dfsplen);
 		/* switch slash direction in prepath depending on whether
 		 * windows or posix style path names
 		 */
@@ -770,7 +770,7 @@ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino)
 		return ERR_PTR(-ENOMEM);
 
 	xid = GetXid();
-	if (cifs_sb->tcon->unix_ext)
+	if (cifs_sb_tcon(cifs_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,
@@ -779,7 +779,7 @@ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino)
 	if (!inode)
 		return ERR_PTR(-ENOMEM);
 
-	if (rc && cifs_sb->tcon->ipc) {
+	if (rc && cifs_sb_tcon(cifs_sb)->ipc) {
 		cFYI(1, ("ipc connection - fake read inode"));
 		inode->i_mode |= S_IFDIR;
 		inode->i_nlink = 2;
@@ -815,7 +815,7 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid,
 	struct cifsFileInfo *open_file;
 	struct cifsInodeInfo *cifsInode = CIFS_I(inode);
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
-	struct cifsTconInfo *pTcon = cifs_sb->tcon;
+	struct cifsTconInfo *pTcon = cifs_sb_tcon(cifs_sb);
 	FILE_BASIC_INFO	info_buf;
 
 	if (attrs == NULL)
@@ -921,7 +921,7 @@ cifs_rename_pending_delete(char *full_path, struct dentry *dentry, int xid)
 	struct inode *inode = dentry->d_inode;
 	struct cifsInodeInfo *cifsInode = CIFS_I(inode);
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
-	struct cifsTconInfo *tcon = cifs_sb->tcon;
+	struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb);
 	__u32 dosattr, origattr;
 	FILE_BASIC_INFO *info_buf = NULL;
 
@@ -1032,7 +1032,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
 	struct cifsInodeInfo *cifs_inode;
 	struct super_block *sb = dir->i_sb;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
-	struct cifsTconInfo *tcon = cifs_sb->tcon;
+	struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb);
 	struct iattr *attrs = NULL;
 	__u32 dosattr = 0, origattr = 0;
 
@@ -1134,7 +1134,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
 	xid = GetXid();
 
 	cifs_sb = CIFS_SB(inode->i_sb);
-	pTcon = cifs_sb->tcon;
+	pTcon = cifs_sb_tcon(cifs_sb);
 
 	full_path = build_path_from_dentry(direntry);
 	if (full_path == NULL) {
@@ -1314,7 +1314,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
 	xid = GetXid();
 
 	cifs_sb = CIFS_SB(inode->i_sb);
-	pTcon = cifs_sb->tcon;
+	pTcon = cifs_sb_tcon(cifs_sb);
 
 	full_path = build_path_from_dentry(direntry);
 	if (full_path == NULL) {
@@ -1355,7 +1355,7 @@ cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath,
 		struct dentry *to_dentry, const char *toPath)
 {
 	struct cifs_sb_info *cifs_sb = CIFS_SB(from_dentry->d_sb);
-	struct cifsTconInfo *pTcon = cifs_sb->tcon;
+	struct cifsTconInfo *pTcon = cifs_sb_tcon(cifs_sb);
 	__u16 srcfid;
 	int oplock, rc;
 
@@ -1404,7 +1404,7 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
 
 	cifs_sb_target = CIFS_SB(target_dir->i_sb);
 	cifs_sb_source = CIFS_SB(source_dir->i_sb);
-	tcon = cifs_sb_source->tcon;
+	tcon = cifs_sb_tcon(cifs_sb_source);
 
 	xid = GetXid();
 
@@ -1412,7 +1412,7 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
 	 * BB: this might be allowed if same server, but different share.
 	 * Consider adding support for this
 	 */
-	if (tcon != cifs_sb_target->tcon) {
+	if (tcon != cifs_sb_tcon(cifs_sb_target)) {
 		rc = -EXDEV;
 		goto cifs_rename_exit;
 	}
@@ -1540,7 +1540,7 @@ int cifs_revalidate_file(struct file *filp)
 	if (!cifs_inode_needs_reval(inode))
 		goto check_inval;
 
-	if (CIFS_SB(inode->i_sb)->tcon->unix_ext)
+	if (cifs_sb_tcon(CIFS_SB(inode->i_sb))->unix_ext)
 		rc = cifs_get_file_info_unix(filp);
 	else
 		rc = cifs_get_file_info(filp);
@@ -1581,7 +1581,7 @@ int cifs_revalidate_dentry(struct dentry *dentry)
 		 "jiffies %ld", full_path, inode, inode->i_count.counter,
 		 dentry, dentry->d_time, jiffies));
 
-	if (CIFS_SB(sb)->tcon->unix_ext)
+	if (cifs_sb_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,
@@ -1655,7 +1655,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
 	struct cifsFileInfo *open_file;
 	struct cifsInodeInfo *cifsInode = CIFS_I(inode);
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
-	struct cifsTconInfo *pTcon = cifs_sb->tcon;
+	struct cifsTconInfo *pTcon = cifs_sb_tcon(cifs_sb);
 
 	/*
 	 * To avoid spurious oplock breaks from server, in the case of
@@ -1733,7 +1733,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
 	struct inode *inode = direntry->d_inode;
 	struct cifsInodeInfo *cifsInode = CIFS_I(inode);
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
-	struct cifsTconInfo *pTcon = cifs_sb->tcon;
+	struct cifsTconInfo *pTcon = cifs_sb_tcon(cifs_sb);
 	struct cifs_unix_set_info_args *args = NULL;
 	struct cifsFileInfo *open_file;
 
@@ -1999,7 +1999,7 @@ cifs_setattr(struct dentry *direntry, struct iattr *attrs)
 {
 	struct inode *inode = direntry->d_inode;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
-	struct cifsTconInfo *pTcon = cifs_sb->tcon;
+	struct cifsTconInfo *pTcon = cifs_sb_tcon(cifs_sb);
 
 	if (pTcon->unix_ext)
 		return cifs_setattr_unix(direntry, attrs);
diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c
index f946506..c28dc62 100644
--- a/fs/cifs/ioctl.c
+++ b/fs/cifs/ioctl.c
@@ -52,7 +52,7 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
 	cifs_sb = CIFS_SB(inode->i_sb);
 
 #ifdef CONFIG_CIFS_POSIX
-	tcon = cifs_sb->tcon;
+	tcon = cifs_sb_tcon(cifs_sb);
 	if (tcon)
 		caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
 	else {
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index c1a9d42..deff001 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -44,7 +44,7 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
 	xid = GetXid();
 
 	cifs_sb_target = CIFS_SB(inode->i_sb);
-	pTcon = cifs_sb_target->tcon;
+	pTcon = cifs_sb_tcon(cifs_sb_target);
 
 /* No need to check for cross device links since server will do that
    BB note DFS case in future though (when we may have to check) */
@@ -113,7 +113,7 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
 	char *full_path = NULL;
 	char *target_path = NULL;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
-	struct cifsTconInfo *tcon = cifs_sb->tcon;
+	struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb);
 
 	xid = GetXid();
 
@@ -168,7 +168,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
 	xid = GetXid();
 
 	cifs_sb = CIFS_SB(inode->i_sb);
-	pTcon = cifs_sb->tcon;
+	pTcon = cifs_sb_tcon(cifs_sb);
 
 	full_path = build_path_from_dentry(direntry);
 
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 7b783d1..789cf12 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -724,6 +724,6 @@ cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb)
 			   "properly. Hardlinks will not be recognized on this "
 			   "mount. Consider mounting with the \"noserverino\" "
 			   "option to silence this message.",
-			   cifs_sb->tcon->treeName));
+			   cifs_sb_tcon(cifs_sb)->treeName));
 	}
 }
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 18e0bc1..9854d09 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -102,7 +102,7 @@ cifs_readdir_lookup(struct dentry *parent, struct qstr *name,
 		return NULL;
 	}
 
-	if (CIFS_SB(sb)->tcon->nocase)
+	if (cifs_sb_tcon(CIFS_SB(sb))->nocase)
 		dentry->d_op = &cifs_ci_dentry_ops;
 	else
 		dentry->d_op = &cifs_dentry_ops;
@@ -171,7 +171,7 @@ static void
 cifs_std_info_to_fattr(struct cifs_fattr *fattr, FIND_FILE_STANDARD_INFO *info,
 		       struct cifs_sb_info *cifs_sb)
 {
-	int offset = cifs_sb->tcon->ses->server->timeAdj;
+	int offset = cifs_sb_tcon(cifs_sb)->ses->server->timeAdj;
 
 	memset(fattr, 0, sizeof(*fattr));
 	fattr->cf_atime = cnvrtDosUnixTm(info->LastAccessDate,
@@ -199,7 +199,7 @@ int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb,
 	int len;
 	int oplock = 0;
 	int rc;
-	struct cifsTconInfo *ptcon = cifs_sb->tcon;
+	struct cifsTconInfo *ptcon = cifs_sb_tcon(cifs_sb);
 	char *tmpbuffer;
 
 	rc = CIFSSMBOpen(xid, ptcon, full_path, FILE_OPEN, GENERIC_READ,
@@ -243,7 +243,7 @@ static int initiate_cifs_search(const int xid, struct file *file)
 	if (cifs_sb == NULL)
 		return -EINVAL;
 
-	pTcon = cifs_sb->tcon;
+	pTcon = cifs_sb_tcon(cifs_sb);
 	if (pTcon == NULL)
 		return -EINVAL;
 
@@ -778,7 +778,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
 	xid = GetXid();
 
 	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
-	pTcon = cifs_sb->tcon;
+	pTcon = cifs_sb_tcon(cifs_sb);
 	if (pTcon == NULL)
 		return -EINVAL;
 
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c
index f555ce0..2161019 100644
--- a/fs/cifs/xattr.c
+++ b/fs/cifs/xattr.c
@@ -61,7 +61,7 @@ int cifs_removexattr(struct dentry *direntry, const char *ea_name)
 	xid = GetXid();
 
 	cifs_sb = CIFS_SB(sb);
-	pTcon = cifs_sb->tcon;
+	pTcon = cifs_sb_tcon(cifs_sb);
 
 	full_path = build_path_from_dentry(direntry);
 	if (full_path == NULL) {
@@ -116,7 +116,7 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
 	xid = GetXid();
 
 	cifs_sb = CIFS_SB(sb);
-	pTcon = cifs_sb->tcon;
+	pTcon = cifs_sb_tcon(cifs_sb);
 
 	full_path = build_path_from_dentry(direntry);
 	if (full_path == NULL) {
@@ -224,7 +224,7 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
 	xid = GetXid();
 
 	cifs_sb = CIFS_SB(sb);
-	pTcon = cifs_sb->tcon;
+	pTcon = cifs_sb_tcon(cifs_sb);
 
 	full_path = build_path_from_dentry(direntry);
 	if (full_path == NULL) {
@@ -346,7 +346,7 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
 		return -EIO;
 
 	cifs_sb = CIFS_SB(sb);
-	pTcon = cifs_sb->tcon;
+	pTcon = cifs_sb_tcon(cifs_sb);
 
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
 		return -EOPNOTSUPP;
-- 
1.6.6.1

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

* [PATCH 02/11] cifs: add tcon field to cifsFileInfo struct
  2010-04-20 20:07 [PATCH 00/11] cifs: implement multisession mounts (try #2) Jeff Layton
  2010-04-20 20:07 ` [PATCH 01/11] cifs: add function to get a tcon from cifs_sb Jeff Layton
@ 2010-04-20 20:07 ` Jeff Layton
  2010-04-20 20:07 ` [PATCH 03/11] cifs: make various routines use the cifsFileInfo->tcon pointer Jeff Layton
                   ` (10 subsequent siblings)
  12 siblings, 0 replies; 24+ messages in thread
From: Jeff Layton @ 2010-04-20 20:07 UTC (permalink / raw)
  To: linux-cifs-client, linux-fsdevel; +Cc: smfrench

With more than one tcon per mount, we need to know which one is
associated with a particular fid.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/cifs/cifsglob.h |    1 +
 fs/cifs/dir.c      |    1 +
 2 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 79a75c4..ca9dd9d 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -342,6 +342,7 @@ struct cifsFileInfo {
 	struct file *pfile; /* needed for writepage */
 	struct inode *pInode; /* needed for oplock break */
 	struct vfsmount *mnt;
+	struct cifsTconInfo *tcon;
 	struct mutex lock_mutex;
 	struct list_head llist; /* list of byte range locks we have. */
 	bool closePend:1;	/* file is marked to close */
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 572d31c..b482486 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -153,6 +153,7 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle,
 	pCifsFile->pfile = file;
 	pCifsFile->invalidHandle = false;
 	pCifsFile->closePend = false;
+	pCifsFile->tcon = cifs_sb_tcon(cifs_sb);
 	mutex_init(&pCifsFile->fh_mutex);
 	mutex_init(&pCifsFile->lock_mutex);
 	INIT_LIST_HEAD(&pCifsFile->llist);
-- 
1.6.6.1

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

* [PATCH 03/11] cifs: make various routines use the cifsFileInfo->tcon pointer
  2010-04-20 20:07 [PATCH 00/11] cifs: implement multisession mounts (try #2) Jeff Layton
  2010-04-20 20:07 ` [PATCH 01/11] cifs: add function to get a tcon from cifs_sb Jeff Layton
  2010-04-20 20:07 ` [PATCH 02/11] cifs: add tcon field to cifsFileInfo struct Jeff Layton
@ 2010-04-20 20:07 ` Jeff Layton
  2010-04-20 20:07 ` [PATCH 04/11] cifs: have find_readable/writable_file filter by fsuid Jeff Layton
                   ` (9 subsequent siblings)
  12 siblings, 0 replies; 24+ messages in thread
From: Jeff Layton @ 2010-04-20 20:07 UTC (permalink / raw)
  To: linux-cifs-client, linux-fsdevel; +Cc: smfrench

...where it's available and appropriate.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/cifs/cifsfs.c  |    4 ++--
 fs/cifs/file.c    |   38 +++++++++++++++++---------------------
 fs/cifs/inode.c   |   22 ++++++++++++++++------
 fs/cifs/ioctl.c   |   19 ++++---------------
 fs/cifs/readdir.c |   18 ++++++++----------
 5 files changed, 47 insertions(+), 54 deletions(-)

diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 211dcbf..3f84df6 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -652,6 +652,7 @@ static int cifs_setlease(struct file *file, long arg, struct file_lock **lease)
 	/* note that this is called by vfs setlease with the BKL held
 	   although I doubt that BKL is needed here in cifs */
 	struct inode *inode = file->f_path.dentry->d_inode;
+	struct cifsFileInfo *cfile = file->private_data;
 
 	if (!(S_ISREG(inode->i_mode)))
 		return -EINVAL;
@@ -662,8 +663,7 @@ static int cifs_setlease(struct file *file, long arg, struct file_lock **lease)
 	    ((arg == F_WRLCK) &&
 		(CIFS_I(inode)->clientCanCacheAll)))
 		return generic_setlease(file, arg, lease);
-	else if (cifs_sb_tcon(CIFS_SB(inode->i_sb))->local_lease &&
-			!CIFS_I(inode)->clientCanCacheRead)
+	else if (cfile->tcon->local_lease && !CIFS_I(inode)->clientCanCacheRead)
 		/* If the server claims to support oplock on this
 		   file, then we still need to check oplock even
 		   if the local_lease mount option is set, but there
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 2e4771f..ba8a61f 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -484,7 +484,7 @@ static int cifs_reopen_file(struct file *file, bool can_flush)
 	}
 
 	cifs_sb = CIFS_SB(inode->i_sb);
-	tcon = cifs_sb_tcon(cifs_sb);
+	tcon = pCifsFile->tcon;
 
 /* can not grab rename sem here because various ops, including
    those that already have the rename sem can end up causing writepage
@@ -599,7 +599,7 @@ int cifs_close(struct inode *inode, struct file *file)
 	xid = GetXid();
 
 	cifs_sb = CIFS_SB(inode->i_sb);
-	pTcon = cifs_sb_tcon(cifs_sb);
+	pTcon = pSMBFile->tcon;
 	if (pSMBFile) {
 		struct cifsLockInfo *li, *tmp;
 		write_lock(&GlobalSMBSeslock);
@@ -680,10 +680,7 @@ int cifs_closedir(struct inode *inode, struct file *file)
 
 	if (pCFileStruct) {
 		struct cifsTconInfo *pTcon;
-		struct cifs_sb_info *cifs_sb =
-			CIFS_SB(file->f_path.dentry->d_sb);
-
-		pTcon = cifs_sb_tcon(cifs_sb);
+		pTcon = pCFileStruct->tcon;
 
 		cFYI(1, ("Freeing private data in close dir"));
 		write_lock(&GlobalSMBSeslock);
@@ -793,7 +790,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
 		cFYI(1, ("Unknown type of lock"));
 
 	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
-	tcon = cifs_sb_tcon(cifs_sb);
+	tcon = ((struct cifsFileInfo *)file->private_data)->tcon;
 
 	if (file->private_data == NULL) {
 		rc = -EBADF;
@@ -986,8 +983,6 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
 
 	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
 
-	pTcon = cifs_sb_tcon(cifs_sb);
-
 	/* cFYI(1,
 	   (" write %d bytes to offset %lld of %s", write_size,
 	   *poffset, file->f_path.dentry->d_name.name)); */
@@ -995,6 +990,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
 	if (file->private_data == NULL)
 		return -EBADF;
 	open_file = (struct cifsFileInfo *) file->private_data;
+	pTcon = open_file->tcon;
 
 	rc = generic_write_checks(file, poffset, &write_size, 0);
 	if (rc)
@@ -1089,14 +1085,14 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
 
 	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
 
-	pTcon = cifs_sb_tcon(cifs_sb);
-
 	cFYI(1, ("write %zd bytes to offset %lld of %s", write_size,
 	   *poffset, file->f_path.dentry->d_name.name));
 
 	if (file->private_data == NULL)
 		return -EBADF;
+
 	open_file = (struct cifsFileInfo *)file->private_data;
+	pTcon = open_file->tcon;
 
 	xid = GetXid();
 
@@ -1308,7 +1304,6 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
 	int rc = -EFAULT;
 	int bytes_written = 0;
 	struct cifs_sb_info *cifs_sb;
-	struct cifsTconInfo *pTcon;
 	struct inode *inode;
 	struct cifsFileInfo *open_file;
 
@@ -1317,7 +1312,6 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
 
 	inode = page->mapping->host;
 	cifs_sb = CIFS_SB(inode->i_sb);
-	pTcon = cifs_sb_tcon(cifs_sb);
 
 	offset += (loff_t)from;
 	write_data = kmap(page);
@@ -1376,6 +1370,7 @@ static int cifs_writepages(struct address_space *mapping,
 	int nr_pages;
 	__u64 offset = 0;
 	struct cifsFileInfo *open_file;
+	struct cifsTconInfo *tcon;
 	struct cifsInodeInfo *cifsi = CIFS_I(mapping->host);
 	struct page *page;
 	struct pagevec pvec;
@@ -1522,8 +1517,9 @@ retry:
 				cERROR(1, ("No writable handles for inode"));
 				rc = -EBADF;
 			} else {
+				tcon = open_file->tcon;
 				long_op = cifs_write_timeout(cifsi, offset);
-				rc = CIFSSMBWrite2(xid, cifs_sb_tcon(cifs_sb),
+				rc = CIFSSMBWrite2(xid, tcon,
 						   open_file->netfid,
 						   bytes_to_write, offset,
 						   &bytes_written, iov, n_iov,
@@ -1541,7 +1537,7 @@ retry:
 					else
 						set_bit(AS_EIO, &mapping->flags);
 				} else {
-					cifs_stats_bytes_written(cifs_sb_tcon(cifs_sb),
+					cifs_stats_bytes_written(tcon,
 								 bytes_written);
 				}
 			}
@@ -1687,7 +1683,7 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
 	if (rc == 0) {
 		rc = CIFS_I(inode)->write_behind_rc;
 		CIFS_I(inode)->write_behind_rc = 0;
-		tcon = cifs_sb_tcon(CIFS_SB(inode->i_sb));
+		tcon = smbfile->tcon;
 		if (!rc && tcon && smbfile &&
 		   !(CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
 			rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
@@ -1772,7 +1768,6 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
 
 	xid = GetXid();
 	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
-	pTcon = cifs_sb_tcon(cifs_sb);
 
 	if (file->private_data == NULL) {
 		rc = -EBADF;
@@ -1780,6 +1775,7 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
 		return rc;
 	}
 	open_file = (struct cifsFileInfo *)file->private_data;
+	pTcon = open_file->tcon;
 
 	if ((file->f_flags & O_ACCMODE) == O_WRONLY)
 		cFYI(1, ("attempting read on write only file instance"));
@@ -1853,14 +1849,15 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
 
 	xid = GetXid();
 	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
-	pTcon = cifs_sb_tcon(cifs_sb);
 
 	if (file->private_data == NULL) {
 		rc = -EBADF;
 		FreeXid(xid);
 		return rc;
 	}
+
 	open_file = (struct cifsFileInfo *)file->private_data;
+	pTcon = open_file->tcon;
 
 	if ((file->f_flags & O_ACCMODE) == O_WRONLY)
 		cFYI(1, ("attempting read on write only file instance"));
@@ -1996,7 +1993,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
 	}
 	open_file = (struct cifsFileInfo *)file->private_data;
 	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
-	pTcon = cifs_sb_tcon(cifs_sb);
+	pTcon = open_file->tcon;
 
 	pagevec_init(&lru_pvec, 0);
 	cFYI(DBG2, ("rpages: num pages %d", num_pages));
@@ -2301,7 +2298,6 @@ cifs_oplock_break(struct slow_work *work)
 						  oplock_break);
 	struct inode *inode = cfile->pInode;
 	struct cifsInodeInfo *cinode = CIFS_I(inode);
-	struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->mnt->mnt_sb);
 	int rc, waitrc = 0;
 
 	if (inode && S_ISREG(inode->i_mode)) {
@@ -2330,7 +2326,7 @@ cifs_oplock_break(struct slow_work *work)
 	 * disconnected since oplock already released by the server
 	 */
 	if (!cfile->closePend && !cfile->oplock_break_cancelled) {
-		rc = CIFSSMBLock(0, cifs_sb_tcon(cifs_sb), cfile->netfid, 0, 0, 0, 0,
+		rc = CIFSSMBLock(0, cfile->tcon, cfile->netfid, 0, 0, 0, 0,
 				 LOCKING_ANDX_OPLOCK_RELEASE, false);
 		cFYI(1, ("Oplock release rc = %d", rc));
 	}
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index cc473d5..0aa40d2 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -277,8 +277,8 @@ int cifs_get_file_info_unix(struct file *filp)
 	struct cifs_fattr fattr;
 	struct inode *inode = filp->f_path.dentry->d_inode;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
-	struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb);
 	struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data;
+	struct cifsTconInfo *tcon = cfile->tcon;
 
 	xid = GetXid();
 	rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->netfid, &find_data);
@@ -503,8 +503,8 @@ int cifs_get_file_info(struct file *filp)
 	struct cifs_fattr fattr;
 	struct inode *inode = filp->f_path.dentry->d_inode;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
-	struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb);
 	struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data;
+	struct cifsTconInfo *tcon = cfile->tcon;
 
 	xid = GetXid();
 	rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data);
@@ -815,7 +815,7 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid,
 	struct cifsFileInfo *open_file;
 	struct cifsInodeInfo *cifsInode = CIFS_I(inode);
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
-	struct cifsTconInfo *pTcon = cifs_sb_tcon(cifs_sb);
+	struct cifsTconInfo *pTcon;
 	FILE_BASIC_INFO	info_buf;
 
 	if (attrs == NULL)
@@ -858,9 +858,12 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid,
 	if (open_file) {
 		netfid = open_file->netfid;
 		netpid = open_file->pid;
+		pTcon = open_file->tcon;
 		goto set_via_filehandle;
 	}
 
+	pTcon = open_file->tcon;
+
 	/*
 	 * NT4 apparently returns success on this call, but it doesn't
 	 * really work.
@@ -1536,11 +1539,12 @@ int cifs_revalidate_file(struct file *filp)
 {
 	int rc = 0;
 	struct inode *inode = filp->f_path.dentry->d_inode;
+	struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data;
 
 	if (!cifs_inode_needs_reval(inode))
 		goto check_inval;
 
-	if (cifs_sb_tcon(CIFS_SB(inode->i_sb))->unix_ext)
+	if (cfile->tcon->unix_ext)
 		rc = cifs_get_file_info_unix(filp);
 	else
 		rc = cifs_get_file_info(filp);
@@ -1655,7 +1659,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
 	struct cifsFileInfo *open_file;
 	struct cifsInodeInfo *cifsInode = CIFS_I(inode);
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
-	struct cifsTconInfo *pTcon = cifs_sb_tcon(cifs_sb);
+	struct cifsTconInfo *pTcon = NULL;
 
 	/*
 	 * To avoid spurious oplock breaks from server, in the case of
@@ -1670,6 +1674,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
 	if (open_file) {
 		__u16 nfid = open_file->netfid;
 		__u32 npid = open_file->pid;
+		pTcon = open_file->tcon;
 		rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, nfid,
 					npid, false);
 		cifsFileInfo_put(open_file);
@@ -1684,6 +1689,9 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
 		rc = -EINVAL;
 
 	if (rc != 0) {
+		if (pTcon == NULL)
+			pTcon = cifs_sb_tcon(cifs_sb);
+
 		/* Set file size by pathname rather than by handle
 		   either because no valid, writeable file handle for
 		   it was found or because there was an error setting
@@ -1733,7 +1741,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
 	struct inode *inode = direntry->d_inode;
 	struct cifsInodeInfo *cifsInode = CIFS_I(inode);
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
-	struct cifsTconInfo *pTcon = cifs_sb_tcon(cifs_sb);
+	struct cifsTconInfo *pTcon;
 	struct cifs_unix_set_info_args *args = NULL;
 	struct cifsFileInfo *open_file;
 
@@ -1826,9 +1834,11 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
 	if (open_file) {
 		u16 nfid = open_file->netfid;
 		u32 npid = open_file->pid;
+		pTcon = open_file->tcon;
 		rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid);
 		cifsFileInfo_put(open_file);
 	} else {
+		pTcon = cifs_sb_tcon(cifs_sb);
 		rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args,
 				    cifs_sb->local_nls,
 				    cifs_sb->mnt_cifs_flags &
diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c
index c28dc62..a2c7ed4 100644
--- a/fs/cifs/ioctl.c
+++ b/fs/cifs/ioctl.c
@@ -37,12 +37,12 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
 	int xid;
 	struct cifs_sb_info *cifs_sb;
 #ifdef CONFIG_CIFS_POSIX
-	__u64	ExtAttrBits = 0;
-	__u64	ExtAttrMask = 0;
-	__u64   caps;
-	struct cifsTconInfo *tcon;
 	struct cifsFileInfo *pSMBFile =
 		(struct cifsFileInfo *)filep->private_data;
+	struct cifsTconInfo *tcon = pSMBFile->tcon;
+	__u64	ExtAttrBits = 0;
+	__u64	ExtAttrMask = 0;
+	__u64   caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
 #endif /* CONFIG_CIFS_POSIX */
 
 	xid = GetXid();
@@ -51,17 +51,6 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
 
 	cifs_sb = CIFS_SB(inode->i_sb);
 
-#ifdef CONFIG_CIFS_POSIX
-	tcon = cifs_sb_tcon(cifs_sb);
-	if (tcon)
-		caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
-	else {
-		rc = -EIO;
-		FreeXid(xid);
-		return -EIO;
-	}
-#endif /* CONFIG_CIFS_POSIX */
-
 	switch (command) {
 		case CIFS_IOC_CHECKUMOUNT:
 			cFYI(1, ("User unmount attempted"));
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 9854d09..17effab 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -228,22 +228,22 @@ static int initiate_cifs_search(const int xid, struct file *file)
 	struct cifs_sb_info *cifs_sb;
 	struct cifsTconInfo *pTcon;
 
-	if (file->private_data == NULL) {
+	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
+	if (cifs_sb == NULL)
+		return -EINVAL;
+
+	if (file->private_data == NULL)
 		file->private_data =
 			kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
-	}
 
 	if (file->private_data == NULL)
 		return -ENOMEM;
 	cifsFile = file->private_data;
 	cifsFile->invalidHandle = true;
 	cifsFile->srch_inf.endOfSearch = false;
+	cifsFile->tcon = cifs_sb_tcon(cifs_sb);
 
-	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
-	if (cifs_sb == NULL)
-		return -EINVAL;
-
-	pTcon = cifs_sb_tcon(cifs_sb);
+	pTcon = cifsFile->tcon;
 	if (pTcon == NULL)
 		return -EINVAL;
 
@@ -778,9 +778,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
 	xid = GetXid();
 
 	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
-	pTcon = cifs_sb_tcon(cifs_sb);
-	if (pTcon == NULL)
-		return -EINVAL;
 
 	switch ((int) file->f_pos) {
 	case 0:
@@ -830,6 +827,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
 			CIFSFindClose(xid, pTcon, cifsFile->netfid);
 		} */
 
+		pTcon = cifsFile->tcon;
 		rc = find_cifs_entry(xid, pTcon, file,
 				&current_entry, &num_to_fill);
 		if (rc) {
-- 
1.6.6.1

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

* [PATCH 04/11] cifs: have find_readable/writable_file filter by fsuid
  2010-04-20 20:07 [PATCH 00/11] cifs: implement multisession mounts (try #2) Jeff Layton
                   ` (2 preceding siblings ...)
  2010-04-20 20:07 ` [PATCH 03/11] cifs: make various routines use the cifsFileInfo->tcon pointer Jeff Layton
@ 2010-04-20 20:07 ` Jeff Layton
  2010-04-20 20:07 ` [PATCH 05/11] cifs: fix cifs_show_options to show "username=" or "multises" Jeff Layton
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 24+ messages in thread
From: Jeff Layton @ 2010-04-20 20:07 UTC (permalink / raw)
  To: linux-cifs-client, linux-fsdevel; +Cc: smfrench

When we implement multisession mounts, we'll need to filter filehandles
by fsuid. Add a flag for multisession mounts and code to filter by
fsuid when it's set.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/cifs/cifs_fs_sb.h |    3 ++-
 fs/cifs/cifsacl.c    |    4 ++--
 fs/cifs/cifsproto.h  |    4 ++--
 fs/cifs/dir.c        |    1 +
 fs/cifs/file.c       |   31 ++++++++++++++++++++++++-------
 fs/cifs/inode.c      |    6 +++---
 6 files changed, 34 insertions(+), 15 deletions(-)

diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
index 4797787..e658723 100644
--- a/fs/cifs/cifs_fs_sb.h
+++ b/fs/cifs/cifs_fs_sb.h
@@ -33,6 +33,7 @@
 #define CIFS_MOUNT_DYNPERM      0x1000 /* allow in-memory only mode setting   */
 #define CIFS_MOUNT_NOPOSIXBRL   0x2000 /* mandatory not posix byte range lock */
 #define CIFS_MOUNT_NOSSYNC      0x4000 /* don't do slow SMBflush on every sync*/
+#define CIFS_MOUNT_MULTISES	0x8000 /* multisession mount */
 
 struct cifs_sb_info {
 	struct cifsTconInfo *tcon;	/* primary mount */
@@ -44,7 +45,7 @@ struct cifs_sb_info {
 	gid_t	mnt_gid;
 	mode_t	mnt_file_mode;
 	mode_t	mnt_dir_mode;
-	int     mnt_cifs_flags;
+	unsigned int mnt_cifs_flags;
 	int	prepathlen;
 	char   *prepath; /* relative path under the share to mount to */
 #ifdef CONFIG_CIFS_DFS_UPCALL
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
index b8dd664..c2fb35c 100644
--- a/fs/cifs/cifsacl.c
+++ b/fs/cifs/cifsacl.c
@@ -603,7 +603,7 @@ static struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
 	struct cifsFileInfo *open_file = NULL;
 
 	if (inode)
-		open_file = find_readable_file(CIFS_I(inode));
+		open_file = find_readable_file(CIFS_I(inode), true);
 	if (!open_file)
 		return get_cifs_acl_by_path(cifs_sb, path, pacllen);
 
@@ -661,7 +661,7 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
 
 	cFYI(DBG2, ("set ACL for %s from mode 0x%x", path, inode->i_mode));
 
-	open_file = find_readable_file(CIFS_I(inode));
+	open_file = find_readable_file(CIFS_I(inode), true);
 	if (!open_file)
 		return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen);
 
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 55f3282..ca341fc 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -66,9 +66,9 @@ extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length);
 extern bool is_valid_oplock_break(struct smb_hdr *smb,
 				  struct TCP_Server_Info *);
 extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof);
-extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *);
+extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, bool);
 #ifdef CONFIG_CIFS_EXPERIMENTAL
-extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *);
+extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool);
 #endif
 extern unsigned int smbCalcSize(struct smb_hdr *ptr);
 extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr);
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index b482486..e563314 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -148,6 +148,7 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle,
 
 	pCifsFile->netfid = fileHandle;
 	pCifsFile->pid = current->tgid;
+	pCifsFile->uid = current_fsuid();
 	pCifsFile->pInode = igrab(newinode);
 	pCifsFile->mnt = mnt;
 	pCifsFile->pfile = file;
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index ba8a61f..651dde4 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1185,9 +1185,15 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
 }
 
 #ifdef CONFIG_CIFS_EXPERIMENTAL
-struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode)
+struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
+					bool fsuid_only)
 {
 	struct cifsFileInfo *open_file = NULL;
+	struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
+
+	/* only filter by fsuid on multisession mounts */
+	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTISES))
+		fsuid_only = false;
 
 	read_lock(&GlobalSMBSeslock);
 	/* we could simply get the first_list_entry since write-only entries
@@ -1196,6 +1202,8 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode)
 	list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
 		if (open_file->closePend)
 			continue;
+		if (fsuid_only && open_file->uid != current_fsuid())
+			continue;
 		if (open_file->pfile && ((open_file->pfile->f_flags & O_RDWR) ||
 		    (open_file->pfile->f_flags & O_RDONLY))) {
 			if (!open_file->invalidHandle) {
@@ -1215,9 +1223,11 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode)
 }
 #endif
 
-struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
+struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
+					bool fsuid_only)
 {
 	struct cifsFileInfo *open_file;
+	struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
 	bool any_available = false;
 	int rc;
 
@@ -1231,13 +1241,19 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
 		return NULL;
 	}
 
+	/* only filter by fsuid on multisession mounts */
+	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTISES))
+		fsuid_only = false;
+
 	read_lock(&GlobalSMBSeslock);
 refind_writable:
 	list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
-		if (open_file->closePend ||
-		    (!any_available && open_file->pid != current->tgid))
+		if (open_file->closePend)
+			continue;
+		if (!any_available && open_file->pid != current->tgid)
+			continue;
+		if (fsuid_only && open_file->uid != current_fsuid())
 			continue;
-
 		if (open_file->pfile &&
 		    ((open_file->pfile->f_flags & O_RDWR) ||
 		     (open_file->pfile->f_flags & O_WRONLY))) {
@@ -1332,7 +1348,7 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
 	if (mapping->host->i_size - offset < (loff_t)to)
 		to = (unsigned)(mapping->host->i_size - offset);
 
-	open_file = find_writable_file(CIFS_I(mapping->host));
+	open_file = find_writable_file(CIFS_I(mapping->host), false);
 	if (open_file) {
 		bytes_written = cifs_write(open_file->pfile, write_data,
 					   to-from, &offset);
@@ -1512,7 +1528,8 @@ retry:
 			 * CIFSSMBWrite2.  We can't rely on the last handle
 			 * we used to still be valid
 			 */
-			open_file = find_writable_file(CIFS_I(mapping->host));
+			open_file = find_writable_file(CIFS_I(mapping->host),
+							false);
 			if (!open_file) {
 				cERROR(1, ("No writable handles for inode"));
 				rc = -EBADF;
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 0aa40d2..e21feaa 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -854,7 +854,7 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid,
 	/*
 	 * If the file is already open for write, just use that fileid
 	 */
-	open_file = find_writable_file(cifsInode);
+	open_file = find_writable_file(cifsInode, true);
 	if (open_file) {
 		netfid = open_file->netfid;
 		netpid = open_file->pid;
@@ -1670,7 +1670,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
 	 * writebehind data than the SMB timeout for the SetPathInfo
 	 * request would allow
 	 */
-	open_file = find_writable_file(cifsInode);
+	open_file = find_writable_file(cifsInode, true);
 	if (open_file) {
 		__u16 nfid = open_file->netfid;
 		__u32 npid = open_file->pid;
@@ -1830,7 +1830,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
 		args->ctime = NO_CHANGE_64;
 
 	args->device = 0;
-	open_file = find_writable_file(cifsInode);
+	open_file = find_writable_file(cifsInode, true);
 	if (open_file) {
 		u16 nfid = open_file->netfid;
 		u32 npid = open_file->pid;
-- 
1.6.6.1

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

* [PATCH 05/11] cifs: fix cifs_show_options to show "username=" or "multises"
  2010-04-20 20:07 [PATCH 00/11] cifs: implement multisession mounts (try #2) Jeff Layton
                   ` (3 preceding siblings ...)
  2010-04-20 20:07 ` [PATCH 04/11] cifs: have find_readable/writable_file filter by fsuid Jeff Layton
@ 2010-04-20 20:07 ` Jeff Layton
  2010-04-20 20:07 ` [PATCH 06/11] cifs: have cifs_new_fileinfo take a tcon arg Jeff Layton
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 24+ messages in thread
From: Jeff Layton @ 2010-04-20 20:07 UTC (permalink / raw)
  To: linux-cifs-client, linux-fsdevel; +Cc: smfrench

...based on CIFS_MOUNT_MULTISES flag.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/cifs/cifsfs.c |    6 +++++-
 1 files changed, 5 insertions(+), 1 deletions(-)

diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 3f84df6..b9ceec0 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -362,8 +362,12 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m)
 	struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb);
 
 	seq_printf(s, ",unc=%s", tcon->treeName);
-	if (tcon->ses->userName)
+
+	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTISES)
+		seq_printf(s, ",multises");
+	else if (tcon->ses->userName)
 		seq_printf(s, ",username=%s", tcon->ses->userName);
+
 	if (tcon->ses->domainName)
 		seq_printf(s, ",domain=%s", tcon->ses->domainName);
 
-- 
1.6.6.1

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

* [PATCH 06/11] cifs: have cifs_new_fileinfo take a tcon arg
  2010-04-20 20:07 [PATCH 00/11] cifs: implement multisession mounts (try #2) Jeff Layton
                   ` (4 preceding siblings ...)
  2010-04-20 20:07 ` [PATCH 05/11] cifs: fix cifs_show_options to show "username=" or "multises" Jeff Layton
@ 2010-04-20 20:07 ` Jeff Layton
  2010-04-20 20:07 ` [PATCH 07/11] cifs: allow for cifs_sb_tcon() to return an error Jeff Layton
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 24+ messages in thread
From: Jeff Layton @ 2010-04-20 20:07 UTC (permalink / raw)
  To: linux-cifs-client, linux-fsdevel; +Cc: smfrench

To minimize calls to cifs_sb_tcon and to allow for a clear error path if
a tcon can't be acquired.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/cifs/dir.c  |   26 ++++++++++++++++++--------
 fs/cifs/file.c |    6 +++++-
 2 files changed, 23 insertions(+), 9 deletions(-)

diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index e563314..05ee024 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -131,8 +131,9 @@ cifs_bp_rename_retry:
 }
 
 struct cifsFileInfo *
-cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle,
-		  struct file *file, struct vfsmount *mnt, unsigned int oflags)
+cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, struct file *file,
+		  struct vfsmount *mnt, struct cifsTconInfo *tcon,
+		  unsigned int oflags)
 {
 	int oplock = 0;
 	struct cifsFileInfo *pCifsFile;
@@ -154,7 +155,7 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle,
 	pCifsFile->pfile = file;
 	pCifsFile->invalidHandle = false;
 	pCifsFile->closePend = false;
-	pCifsFile->tcon = cifs_sb_tcon(cifs_sb);
+	pCifsFile->tcon = tcon;
 	mutex_init(&pCifsFile->fh_mutex);
 	mutex_init(&pCifsFile->lock_mutex);
 	INIT_LIST_HEAD(&pCifsFile->llist);
@@ -193,6 +194,10 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
 	__u32 posix_flags = 0;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(mnt->mnt_sb);
 	struct cifs_fattr fattr;
+	struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb);
+
+	if (IS_ERR(tcon))
+		return PTR_ERR(tcon);
 
 	cFYI(1, ("posix open %s", full_path));
 
@@ -227,9 +232,9 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
 		posix_flags |= SMB_O_DIRECT;
 
 	mode &= ~current_umask();
-	rc = CIFSPOSIXCreate(xid, cifs_sb_tcon(cifs_sb), posix_flags, mode,
-			pnetfid, presp_data, poplock, full_path,
-			cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
+	rc = CIFSPOSIXCreate(xid, tcon, posix_flags, mode, pnetfid, presp_data,
+			     poplock, full_path, cifs_sb->local_nls,
+			     cifs_sb->mnt_cifs_flags &
 					CIFS_MOUNT_MAP_SPECIAL_CHR);
 	if (rc)
 		goto posix_open_ret;
@@ -253,7 +258,7 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
 		cifs_fattr_to_inode(*pinode, &fattr);
 	}
 
-	cifs_new_fileinfo(*pinode, *pnetfid, NULL, mnt, oflags);
+	cifs_new_fileinfo(*pinode, *pnetfid, NULL, mnt, tcon, oflags);
 
 posix_open_ret:
 	kfree(presp_data);
@@ -304,6 +309,11 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
 	cifs_sb = CIFS_SB(inode->i_sb);
 	tcon = cifs_sb_tcon(cifs_sb);
 
+	if (IS_ERR(tcon)) {
+		FreeXid(xid);
+		return PTR_ERR(tcon);
+	}
+
 	full_path = build_path_from_dentry(direntry);
 	if (full_path == NULL) {
 		rc = -ENOMEM;
@@ -467,7 +477,7 @@ cifs_create_set_dentry:
 		CIFSSMBClose(xid, tcon, fileHandle);
 	} else if (!(posix_create) && (newinode)) {
 			cifs_new_fileinfo(newinode, fileHandle, NULL,
-						nd->path.mnt, oflags);
+					  nd->path.mnt, tcon, oflags);
 	}
 cifs_create_out:
 	kfree(buf);
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 651dde4..26665b8 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -269,6 +269,10 @@ int cifs_open(struct inode *inode, struct file *file)
 
 	cifs_sb = CIFS_SB(inode->i_sb);
 	tcon = cifs_sb_tcon(cifs_sb);
+	if (IS_ERR(tcon)) {
+		FreeXid(xid);
+		return PTR_ERR(tcon);
+	}
 
 	pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
 	pCifsFile = cifs_fill_filedata(file);
@@ -391,7 +395,7 @@ int cifs_open(struct inode *inode, struct file *file)
 	}
 
 	pCifsFile = cifs_new_fileinfo(inode, netfid, file, file->f_path.mnt,
-					file->f_flags);
+				      tcon, file->f_flags);
 	file->private_data = pCifsFile;
 	if (file->private_data == NULL) {
 		rc = -ENOMEM;
-- 
1.6.6.1

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

* [PATCH 07/11] cifs: allow for cifs_sb_tcon() to return an error
  2010-04-20 20:07 [PATCH 00/11] cifs: implement multisession mounts (try #2) Jeff Layton
                   ` (5 preceding siblings ...)
  2010-04-20 20:07 ` [PATCH 06/11] cifs: have cifs_new_fileinfo take a tcon arg Jeff Layton
@ 2010-04-20 20:07 ` Jeff Layton
  2010-04-20 20:07 ` [PATCH 08/11] cifs: fix handling of signing with writepages Jeff Layton
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 24+ messages in thread
From: Jeff Layton @ 2010-04-20 20:07 UTC (permalink / raw)
  To: linux-cifs-client, linux-fsdevel; +Cc: smfrench

Fix the callers to expect and handle it properly.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/cifs/cifs_dfs_ref.c |   10 ++--
 fs/cifs/cifsacl.c      |   32 ++++++++++---
 fs/cifs/cifsfs.c       |   69 ++++++++++------------------
 fs/cifs/cifsglob.h     |    6 --
 fs/cifs/cifsproto.h    |    5 ++-
 fs/cifs/dir.c          |   47 +++++++++++--------
 fs/cifs/file.c         |   12 +++--
 fs/cifs/inode.c        |  120 +++++++++++++++++++++++++++++++++++++----------
 fs/cifs/link.c         |   13 +++++-
 fs/cifs/misc.c         |    2 +-
 fs/cifs/readdir.c      |   12 +++--
 fs/cifs/xattr.c        |   23 +++++++++-
 12 files changed, 229 insertions(+), 122 deletions(-)

diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c
index fc7035a..f3edaf3 100644
--- a/fs/cifs/cifs_dfs_ref.c
+++ b/fs/cifs/cifs_dfs_ref.c
@@ -308,6 +308,7 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
 	struct dfs_info3_param *referrals = NULL;
 	unsigned int num_referrals = 0;
 	struct cifs_sb_info *cifs_sb;
+	struct cifsTconInfo *tcon;
 	struct cifsSesInfo *ses;
 	char *full_path = NULL;
 	int xid, i;
@@ -323,13 +324,14 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
 	nd->path.dentry = dget(dentry);
 
 	cifs_sb = CIFS_SB(dentry->d_inode->i_sb);
-	ses = cifs_sb_tcon(cifs_sb)->ses;
-
-	if (!ses) {
-		rc = -EINVAL;
+	tcon = cifs_sb_tcon(cifs_sb);
+	if (IS_ERR(tcon)) {
+		rc = PTR_ERR(tcon);
 		goto out_err;
 	}
 
+	ses = tcon->ses;
+
 	/*
 	 * The MSDFS spec states that paths in DFS referral requests and
 	 * responses must be prefixed by a single '\' character instead of
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
index c2fb35c..673a0dc 100644
--- a/fs/cifs/cifsacl.c
+++ b/fs/cifs/cifsacl.c
@@ -556,10 +556,14 @@ static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
 		__u16 fid, u32 *pacllen)
 {
 	struct cifs_ntsd *pntsd = NULL;
+	struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb);
 	int xid, rc;
 
+	if (IS_ERR(tcon))
+		return (struct cifs_ntsd *) tcon;
+
 	xid = GetXid();
-	rc = CIFSSMBGetCIFSACL(xid, cifs_sb_tcon(cifs_sb), fid, &pntsd, pacllen);
+	rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
 	FreeXid(xid);
 
 
@@ -571,13 +575,17 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
 		const char *path, u32 *pacllen)
 {
 	struct cifs_ntsd *pntsd = NULL;
+	struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb);
 	int oplock = 0;
 	int xid, rc;
 	__u16 fid;
 
+	if (IS_ERR(tcon))
+		return (struct cifs_ntsd *) tcon;
+
 	xid = GetXid();
 
-	rc = CIFSSMBOpen(xid, cifs_sb_tcon(cifs_sb), path, FILE_OPEN, READ_CONTROL, 0,
+	rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL, 0,
 			 &fid, &oplock, NULL, cifs_sb->local_nls,
 			 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 	if (rc) {
@@ -585,10 +593,10 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
 		goto out;
 	}
 
-	rc = CIFSSMBGetCIFSACL(xid, cifs_sb_tcon(cifs_sb), fid, &pntsd, pacllen);
+	rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
 	cFYI(1, ("GetCIFSACL rc = %d ACL len %d", rc, *pacllen));
 
-	CIFSSMBClose(xid, cifs_sb_tcon(cifs_sb), fid);
+	CIFSSMBClose(xid, tcon, fid);
  out:
 	FreeXid(xid);
 	return pntsd;
@@ -616,9 +624,13 @@ static int set_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, __u16 fid,
 		struct cifs_ntsd *pnntsd, u32 acllen)
 {
 	int xid, rc;
+	struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb);
+
+	if (IS_ERR(tcon))
+		return PTR_ERR(tcon);
 
 	xid = GetXid();
-	rc = CIFSSMBSetCIFSACL(xid, cifs_sb_tcon(cifs_sb), fid, pnntsd, acllen);
+	rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen);
 	FreeXid(xid);
 
 	cFYI(DBG2, ("SetCIFSACL rc = %d", rc));
@@ -631,10 +643,14 @@ static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path,
 	int oplock = 0;
 	int xid, rc;
 	__u16 fid;
+	struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb);
+
+	if (IS_ERR(tcon))
+		return PTR_ERR(tcon);
 
 	xid = GetXid();
 
-	rc = CIFSSMBOpen(xid, cifs_sb_tcon(cifs_sb), path, FILE_OPEN, WRITE_DAC, 0,
+	rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, WRITE_DAC, 0,
 			 &fid, &oplock, NULL, cifs_sb->local_nls,
 			 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 	if (rc) {
@@ -642,10 +658,10 @@ static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path,
 		goto out;
 	}
 
-	rc = CIFSSMBSetCIFSACL(xid, cifs_sb_tcon(cifs_sb), fid, pnntsd, acllen);
+	rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen);
 	cFYI(DBG2, ("SetCIFSACL rc = %d", rc));
 
-	CIFSSMBClose(xid, cifs_sb_tcon(cifs_sb), fid);
+	CIFSSMBClose(xid, tcon, fid);
  out:
 	FreeXid(xid);
 	return rc;
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index b9ceec0..10137f4 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -102,6 +102,8 @@ cifs_read_super(struct super_block *sb, void *data,
 	cifs_sb = CIFS_SB(sb);
 	if (cifs_sb == NULL)
 		return -ENOMEM;
+	INIT_RADIX_TREE(&cifs_sb->tcon_tree, GFP_KERNEL);
+	spin_lock_init(&cifs_sb->tcon_tree_lock);
 
 #ifdef CONFIG_CIFS_DFS_UPCALL
 	/* copy mount params to sb for use in submounts */
@@ -228,6 +230,9 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
 	int rc = -EOPNOTSUPP;
 	int xid;
 
+	if (IS_ERR(tcon))
+		return PTR_ERR(tcon);
+
 	xid = GetXid();
 
 	buf->f_type = CIFS_MAGIC_NUMBER;
@@ -359,7 +364,7 @@ static int
 cifs_show_options(struct seq_file *s, struct vfsmount *m)
 {
 	struct cifs_sb_info *cifs_sb = CIFS_SB(m->mnt_sb);
-	struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb);
+	struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb);
 
 	seq_printf(s, ",unc=%s", tcon->treeName);
 
@@ -433,20 +438,13 @@ int cifs_xquota_set(struct super_block *sb, int quota_type, qid_t qid,
 	int xid;
 	int rc = 0;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
-	struct cifsTconInfo *pTcon;
-
-	if (cifs_sb)
-		pTcon = cifs_sb_tcon(cifs_sb);
-	else
-		return -EIO;
+	struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb);
 
+	if (IS_ERR(tcon))
+		return PTR_ERR(tcon);
 
 	xid = GetXid();
-	if (pTcon) {
-		cFYI(1, ("set type: 0x%x id: %d", quota_type, qid));
-	} else
-		rc = -EIO;
-
+	cFYI(1, ("set type: 0x%x id: %d", quota_type, qid));
 	FreeXid(xid);
 	return rc;
 }
@@ -457,19 +455,13 @@ int cifs_xquota_get(struct super_block *sb, int quota_type, qid_t qid,
 	int xid;
 	int rc = 0;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
-	struct cifsTconInfo *pTcon;
+	struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb);
 
-	if (cifs_sb)
-		pTcon = cifs_sb_tcon(cifs_sb);
-	else
-		return -EIO;
+	if (IS_ERR(tcon))
+		return PTR_ERR(tcon);
 
 	xid = GetXid();
-	if (pTcon) {
-		cFYI(1, ("set type: 0x%x id: %d", quota_type, qid));
-	} else
-		rc = -EIO;
-
+	cFYI(1, ("set type: 0x%x id: %d", quota_type, qid));
 	FreeXid(xid);
 	return rc;
 }
@@ -479,19 +471,13 @@ int cifs_xstate_set(struct super_block *sb, unsigned int flags, int operation)
 	int xid;
 	int rc = 0;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
-	struct cifsTconInfo *pTcon;
+	struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb);
 
-	if (cifs_sb)
-		pTcon = cifs_sb_tcon(cifs_sb);
-	else
-		return -EIO;
+	if (IS_ERR(tcon))
+		return PTR_ERR(tcon);
 
 	xid = GetXid();
-	if (pTcon) {
-		cFYI(1, ("flags: 0x%x operation: 0x%x", flags, operation));
-	} else
-		rc = -EIO;
-
+	cFYI(1, ("flags: 0x%x operation: 0x%x", flags, operation));
 	FreeXid(xid);
 	return rc;
 }
@@ -501,19 +487,13 @@ int cifs_xstate_get(struct super_block *sb, struct fs_quota_stat *qstats)
 	int xid;
 	int rc = 0;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
-	struct cifsTconInfo *pTcon;
+	struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb);
 
-	if (cifs_sb)
-		pTcon = cifs_sb_tcon(cifs_sb);
-	else
-		return -EIO;
+	if (IS_ERR(tcon))
+		return PTR_ERR(tcon);
 
 	xid = GetXid();
-	if (pTcon) {
-		cFYI(1, ("pqstats %p", qstats));
-	} else
-		rc = -EIO;
-
+	cFYI(1, ("pqstats %p", qstats));
 	FreeXid(xid);
 	return rc;
 }
@@ -534,9 +514,8 @@ static void cifs_umount_begin(struct super_block *sb)
 	if (cifs_sb == NULL)
 		return;
 
-	tcon = cifs_sb_tcon(cifs_sb);
-	if (tcon == NULL)
-		return;
+	/* FIXME: handle multisession case properly */
+	tcon = cifs_sb_master_tcon(cifs_sb);
 
 	read_lock(&cifs_tcp_ses_lock);
 	if ((tcon->tc_count > 1) || (tcon->tidStatus == CifsExiting)) {
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index ca9dd9d..2e3c489 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -401,12 +401,6 @@ CIFS_SB(struct super_block *sb)
 	return sb->s_fs_info;
 }
 
-static inline struct cifsTconInfo *
-cifs_sb_tcon(struct cifs_sb_info *cifs_sb)
-{
-	return cifs_sb->tcon;
-}
-
 static inline char CIFS_DIR_SEP(const struct cifs_sb_info *cifs_sb)
 {
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index ca341fc..301566e 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -92,7 +92,8 @@ extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time,
 
 extern struct cifsFileInfo *cifs_new_fileinfo(struct inode *newinode,
 				__u16 fileHandle, struct file *file,
-				struct vfsmount *mnt, unsigned int oflags);
+				struct vfsmount *mnt, struct cifsTconInfo *tcon,
+				unsigned int oflags);
 extern int cifs_posix_open(char *full_path, struct inode **pinode,
 			   struct vfsmount *mnt, int mode, int oflags,
 			   __u32 *poplock, __u16 *pnetfid, int xid);
@@ -117,6 +118,8 @@ extern void cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb,
 			      const char *path, const __u16 *pfid);
 extern int mode_to_acl(struct inode *inode, const char *path, __u64);
 
+extern struct cifsTconInfo *cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb);
+extern struct cifsTconInfo *cifs_sb_tcon(struct cifs_sb_info *cifs_sb);
 extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
 			const char *);
 extern int cifs_umount(struct super_block *, struct cifs_sb_info *);
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 05ee024..90184cd 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -53,18 +53,19 @@ build_path_from_dentry(struct dentry *direntry)
 	int dfsplen;
 	char *full_path;
 	char dirsep;
-	struct cifs_sb_info *cifs_sb;
+	struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
+	struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb);
 
+	/* FIXME: this is racy -- need to take proper references */
 	if (direntry == NULL)
 		return NULL;  /* not much we can do if dentry is freed and
 		we need to reopen the file after it was closed implicitly
 		when the server crashed */
 
-	cifs_sb = CIFS_SB(direntry->d_sb);
 	dirsep = CIFS_DIR_SEP(cifs_sb);
 	pplen = cifs_sb->prepathlen;
-	if (cifs_sb_tcon(cifs_sb) && (cifs_sb_tcon(cifs_sb)->Flags & SMB_SHARE_IS_IN_DFS))
-		dfsplen = strnlen(cifs_sb_tcon(cifs_sb)->treeName, MAX_TREE_SIZE + 1);
+	if (tcon && (tcon->Flags & SMB_SHARE_IS_IN_DFS))
+		dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1);
 	else
 		dfsplen = 0;
 cifs_bp_rename_retry:
@@ -117,7 +118,7 @@ cifs_bp_rename_retry:
 	/* BB test paths to Windows with '/' in the midst of prepath */
 
 	if (dfsplen) {
-		strncpy(full_path, cifs_sb_tcon(cifs_sb)->treeName, dfsplen);
+		strncpy(full_path, tcon->treeName, dfsplen);
 		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
 			int i;
 			for (i = 0; i < dfsplen; i++) {
@@ -126,7 +127,7 @@ cifs_bp_rename_retry:
 			}
 		}
 	}
-	strncpy(full_path + dfsplen, CIFS_SB(direntry->d_sb)->prepath, pplen);
+	strncpy(full_path + dfsplen, cifs_sb->prepath, pplen);
 	return full_path;
 }
 
@@ -138,7 +139,6 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, struct file *file,
 	int oplock = 0;
 	struct cifsFileInfo *pCifsFile;
 	struct cifsInodeInfo *pCifsInode;
-	struct cifs_sb_info *cifs_sb = CIFS_SB(mnt->mnt_sb);
 
 	pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
 	if (pCifsFile == NULL)
@@ -163,7 +163,7 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, struct file *file,
 	slow_work_init(&pCifsFile->oplock_break, &cifs_oplock_break_ops);
 
 	write_lock(&GlobalSMBSeslock);
-	list_add(&pCifsFile->tlist, &cifs_sb_tcon(cifs_sb)->openFileList);
+	list_add(&pCifsFile->tlist, &tcon->openFileList);
 	pCifsInode = CIFS_I(newinode);
 	if (pCifsInode) {
 		/* if readable file instance put first in list*/
@@ -193,14 +193,17 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
 	FILE_UNIX_BASIC_INFO *presp_data;
 	__u32 posix_flags = 0;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(mnt->mnt_sb);
-	struct cifs_fattr fattr;
 	struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb);
+	struct cifs_fattr fattr;
 
 	if (IS_ERR(tcon))
 		return PTR_ERR(tcon);
 
 	cFYI(1, ("posix open %s", full_path));
 
+	if (IS_ERR(tcon))
+		return PTR_ERR(tcon);
+
 	presp_data = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
 	if (presp_data == NULL)
 		return -ENOMEM;
@@ -297,17 +300,17 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
 	 */
 	int desiredAccess = GENERIC_READ | GENERIC_WRITE;
 	__u16 fileHandle;
-	struct cifs_sb_info *cifs_sb;
-	struct cifsTconInfo *tcon;
+	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+	struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb);
 	char *full_path = NULL;
 	FILE_ALL_INFO *buf = NULL;
 	struct inode *newinode = NULL;
 	int disposition = FILE_OVERWRITE_IF;
 
-	xid = GetXid();
+	if (IS_ERR(tcon))
+		return PTR_ERR(tcon);
 
-	cifs_sb = CIFS_SB(inode->i_sb);
-	tcon = cifs_sb_tcon(cifs_sb);
+	xid = GetXid();
 
 	if (IS_ERR(tcon)) {
 		FreeXid(xid);
@@ -390,7 +393,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
 	if (!tcon->unix_ext && (mode & S_IWUGO) == 0)
 		create_options |= CREATE_OPTION_READONLY;
 
-	if (cifs_sb_tcon(cifs_sb)->ses->capabilities & CAP_NT_SMBS)
+	if (tcon->ses->capabilities & CAP_NT_SMBS)
 		rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
 			 desiredAccess, create_options,
 			 &fileHandle, &oplock, buf, cifs_sb->local_nls,
@@ -491,18 +494,18 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
 {
 	int rc = -EPERM;
 	int xid;
-	struct cifs_sb_info *cifs_sb;
-	struct cifsTconInfo *pTcon;
+	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+	struct cifsTconInfo *pTcon = cifs_sb_tcon(cifs_sb);
 	char *full_path = NULL;
 	struct inode *newinode = NULL;
 
 	if (!old_valid_dev(device_number))
 		return -EINVAL;
 
-	xid = GetXid();
+	if (IS_ERR(pTcon))
+		return PTR_ERR(pTcon);
 
-	cifs_sb = CIFS_SB(inode->i_sb);
-	pTcon = cifs_sb_tcon(cifs_sb);
+	xid = GetXid();
 
 	full_path = build_path_from_dentry(direntry);
 	if (full_path == NULL)
@@ -635,6 +638,10 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
 
 	cifs_sb = CIFS_SB(parent_dir_inode->i_sb);
 	pTcon = cifs_sb_tcon(cifs_sb);
+	if (IS_ERR(pTcon)) {
+		FreeXid(xid);
+		return (struct dentry *) pTcon;
+	}
 
 	/*
 	 * Don't allow the separator character in a path component.
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 26665b8..b56913a 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -265,9 +265,9 @@ int cifs_open(struct inode *inode, struct file *file)
 	__u16 netfid;
 	FILE_ALL_INFO *buf = NULL;
 
-	xid = GetXid();
-
 	cifs_sb = CIFS_SB(inode->i_sb);
+
+	xid = GetXid();
 	tcon = cifs_sb_tcon(cifs_sb);
 	if (IS_ERR(tcon)) {
 		FreeXid(xid);
@@ -374,7 +374,7 @@ int cifs_open(struct inode *inode, struct file *file)
 		goto out;
 	}
 
-	if (cifs_sb_tcon(cifs_sb)->ses->capabilities & CAP_NT_SMBS)
+	if (tcon->ses->capabilities & CAP_NT_SMBS)
 		rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
 			 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
 			 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
@@ -1399,6 +1399,7 @@ static int cifs_writepages(struct address_space *mapping,
 	int xid, long_op;
 
 	cifs_sb = CIFS_SB(mapping->host->i_sb);
+	tcon = cifs_sb_master_tcon(cifs_sb);
 
 	/*
 	 * If wsize is smaller that the page cache size, default to writing
@@ -1407,7 +1408,10 @@ static int cifs_writepages(struct address_space *mapping,
 	if (cifs_sb->wsize < PAGE_CACHE_SIZE)
 		return generic_writepages(mapping, wbc);
 
-	if (cifs_sb_tcon(cifs_sb)->ses->sign && !experimEnabled)
+	/* FIXME: not quite right -- we need to determine this once we know
+	 * what tcon we're going to use.
+	 */
+	if (tcon->ses->sign && !experimEnabled)
 		return generic_writepages(mapping, wbc);
 
 	iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL);
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index e21feaa..100ad85 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -51,7 +51,7 @@ static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral)
 
 
 		/* check if server can support readpages */
-		if (cifs_sb_tcon(cifs_sb)->ses->server->maxBuf <
+		if (cifs_sb_master_tcon(cifs_sb)->ses->server->maxBuf <
 				PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
 			inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
 		else
@@ -301,12 +301,14 @@ int cifs_get_inode_info_unix(struct inode **pinode,
 	int rc;
 	FILE_UNIX_BASIC_INFO find_data;
 	struct cifs_fattr fattr;
-	struct cifsTconInfo *tcon;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+	struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb);
 
-	tcon = cifs_sb_tcon(cifs_sb);
 	cFYI(1, ("Getting info on %s", full_path));
 
+	if (IS_ERR(tcon))
+		return PTR_ERR(tcon);
+
 	/* could have done a find first instead but this returns more info */
 	rc = CIFSSMBUnixQPathInfo(xid, tcon, full_path, &find_data,
 				  cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
@@ -341,11 +343,14 @@ cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path,
 	int rc;
 	int oplock = 0;
 	__u16 netfid;
-	struct cifsTconInfo *pTcon = cifs_sb_tcon(cifs_sb);
+	struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb);
 	char buf[24];
 	unsigned int bytes_read;
 	char *pbuf;
 
+	if (IS_ERR(tcon))
+		return PTR_ERR(tcon);
+
 	pbuf = buf;
 
 	fattr->cf_mode &= ~S_IFMT;
@@ -360,7 +365,7 @@ cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path,
 		return -EINVAL;	 /* EOPNOTSUPP? */
 	}
 
-	rc = CIFSSMBOpen(xid, pTcon, path, FILE_OPEN, GENERIC_READ,
+	rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, GENERIC_READ,
 			 CREATE_NOT_DIR, &netfid, &oplock, NULL,
 			 cifs_sb->local_nls,
 			 cifs_sb->mnt_cifs_flags &
@@ -368,7 +373,7 @@ cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path,
 	if (rc == 0) {
 		int buf_type = CIFS_NO_BUFFER;
 			/* Read header */
-		rc = CIFSSMBRead(xid, pTcon, netfid,
+		rc = CIFSSMBRead(xid, tcon, netfid,
 				 24 /* length */, 0 /* offset */,
 				 &bytes_read, &pbuf, &buf_type);
 		if ((rc == 0) && (bytes_read >= 8)) {
@@ -410,7 +415,7 @@ cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path,
 			fattr->cf_dtype = DT_REG;
 			rc = -EOPNOTSUPP; /* or some unknown SFU type */
 		}
-		CIFSSMBClose(xid, pTcon, netfid);
+		CIFSSMBClose(xid, tcon, netfid);
 	}
 	return rc;
 }
@@ -429,8 +434,12 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path,
 	ssize_t rc;
 	char ea_value[4];
 	__u32 mode;
+	struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb);
+
+	if (IS_ERR(tcon))
+		return PTR_ERR(tcon);
 
-	rc = CIFSSMBQAllEAs(xid, cifs_sb_tcon(cifs_sb), path, "SETFILEBITS",
+	rc = CIFSSMBQAllEAs(xid, tcon, path, "SETFILEBITS",
 			    ea_value, 4 /* size of buf */, cifs_sb->local_nls,
 			    cifs_sb->mnt_cifs_flags &
 				CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -456,6 +465,8 @@ static void
 cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
 		       struct cifs_sb_info *cifs_sb, bool adjust_tz)
 {
+	struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb);
+
 	memset(fattr, 0, sizeof(*fattr));
 	fattr->cf_cifsattrs = le32_to_cpu(info->Attributes);
 	if (info->DeletePending)
@@ -470,8 +481,8 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
 	fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);
 
 	if (adjust_tz) {
-		fattr->cf_ctime.tv_sec += cifs_sb_tcon(cifs_sb)->ses->server->timeAdj;
-		fattr->cf_mtime.tv_sec += cifs_sb_tcon(cifs_sb)->ses->server->timeAdj;
+		fattr->cf_ctime.tv_sec += tcon->ses->server->timeAdj;
+		fattr->cf_mtime.tv_sec += tcon->ses->server->timeAdj;
 	}
 
 	fattr->cf_eof = le64_to_cpu(info->EndOfFile);
@@ -541,15 +552,17 @@ int cifs_get_inode_info(struct inode **pinode,
 	struct super_block *sb, int xid, const __u16 *pfid)
 {
 	int rc = 0, tmprc;
-	struct cifsTconInfo *pTcon;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+	struct cifsTconInfo *pTcon = cifs_sb_tcon(cifs_sb);
 	char *buf = NULL;
 	bool adjustTZ = false;
 	struct cifs_fattr fattr;
 
-	pTcon = cifs_sb_tcon(cifs_sb);
 	cFYI(1, ("Getting info on %s", full_path));
 
+	if (IS_ERR(pTcon))
+		return PTR_ERR(pTcon);
+
 	if ((pfindData == NULL) && (*pinode != NULL)) {
 		if (CIFS_I(*pinode)->clientCanCacheRead) {
 			cFYI(1, ("No need to revalidate cached inode sizes"));
@@ -671,6 +684,7 @@ char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb)
 	int pplen = cifs_sb->prepathlen;
 	int dfsplen;
 	char *full_path = NULL;
+	struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb);
 
 	/* if no prefix path, simply set path to the root of share to "" */
 	if (pplen == 0) {
@@ -680,8 +694,8 @@ char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb)
 		return full_path;
 	}
 
-	if (cifs_sb_tcon(cifs_sb) && (cifs_sb_tcon(cifs_sb)->Flags & SMB_SHARE_IS_IN_DFS))
-		dfsplen = strnlen(cifs_sb_tcon(cifs_sb)->treeName, MAX_TREE_SIZE + 1);
+	if (tcon->Flags & SMB_SHARE_IS_IN_DFS)
+		dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1);
 	else
 		dfsplen = 0;
 
@@ -690,7 +704,7 @@ char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb)
 		return full_path;
 
 	if (dfsplen) {
-		strncpy(full_path, cifs_sb_tcon(cifs_sb)->treeName, dfsplen);
+		strncpy(full_path, tcon->treeName, dfsplen);
 		/* switch slash direction in prepath depending on whether
 		 * windows or posix style path names
 		 */
@@ -759,18 +773,21 @@ cifs_iget(struct super_block *sb, struct cifs_fattr *fattr)
 struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino)
 {
 	int xid;
-	struct cifs_sb_info *cifs_sb;
+	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+	struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb);
 	struct inode *inode = NULL;
 	long rc;
 	char *full_path;
 
-	cifs_sb = CIFS_SB(sb);
+	if (IS_ERR(tcon))
+		return (struct inode *) tcon;
+
 	full_path = cifs_build_path_to_root(cifs_sb);
 	if (full_path == NULL)
 		return ERR_PTR(-ENOMEM);
 
 	xid = GetXid();
-	if (cifs_sb_tcon(cifs_sb)->unix_ext)
+	if (tcon->unix_ext)
 		rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);
 	else
 		rc = cifs_get_inode_info(&inode, full_path, NULL, sb,
@@ -779,7 +796,7 @@ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino)
 	if (!inode)
 		return ERR_PTR(-ENOMEM);
 
-	if (rc && cifs_sb_tcon(cifs_sb)->ipc) {
+	if (rc && tcon->ipc) {
 		cFYI(1, ("ipc connection - fake read inode"));
 		inode->i_mode |= S_IFDIR;
 		inode->i_nlink = 2;
@@ -862,7 +879,11 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid,
 		goto set_via_filehandle;
 	}
 
-	pTcon = open_file->tcon;
+	pTcon = cifs_sb_tcon(cifs_sb);
+	if (IS_ERR(pTcon)) {
+		rc = PTR_ERR(pTcon);
+		goto out;
+	}
 
 	/*
 	 * NT4 apparently returns success on this call, but it doesn't
@@ -928,6 +949,11 @@ cifs_rename_pending_delete(char *full_path, struct dentry *dentry, int xid)
 	__u32 dosattr, origattr;
 	FILE_BASIC_INFO *info_buf = NULL;
 
+	if (IS_ERR(tcon)) {
+		rc = PTR_ERR(tcon);
+		goto out;
+	}
+
 	rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN,
 			 DELETE|FILE_WRITE_ATTRIBUTES, CREATE_NOT_DIR,
 			 &netfid, &oplock, NULL, cifs_sb->local_nls,
@@ -1042,6 +1068,11 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
 	cFYI(1, ("cifs_unlink, dir=0x%p, dentry=0x%p", dir, dentry));
 
 	xid = GetXid();
+	if (IS_ERR(tcon)) {
+		rc = PTR_ERR(tcon);
+		FreeXid(xid);
+		return rc;
+	}
 
 	/* Unlink can be called from rename so we can not take the
 	 * sb->s_vfs_rename_mutex here */
@@ -1138,6 +1169,11 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
 
 	cifs_sb = CIFS_SB(inode->i_sb);
 	pTcon = cifs_sb_tcon(cifs_sb);
+	if (IS_ERR(pTcon)) {
+		rc = PTR_ERR(pTcon);
+		FreeXid(xid);
+		return rc;
+	}
 
 	full_path = build_path_from_dentry(direntry);
 	if (full_path == NULL) {
@@ -1318,6 +1354,11 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
 
 	cifs_sb = CIFS_SB(inode->i_sb);
 	pTcon = cifs_sb_tcon(cifs_sb);
+	if (IS_ERR(pTcon)) {
+		rc = PTR_ERR(pTcon);
+		FreeXid(xid);
+		return rc;
+	}
 
 	full_path = build_path_from_dentry(direntry);
 	if (full_path == NULL) {
@@ -1362,6 +1403,9 @@ cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath,
 	__u16 srcfid;
 	int oplock, rc;
 
+	if (IS_ERR(pTcon))
+		return PTR_ERR(pTcon);
+
 	/* try path-based rename first */
 	rc = CIFSSMBRename(xid, pTcon, fromPath, toPath, cifs_sb->local_nls,
 			   cifs_sb->mnt_cifs_flags &
@@ -1400,14 +1444,21 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
 	char *toName = NULL;
 	struct cifs_sb_info *cifs_sb_source;
 	struct cifs_sb_info *cifs_sb_target;
-	struct cifsTconInfo *tcon;
+	struct cifsTconInfo *source_tcon, *target_tcon;
 	FILE_UNIX_BASIC_INFO *info_buf_source = NULL;
 	FILE_UNIX_BASIC_INFO *info_buf_target;
 	int xid, rc, tmprc;
 
 	cifs_sb_target = CIFS_SB(target_dir->i_sb);
 	cifs_sb_source = CIFS_SB(source_dir->i_sb);
-	tcon = cifs_sb_tcon(cifs_sb_source);
+	source_tcon = cifs_sb_tcon(cifs_sb_source);
+	target_tcon = cifs_sb_tcon(cifs_sb_target);
+
+	if (IS_ERR(source_tcon))
+		return PTR_ERR(source_tcon);
+
+	if (IS_ERR(target_tcon))
+		return PTR_ERR(target_tcon);
 
 	xid = GetXid();
 
@@ -1415,7 +1466,7 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
 	 * BB: this might be allowed if same server, but different share.
 	 * Consider adding support for this
 	 */
-	if (tcon != cifs_sb_tcon(cifs_sb_target)) {
+	if (source_tcon != target_tcon) {
 		rc = -EXDEV;
 		goto cifs_rename_exit;
 	}
@@ -1439,7 +1490,7 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
 	rc = cifs_do_rename(xid, source_dentry, fromName,
 			    target_dentry, toName);
 
-	if (rc == -EEXIST && tcon->unix_ext) {
+	if (rc == -EEXIST && source_tcon->unix_ext) {
 		/*
 		 * Are src and dst hardlinks of same inode? We can
 		 * only tell with unix extensions enabled
@@ -1453,7 +1504,7 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
 		}
 
 		info_buf_target = info_buf_source + 1;
-		tmprc = CIFSSMBUnixQPathInfo(xid, tcon, fromName,
+		tmprc = CIFSSMBUnixQPathInfo(xid, source_tcon, fromName,
 					info_buf_source,
 					cifs_sb_source->local_nls,
 					cifs_sb_source->mnt_cifs_flags &
@@ -1461,7 +1512,7 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
 		if (tmprc != 0)
 			goto unlink_target;
 
-		tmprc = CIFSSMBUnixQPathInfo(xid, tcon,
+		tmprc = CIFSSMBUnixQPathInfo(xid, source_tcon,
 					toName, info_buf_target,
 					cifs_sb_target->local_nls,
 					/* remap based on source sb */
@@ -1564,12 +1615,19 @@ int cifs_revalidate_dentry(struct dentry *dentry)
 	char *full_path = NULL;
 	struct inode *inode = dentry->d_inode;
 	struct super_block *sb = dentry->d_sb;
+	struct cifsTconInfo *tcon;
 
 	if (inode == NULL)
 		return -ENOENT;
 
 	xid = GetXid();
 
+	tcon = cifs_sb_tcon(CIFS_SB(sb));
+	if (IS_ERR(tcon)) {
+		rc = PTR_ERR(tcon);
+		goto check_inval;
+	}
+
 	if (!cifs_inode_needs_reval(inode))
 		goto check_inval;
 
@@ -1692,6 +1750,9 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
 		if (pTcon == NULL)
 			pTcon = cifs_sb_tcon(cifs_sb);
 
+		if (IS_ERR(pTcon))
+			return PTR_ERR(pTcon);
+
 		/* Set file size by pathname rather than by handle
 		   either because no valid, writeable file handle for
 		   it was found or because there was an error setting
@@ -1839,6 +1900,10 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
 		cifsFileInfo_put(open_file);
 	} else {
 		pTcon = cifs_sb_tcon(cifs_sb);
+		if (IS_ERR(pTcon)) {
+			rc = PTR_ERR(pTcon);
+			goto out;
+		}
 		rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args,
 				    cifs_sb->local_nls,
 				    cifs_sb->mnt_cifs_flags &
@@ -2011,6 +2076,9 @@ cifs_setattr(struct dentry *direntry, struct iattr *attrs)
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 	struct cifsTconInfo *pTcon = cifs_sb_tcon(cifs_sb);
 
+	if (IS_ERR(pTcon))
+		return PTR_ERR(pTcon);
+
 	if (pTcon->unix_ext)
 		return cifs_setattr_unix(direntry, attrs);
 
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index deff001..72be30c 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -45,6 +45,8 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
 
 	cifs_sb_target = CIFS_SB(inode->i_sb);
 	pTcon = cifs_sb_tcon(cifs_sb_target);
+	if (IS_ERR(pTcon))
+		return PTR_ERR(pTcon);
 
 /* No need to check for cross device links since server will do that
    BB note DFS case in future though (when we may have to check) */
@@ -117,6 +119,11 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
 
 	xid = GetXid();
 
+	if (IS_ERR(tcon)) {
+		rc = PTR_ERR(tcon);
+		goto out;
+	}
+
 	/*
 	 * For now, we just handle symlinks with unix extensions enabled.
 	 * Eventually we should handle NTFS reparse points, and MacOS
@@ -169,9 +176,13 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
 
 	cifs_sb = CIFS_SB(inode->i_sb);
 	pTcon = cifs_sb_tcon(cifs_sb);
+	if (IS_ERR(pTcon)) {
+		rc = PTR_ERR(pTcon);
+		FreeXid(xid);
+		return rc;
+	}
 
 	full_path = build_path_from_dentry(direntry);
-
 	if (full_path == NULL) {
 		rc = -ENOMEM;
 		FreeXid(xid);
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 789cf12..28cfccd 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -724,6 +724,6 @@ cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb)
 			   "properly. Hardlinks will not be recognized on this "
 			   "mount. Consider mounting with the \"noserverino\" "
 			   "option to silence this message.",
-			   cifs_sb_tcon(cifs_sb)->treeName));
+			   cifs_sb_master_tcon(cifs_sb)->treeName));
 	}
 }
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 17effab..10b987b 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -102,7 +102,7 @@ cifs_readdir_lookup(struct dentry *parent, struct qstr *name,
 		return NULL;
 	}
 
-	if (cifs_sb_tcon(CIFS_SB(sb))->nocase)
+	if (cifs_sb_master_tcon(CIFS_SB(sb))->nocase)
 		dentry->d_op = &cifs_ci_dentry_ops;
 	else
 		dentry->d_op = &cifs_dentry_ops;
@@ -171,7 +171,7 @@ static void
 cifs_std_info_to_fattr(struct cifs_fattr *fattr, FIND_FILE_STANDARD_INFO *info,
 		       struct cifs_sb_info *cifs_sb)
 {
-	int offset = cifs_sb_tcon(cifs_sb)->ses->server->timeAdj;
+	int offset = cifs_sb_master_tcon(cifs_sb)->ses->server->timeAdj;
 
 	memset(fattr, 0, sizeof(*fattr));
 	fattr->cf_atime = cnvrtDosUnixTm(info->LastAccessDate,
@@ -232,6 +232,10 @@ static int initiate_cifs_search(const int xid, struct file *file)
 	if (cifs_sb == NULL)
 		return -EINVAL;
 
+	pTcon = cifs_sb_tcon(cifs_sb);
+	if (IS_ERR(pTcon))
+		return PTR_ERR(pTcon);
+
 	if (file->private_data == NULL)
 		file->private_data =
 			kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
@@ -241,11 +245,9 @@ static int initiate_cifs_search(const int xid, struct file *file)
 	cifsFile = file->private_data;
 	cifsFile->invalidHandle = true;
 	cifsFile->srch_inf.endOfSearch = false;
-	cifsFile->tcon = cifs_sb_tcon(cifs_sb);
+	cifsFile->tcon = pTcon;
 
 	pTcon = cifsFile->tcon;
-	if (pTcon == NULL)
-		return -EINVAL;
 
 	full_path = build_path_from_dentry(file->f_path.dentry);
 
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c
index 2161019..77ee3b6 100644
--- a/fs/cifs/xattr.c
+++ b/fs/cifs/xattr.c
@@ -62,6 +62,11 @@ int cifs_removexattr(struct dentry *direntry, const char *ea_name)
 
 	cifs_sb = CIFS_SB(sb);
 	pTcon = cifs_sb_tcon(cifs_sb);
+	if (IS_ERR(pTcon)) {
+		rc = PTR_ERR(pTcon);
+		FreeXid(xid);
+		return rc;
+	}
 
 	full_path = build_path_from_dentry(direntry);
 	if (full_path == NULL) {
@@ -117,6 +122,11 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
 
 	cifs_sb = CIFS_SB(sb);
 	pTcon = cifs_sb_tcon(cifs_sb);
+	if (IS_ERR(pTcon)) {
+		rc = PTR_ERR(pTcon);
+		FreeXid(xid);
+		return rc;
+	}
 
 	full_path = build_path_from_dentry(direntry);
 	if (full_path == NULL) {
@@ -225,6 +235,11 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
 
 	cifs_sb = CIFS_SB(sb);
 	pTcon = cifs_sb_tcon(cifs_sb);
+	if (IS_ERR(pTcon)) {
+		rc = PTR_ERR(pTcon);
+		FreeXid(xid);
+		return rc;
+	}
 
 	full_path = build_path_from_dentry(direntry);
 	if (full_path == NULL) {
@@ -346,13 +361,19 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
 		return -EIO;
 
 	cifs_sb = CIFS_SB(sb);
-	pTcon = cifs_sb_tcon(cifs_sb);
 
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
 		return -EOPNOTSUPP;
 
 	xid = GetXid();
 
+	pTcon = cifs_sb_tcon(cifs_sb);
+	if (IS_ERR(pTcon)) {
+		rc = PTR_ERR(pTcon);
+		FreeXid(xid);
+		return rc;
+	}
+
 	full_path = build_path_from_dentry(direntry);
 	if (full_path == NULL) {
 		rc = -ENOMEM;
-- 
1.6.6.1

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

* [PATCH 08/11] cifs: fix handling of signing with writepages
  2010-04-20 20:07 [PATCH 00/11] cifs: implement multisession mounts (try #2) Jeff Layton
                   ` (6 preceding siblings ...)
  2010-04-20 20:07 ` [PATCH 07/11] cifs: allow for cifs_sb_tcon() to return an error Jeff Layton
@ 2010-04-20 20:07 ` Jeff Layton
  2010-04-20 20:07 ` [PATCH 09/11] cifs: add routines to build sessions and tcons on the fly Jeff Layton
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 24+ messages in thread
From: Jeff Layton @ 2010-04-20 20:07 UTC (permalink / raw)
  To: linux-cifs-client, linux-fsdevel; +Cc: smfrench

Get a reference to the file early so we can base the decision about signing
on the correct tcon. If that doesn't work for some reason, then fall back
to generic_writepages. That's just as likely to fail, but it simplifies the
error handling.

In truth, I'm not sure how that could occur anyway, so maybe a NULL
open_file here ought to be a BUG()?

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/cifs/file.c |   85 ++++++++++++++++++++++++++-----------------------------
 1 files changed, 40 insertions(+), 45 deletions(-)

diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index b56913a..12495c7 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1398,8 +1398,16 @@ static int cifs_writepages(struct address_space *mapping,
 	int scanned = 0;
 	int xid, long_op;
 
+	/*
+	 * BB: Is this meaningful for a non-block-device file system?
+	 * If it is, we should test it again after we do I/O
+	 */
+	if (wbc->nonblocking && bdi_write_congested(bdi)) {
+		wbc->encountered_congestion = 1;
+		return 0;
+	}
+
 	cifs_sb = CIFS_SB(mapping->host->i_sb);
-	tcon = cifs_sb_master_tcon(cifs_sb);
 
 	/*
 	 * If wsize is smaller that the page cache size, default to writing
@@ -1408,25 +1416,26 @@ static int cifs_writepages(struct address_space *mapping,
 	if (cifs_sb->wsize < PAGE_CACHE_SIZE)
 		return generic_writepages(mapping, wbc);
 
-	/* FIXME: not quite right -- we need to determine this once we know
-	 * what tcon we're going to use.
-	 */
-	if (tcon->ses->sign && !experimEnabled)
-		return generic_writepages(mapping, wbc);
-
 	iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL);
 	if (iov == NULL)
 		return generic_writepages(mapping, wbc);
 
-
 	/*
-	 * BB: Is this meaningful for a non-block-device file system?
-	 * If it is, we should test it again after we do I/O
+	 * if there's no open file, then this is likely to fail too,
+	 * but it'll at least handle the return. Maybe it should be
+	 * a BUG() instead?
 	 */
-	if (wbc->nonblocking && bdi_write_congested(bdi)) {
-		wbc->encountered_congestion = 1;
+	open_file = find_writable_file(CIFS_I(mapping->host), false);
+	if (!open_file) {
 		kfree(iov);
-		return 0;
+		return generic_writepages(mapping, wbc);
+	}
+
+	tcon = open_file->tcon;
+	if (tcon->ses->sign && !experimEnabled) {
+		kfree(iov);
+		cifsFileInfo_put(open_file);
+		return generic_writepages(mapping, wbc);
 	}
 
 	xid = GetXid();
@@ -1532,39 +1541,24 @@ retry:
 				break;
 		}
 		if (n_iov) {
-			/* Search for a writable handle every time we call
-			 * CIFSSMBWrite2.  We can't rely on the last handle
-			 * we used to still be valid
-			 */
-			open_file = find_writable_file(CIFS_I(mapping->host),
-							false);
-			if (!open_file) {
-				cERROR(1, ("No writable handles for inode"));
-				rc = -EBADF;
+			long_op = cifs_write_timeout(cifsi, offset);
+			rc = CIFSSMBWrite2(xid, tcon, open_file->netfid,
+					   bytes_to_write, offset,
+					   &bytes_written, iov, n_iov,
+					   long_op);
+			cifs_update_eof(cifsi, offset, bytes_written);
+
+			if (rc || bytes_written < bytes_to_write) {
+				cERROR(1, ("Write2 ret %d, wrote %d",
+					  rc, bytes_written));
+				/* BB what if continued retry is
+				   requested via mount flags? */
+				if (rc == -ENOSPC)
+					set_bit(AS_ENOSPC, &mapping->flags);
+				else
+					set_bit(AS_EIO, &mapping->flags);
 			} else {
-				tcon = open_file->tcon;
-				long_op = cifs_write_timeout(cifsi, offset);
-				rc = CIFSSMBWrite2(xid, tcon,
-						   open_file->netfid,
-						   bytes_to_write, offset,
-						   &bytes_written, iov, n_iov,
-						   long_op);
-				cifsFileInfo_put(open_file);
-				cifs_update_eof(cifsi, offset, bytes_written);
-
-				if (rc || bytes_written < bytes_to_write) {
-					cERROR(1, ("Write2 ret %d, wrote %d",
-						  rc, bytes_written));
-					/* BB what if continued retry is
-					   requested via mount flags? */
-					if (rc == -ENOSPC)
-						set_bit(AS_ENOSPC, &mapping->flags);
-					else
-						set_bit(AS_EIO, &mapping->flags);
-				} else {
-					cifs_stats_bytes_written(tcon,
-								 bytes_written);
-				}
+				cifs_stats_bytes_written(tcon, bytes_written);
 			}
 			for (i = 0; i < n_iov; i++) {
 				page = pvec.pages[first + i];
@@ -1601,6 +1595,7 @@ retry:
 	if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
 		mapping->writeback_index = index;
 
+	cifsFileInfo_put(open_file);
 	FreeXid(xid);
 	kfree(iov);
 	return rc;
-- 
1.6.6.1

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

* [PATCH 09/11] cifs: add routines to build sessions and tcons on the fly
  2010-04-20 20:07 [PATCH 00/11] cifs: implement multisession mounts (try #2) Jeff Layton
                   ` (7 preceding siblings ...)
  2010-04-20 20:07 ` [PATCH 08/11] cifs: fix handling of signing with writepages Jeff Layton
@ 2010-04-20 20:07 ` Jeff Layton
  2010-04-20 20:07 ` [PATCH 10/11] cifs: on multises mount, set ownership to current_fsuid/current_fsgid Jeff Layton
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 24+ messages in thread
From: Jeff Layton @ 2010-04-20 20:07 UTC (permalink / raw)
  To: linux-cifs-client, linux-fsdevel; +Cc: smfrench

This patch is rather large, but it's a bit difficult to do piecemeal...

Turn the tcon pointer in the cifs_sb into a radix tree that uses the
fsuid of the process as a key. The value is a new "tcon_link" struct
that contains info about a tcon that's under construction.

When a new process needs a tcon, it'll call cifs_sb_tcon. That will
then look up the tcon_link in the radix tree. If it exists and is
valid, it's returned.

If it doesn't exist, then we stuff a new tcon_link into the tree and
mark it as pending and then go and try to build the session/tcon.
If that works, the tcon pointer in the tcon_link is updated and the
pending flag is cleared.

If the construction fails, then we set the tcon pointer to an ERR_PTR
and clear the pending flag.

If the radix tree is searched and the tcon_link is marked pending
then we go to sleep and wait for the pending flag to be cleared.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/cifs/cifs_fs_sb.h |    7 +-
 fs/cifs/connect.c    |  202 ++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 200 insertions(+), 9 deletions(-)

diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
index e658723..14c3b69 100644
--- a/fs/cifs/cifs_fs_sb.h
+++ b/fs/cifs/cifs_fs_sb.h
@@ -15,6 +15,8 @@
  *   the GNU Lesser General Public License for more details.
  *
  */
+#include <linux/radix-tree.h>
+
 #ifndef _CIFS_FS_SB_H
 #define _CIFS_FS_SB_H
 
@@ -36,8 +38,9 @@
 #define CIFS_MOUNT_MULTISES	0x8000 /* multisession mount */
 
 struct cifs_sb_info {
-	struct cifsTconInfo *tcon;	/* primary mount */
-	struct list_head nested_tcon_q;
+	struct radix_tree_root tcon_tree;
+#define CIFS_TCON_MASTER_TAG		0	/* tcon is "master" (mount) tcon */
+	spinlock_t tcon_tree_lock;
 	struct nls_table *local_nls;
 	unsigned int rsize;
 	unsigned int wsize;
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 09a1216..bc408ad 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -106,6 +106,15 @@ struct smb_vol {
 	struct nls_table *local_nls;
 };
 
+#define TLINK_ERROR_EXPIRE	(1 * HZ)
+
+#define TCON_LINK_PENDING	1
+struct tcon_link {
+	unsigned long flags;
+	unsigned long time;
+	struct cifsTconInfo *tcon;
+};
+
 static int ipv4_connect(struct TCP_Server_Info *server);
 static int ipv6_connect(struct TCP_Server_Info *server);
 
@@ -2660,6 +2669,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 	struct TCP_Server_Info *srvTcp;
 	char   *full_path;
 	char *mount_data = mount_data_global;
+	struct tcon_link *tlink;
 #ifdef CONFIG_CIFS_DFS_UPCALL
 	struct dfs_info3_param *referrals = NULL;
 	unsigned int num_referrals = 0;
@@ -2671,6 +2681,7 @@ try_mount_again:
 	pSesInfo = NULL;
 	srvTcp = NULL;
 	full_path = NULL;
+	tlink = NULL;
 
 	xid = GetXid();
 
@@ -2746,8 +2757,6 @@ try_mount_again:
 		goto remote_path_check;
 	}
 
-	cifs_sb->tcon = tcon;
-
 	/* do not care if following two calls succeed - informational */
 	if (!tcon->ipc) {
 		CIFSSMBQFSDeviceInfo(xid, tcon);
@@ -2856,6 +2865,29 @@ remote_path_check:
 #endif
 	}
 
+	/* now, hang the tcon off of the superblock */
+	tlink = kzalloc(sizeof *tlink, GFP_KERNEL);
+	if (tlink == NULL) {
+		rc = -ENOMEM;
+		goto mount_fail_check;
+	}
+
+	tlink->tcon = tcon;
+	tlink->time = jiffies;
+
+	rc = radix_tree_preload(GFP_KERNEL);
+	if (rc == -ENOMEM) {
+		kfree(tlink);
+		goto mount_fail_check;
+	}
+
+	spin_lock(&cifs_sb->tcon_tree_lock);
+	radix_tree_insert(&cifs_sb->tcon_tree, pSesInfo->linux_uid, tlink);
+	radix_tree_tag_set(&cifs_sb->tcon_tree, pSesInfo->linux_uid,
+			   CIFS_TCON_MASTER_TAG);
+	spin_unlock(&cifs_sb->tcon_tree_lock);
+	radix_tree_preload_end();
+
 mount_fail_check:
 	/* on error free sesinfo and tcon struct if needed */
 	if (rc) {
@@ -3041,19 +3073,35 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
 int
 cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
 {
-	int rc = 0;
+	int i, ret;
 	char *tmp;
+	struct tcon_link *tlink[8];
+	unsigned long index = 0;
+
+	while (1) {
+		spin_lock(&cifs_sb->tcon_tree_lock);
+		ret = radix_tree_gang_lookup(&cifs_sb->tcon_tree,
+					     (void **)tlink, index,
+					     ARRAY_SIZE(tlink));
+		for (i = 0; i < ret; i++) {
+			index = (unsigned long)tlink[i]->tcon->ses->linux_uid;
+			radix_tree_delete(&cifs_sb->tcon_tree, index);
+		}
+		spin_unlock(&cifs_sb->tcon_tree_lock);
 
-	if (cifs_sb_tcon(cifs_sb))
-		cifs_put_tcon(cifs_sb_tcon(cifs_sb));
+		for (i = 0; i < ret; i++)
+			cifs_put_tcon(tlink[i]->tcon);
+
+		if (!ret)
+			break;
+	}
 
-	cifs_sb->tcon = NULL;
 	tmp = cifs_sb->prepath;
 	cifs_sb->prepathlen = 0;
 	cifs_sb->prepath = NULL;
 	kfree(tmp);
 
-	return rc;
+	return 0;
 }
 
 int cifs_negotiate_protocol(unsigned int xid, struct cifsSesInfo *ses)
@@ -3114,3 +3162,143 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *ses,
 	return rc;
 }
 
+struct cifsTconInfo *
+cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid)
+{
+	struct cifsTconInfo *master_tcon = cifs_sb_master_tcon(cifs_sb);
+	struct cifsSesInfo *ses;
+	struct cifsTconInfo *tcon = NULL;
+	struct smb_vol *vol_info;
+
+	vol_info = kzalloc(sizeof(*vol_info), GFP_KERNEL);
+	if (vol_info == NULL) {
+		tcon = ERR_PTR(-ENOMEM);
+		goto out;
+	}
+
+	vol_info->username = kzalloc(MAX_USERNAME_SIZE + 1, GFP_KERNEL);
+	if (vol_info->username == NULL) {
+		tcon = ERR_PTR(-ENOMEM);
+		goto out;
+	}
+
+	snprintf(vol_info->username, MAX_USERNAME_SIZE, "krb50x%x", fsuid);
+	vol_info->local_nls = cifs_sb->local_nls;
+	vol_info->linux_uid = fsuid;
+	vol_info->cred_uid = fsuid;
+	vol_info->UNC = master_tcon->treeName;
+	vol_info->retry = master_tcon->retry;
+	vol_info->nocase = master_tcon->nocase;
+	vol_info->local_lease = master_tcon->local_lease;
+	vol_info->no_linux_ext = !master_tcon->unix_ext;
+	vol_info->sectype = master_tcon->ses->secType;
+
+	ses = cifs_get_smb_ses(master_tcon->ses->server, vol_info);
+	if (IS_ERR(ses)) {
+		tcon = (struct cifsTconInfo *) ses;
+		goto out;
+	}
+
+	tcon = cifs_get_tcon(ses, vol_info);
+	if (IS_ERR(tcon)) {
+		cifs_put_smb_ses(ses);
+		goto out;
+	}
+
+	if (ses->capabilities & CAP_UNIX)
+		reset_cifs_unix_caps(0, tcon, NULL, vol_info);
+out:
+	kfree(vol_info->username);
+	kfree(vol_info);
+
+	return tcon;
+}
+
+struct cifsTconInfo *
+cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb)
+{
+	struct tcon_link *tlink;
+	unsigned int ret;
+
+	spin_lock(&cifs_sb->tcon_tree_lock);
+	ret = radix_tree_gang_lookup_tag(&cifs_sb->tcon_tree, (void **) &tlink,
+					0, 1, CIFS_TCON_MASTER_TAG);
+	spin_unlock(&cifs_sb->tcon_tree_lock);
+
+	/* the master tcon should always be present */
+	if (ret == 0)
+		BUG();
+
+	return tlink->tcon;
+}
+
+static int
+cifs_sb_tcon_pending_wait(void *unused)
+{
+	schedule();
+	return signal_pending(current) ? -ERESTARTSYS : 0;
+}
+
+struct cifsTconInfo *
+cifs_sb_tcon(struct cifs_sb_info *cifs_sb)
+{
+	int ret;
+	unsigned long fsuid = (unsigned long) current_fsuid();
+	struct tcon_link *tlink, *newtlink;
+
+	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTISES))
+		return cifs_sb_master_tcon(cifs_sb);
+
+	spin_lock(&cifs_sb->tcon_tree_lock);
+	tlink = radix_tree_lookup(&cifs_sb->tcon_tree, fsuid);
+	spin_unlock(&cifs_sb->tcon_tree_lock);
+
+	if (tlink == NULL) {
+		newtlink = kzalloc(sizeof(*tlink), GFP_KERNEL);
+		if (newtlink == NULL)
+			return ERR_PTR(-ENOMEM);
+		newtlink->time = jiffies;
+		newtlink->tcon = ERR_PTR(-EACCES);
+		set_bit(TCON_LINK_PENDING, &newtlink->flags);
+
+		ret = radix_tree_preload(GFP_KERNEL);
+		if (ret != 0) {
+			kfree(newtlink);
+			return ERR_PTR(ret);
+		}
+
+		spin_lock(&cifs_sb->tcon_tree_lock);
+		tlink = radix_tree_lookup(&cifs_sb->tcon_tree, fsuid);
+		if (!tlink) {
+			tlink = newtlink;
+			newtlink = NULL;
+			ret = radix_tree_insert(&cifs_sb->tcon_tree, fsuid,
+						tlink);
+		}
+		spin_unlock(&cifs_sb->tcon_tree_lock);
+		radix_tree_preload_end();
+		kfree(newtlink);
+		if (ret)
+			return ERR_PTR(ret);
+	} else {
+		ret = wait_on_bit(&tlink->flags, TCON_LINK_PENDING,
+				  cifs_sb_tcon_pending_wait,
+				  TASK_INTERRUPTIBLE);
+		if (ret)
+			return ERR_PTR(ret);
+
+		spin_lock(&cifs_sb->tcon_tree_lock);
+		if (!IS_ERR(tlink->tcon) ||
+		    time_before(jiffies, tlink->time + TLINK_ERROR_EXPIRE)) {
+			spin_unlock(&cifs_sb->tcon_tree_lock);
+			return tlink->tcon;
+		}
+		set_bit(TCON_LINK_PENDING, &tlink->flags);
+		spin_unlock(&cifs_sb->tcon_tree_lock);
+	}
+
+	tlink->tcon = cifs_construct_tcon(cifs_sb, current_fsuid());
+	clear_bit(TCON_LINK_PENDING, &tlink->flags);
+	wake_up_bit(&tlink->flags, TCON_LINK_PENDING);
+	return tlink->tcon;
+}
-- 
1.6.6.1

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

* [PATCH 10/11] cifs: on multises mount, set ownership to current_fsuid/current_fsgid
  2010-04-20 20:07 [PATCH 00/11] cifs: implement multisession mounts (try #2) Jeff Layton
                   ` (8 preceding siblings ...)
  2010-04-20 20:07 ` [PATCH 09/11] cifs: add routines to build sessions and tcons on the fly Jeff Layton
@ 2010-04-20 20:07 ` Jeff Layton
  2010-04-20 20:07 ` [PATCH 11/11] cifs: add "multises" mount option Jeff Layton
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 24+ messages in thread
From: Jeff Layton @ 2010-04-20 20:07 UTC (permalink / raw)
  To: linux-cifs-client, linux-fsdevel; +Cc: smfrench

...when unix extensions aren't enabled. This makes everything on
the mount appear to be owned by the current user.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/cifs/inode.c |    8 ++++++++
 1 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 100ad85..d425d08 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1661,11 +1661,19 @@ check_inval:
 int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
 	struct kstat *stat)
 {
+	struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb);
+	struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb);
 	int err = cifs_revalidate_dentry(dentry);
+
 	if (!err) {
 		generic_fillattr(dentry->d_inode, stat);
 		stat->blksize = CIFS_MAX_MSGSIZE;
 		stat->ino = CIFS_I(dentry->d_inode)->uniqueid;
+		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTISES &&
+		    !tcon->unix_ext) {
+			stat->uid = current_fsuid();
+			stat->gid = current_fsgid();
+		}
 	}
 	return err;
 }
-- 
1.6.6.1

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

* [PATCH 11/11] cifs: add "multises" mount option
  2010-04-20 20:07 [PATCH 00/11] cifs: implement multisession mounts (try #2) Jeff Layton
                   ` (9 preceding siblings ...)
  2010-04-20 20:07 ` [PATCH 10/11] cifs: on multises mount, set ownership to current_fsuid/current_fsgid Jeff Layton
@ 2010-04-20 20:07 ` Jeff Layton
  2010-04-21  2:42 ` [PATCH 00/11] cifs: implement multisession mounts (try #2) Steve French
  2010-04-21 14:16 ` Stef Bon
  12 siblings, 0 replies; 24+ messages in thread
From: Jeff Layton @ 2010-04-20 20:07 UTC (permalink / raw)
  To: linux-cifs-client, linux-fsdevel; +Cc: obnox, smfrench

This allows someone to declare a mount as multisession mount.
Multisession mounts also imply "noperm" since we want to allow
the server to handle permission checking. It also (for now)
requires Kerberos authentication. Eventually, we could expand
this to other authtypes, but that requires a scheme to allow
per-user credential stashing in some form.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/cifs/connect.c |   13 +++++++++++++
 1 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index bc408ad..75b49f5 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -98,6 +98,7 @@ struct smb_vol {
 	bool noblocksnd:1;
 	bool noautotune:1;
 	bool nostrictsync:1; /* do not force expensive SMBflush on every sync */
+	bool multises:1;
 	unsigned int rsize;
 	unsigned int wsize;
 	bool sockopt_tcp_nodelay:1;
@@ -1338,6 +1339,8 @@ cifs_parse_mount_options(char *options, const char *devname,
 			printk(KERN_WARNING "CIFS: Mount option noac not "
 				"supported. Instead set "
 				"/proc/fs/cifs/LookupCacheEnabled to 0\n");
+		} else if (strnicmp(data, "multises", 8) == 0) {
+			vol->multises = true;
 		} else
 			printk(KERN_WARNING "CIFS: Unknown mount option %s\n",
 						data);
@@ -1369,6 +1372,13 @@ cifs_parse_mount_options(char *options, const char *devname,
 			return 1;
 		}
 	}
+
+	if (vol->multises && vol->sectype != Kerberos) {
+		cERROR(1, ("Multisession mounts currently require krb5 "
+			   "authentication!"));
+		return 1;
+	}
+
 	if (vol->UNCip == NULL)
 		vol->UNCip = &vol->UNC[2];
 
@@ -2579,6 +2589,9 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info,
 		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
 	if (pvolume_info->dynperm)
 		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
+	if (pvolume_info->multises)
+		cifs_sb->mnt_cifs_flags |= (CIFS_MOUNT_MULTISES |
+					    CIFS_MOUNT_NO_PERM);
 	if (pvolume_info->direct_io) {
 		cFYI(1, ("mounting share using direct i/o"));
 		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
-- 
1.6.6.1


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

* Re: [PATCH 00/11] cifs: implement multisession mounts (try #2)
  2010-04-20 20:07 [PATCH 00/11] cifs: implement multisession mounts (try #2) Jeff Layton
                   ` (10 preceding siblings ...)
  2010-04-20 20:07 ` [PATCH 11/11] cifs: add "multises" mount option Jeff Layton
@ 2010-04-21  2:42 ` Steve French
  2010-04-21 14:16 ` Stef Bon
  12 siblings, 0 replies; 24+ messages in thread
From: Steve French @ 2010-04-21  2:42 UTC (permalink / raw)
  To: Jeff Layton; +Cc: linux-fsdevel, linux-cifs-client

On Tue, Apr 20, 2010 at 3:07 PM, Jeff Layton <jlayton@redhat.com> wrote:
> This is a second pass at implementing multisession mounts for CIFS. The
> main change since the last one is that I've broken out a series of
> preliminary patches into a separate set and posted them separately. This
> set is based on those changes:

This looks like it will be very useful.

>    http://lists.samba.org/archive/linux-cifs-client/2010-April/005830.html
>
> Thus, this set is a bit smaller than the last one. Hopefully that will
> make it easier to review.

I will review these, but other review feedback would be appreciated
especially given the complexity.

-- 
Thanks,

Steve

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

* Re: [PATCH 00/11] cifs: implement multisession mounts (try #2)
  2010-04-20 20:07 [PATCH 00/11] cifs: implement multisession mounts (try #2) Jeff Layton
                   ` (11 preceding siblings ...)
  2010-04-21  2:42 ` [PATCH 00/11] cifs: implement multisession mounts (try #2) Steve French
@ 2010-04-21 14:16 ` Stef Bon
  2010-04-21 18:13   ` [linux-cifs-client] " Jeff Layton
  12 siblings, 1 reply; 24+ messages in thread
From: Stef Bon @ 2010-04-21 14:16 UTC (permalink / raw)
  To: Jeff Layton; +Cc: linux-fsdevel, smfrench, linux-cifs-client

I'm sorry but what is a multisession mount?

Stef

2010/4/20 Jeff Layton <jlayton@redhat.com>:
> This is a second pass at implementing multisession mounts for CIFS. The
>
> _______________________________________________
> linux-cifs-client mailing list
> linux-cifs-client@lists.samba.org
> https://lists.samba.org/mailman/listinfo/linux-cifs-client
>

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

* Re: [linux-cifs-client] [PATCH 00/11] cifs: implement multisession mounts (try #2)
  2010-04-21 14:16 ` Stef Bon
@ 2010-04-21 18:13   ` Jeff Layton
  2010-04-22 14:56     ` Stef Bon
  0 siblings, 1 reply; 24+ messages in thread
From: Jeff Layton @ 2010-04-21 18:13 UTC (permalink / raw)
  To: Stef Bon; +Cc: linux-cifs-client, linux-fsdevel, smfrench

On Wed, 21 Apr 2010 16:16:26 +0200
Stef Bon <stefbon@gmail.com> wrote:

> I'm sorry but what is a multisession mount?
> 
> Stef
> 

Sorry, I guess I should have been more clear. I'll try to flesh out the
description a bit more on the next respin of this set:

Currently, CIFS will only uses a single set of credentials on a
mountpoint, and those credentials are decided at mount time. This is
fine if you only ever have a single user using that mountpoint. In many
cases though, multiple users on a client may access the mount. When
this happens, those users share the mount's credentials. This means
that you can't enforce permissions on a per-user basis on a CIFS mount.

Now, CIFS tries to do several kludgey things to get around this
limitation. It tries to enforce permissions locally, particularly if
you have unix extensions enabled (which allows the client to fetch
ownership and mode info from the server), but this is an inherently
broken and racy proposition -- you have to be able to map local uid's
to the server's, for instance and you also are faced with the
possibility that permissions can change after you check them.

There are also problems with inode creation. If you create a file, the
ownership on the server is generally set to whatever the mount creds
map to, and that has no relation to the user actually accessing the
mount. This leads to a very confusing problem that users sometimes hit
where they "touch" a new file on a mount, and get an error back. The
file is created, but the ownership and mode are set in such a way that
utimes() on it fails when the client tries to enforce permissions.

The idea with this set is to address the root cause and allow the
client to use multiple sets of credentials based on the fsuid of the
task accessing the mount. This is a little more involved than with a
filesystem like NFS -- you have to establish a "session" with the
server for each set of credentials.

Clear as mud?
-- 
Jeff Layton <jlayton@redhat.com>

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

* Re: [linux-cifs-client] [PATCH 00/11] cifs: implement multisession mounts (try #2)
  2010-04-21 18:13   ` [linux-cifs-client] " Jeff Layton
@ 2010-04-22 14:56     ` Stef Bon
  2010-04-22 15:39       ` Jamie Lokier
  2010-04-22 17:51       ` Jeff Layton
  0 siblings, 2 replies; 24+ messages in thread
From: Stef Bon @ 2010-04-22 14:56 UTC (permalink / raw)
  To: Jeff Layton; +Cc: linux-cifs-client, linux-fsdevel, smfrench

2010/4/21 Jeff Layton <jlayton@redhat.com>:
> On Wed, 21 Apr 2010 16:16:26 +0200
> Stef Bon <stefbon@gmail.com> wrote:
>
>> I'm sorry but what is a multisession mount?
>>
>> Stef
>>
>
> Sorry, I guess I should have been more clear.

Well you dio not have to apologise!
There is nothing wrong with asking.

>I'll try to flesh out the
> description a bit more on the next respin of this set:
>
> Currently, CIFS will only uses a single set of credentials on a
> mountpoint, and those credentials are decided at mount time. This is
> fine if you only ever have a single user using that mountpoint. In many
> cases though, multiple users on a client may access the mount. When
> this happens, those users share the mount's credentials. This means
> that you can't enforce permissions on a per-user basis on a CIFS mount.
>
> Now, CIFS tries to do several kludgey things to get around this
> limitation. It tries to enforce permissions locally, particularly if
> you have unix extensions enabled (which allows the client to fetch
> ownership and mode info from the server), but this is an inherently
> broken and racy proposition -- you have to be able to map local uid's
> to the server's, for instance and you also are faced with the
> possibility that permissions can change after you check them.
>
> There are also problems with inode creation. If you create a file, the
> ownership on the server is generally set to whatever the mount creds
> map to, and that has no relation to the user actually accessing the
> mount. This leads to a very confusing problem that users sometimes hit
> where they "touch" a new file on a mount, and get an error back. The
> file is created, but the ownership and mode are set in such a way that
> utimes() on it fails when the client tries to enforce permissions.
>
> The idea with this set is to address the root cause and allow the
> client to use multiple sets of credentials based on the fsuid of the
> task accessing the mount. This is a little more involved than with a
> filesystem like NFS -- you have to establish a "session" with the
> server for each set of credentials.
>
> Clear as mud?

Yes very clear, what you want, but to me the whole problem is strange!

Using more than one set of credentials (if using those) looks to me a not logic.
NOt only because my construction (mount.md5key) is using seperate
mountpoints per user, pure
for securiity reasons. Another user is not allowed to access my mounts
(not only to smb shares but every mount)

But apart from that, I think all the data (files,permissions,..)
depend on the credentials provided. The server "decides"
what the client can see. Now you want to make the mounpoint present
all the different "views" in one?

I do not know this is possible. The client should maintain different
views (or sessions as you call it) and present the view to the user.
But what if a user which is not linked to any credentials on the
client accesses the mountpiont?

Stef

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

* Re: [linux-cifs-client] [PATCH 00/11] cifs: implement multisession mounts (try #2)
  2010-04-22 14:56     ` Stef Bon
@ 2010-04-22 15:39       ` Jamie Lokier
  2010-04-22 16:57         ` Steve French
  2010-04-22 19:25         ` Jeff Layton
  2010-04-22 17:51       ` Jeff Layton
  1 sibling, 2 replies; 24+ messages in thread
From: Jamie Lokier @ 2010-04-22 15:39 UTC (permalink / raw)
  To: Stef Bon; +Cc: Jeff Layton, linux-cifs-client, linux-fsdevel, smfrench

Stef Bon wrote:
> 2010/4/21 Jeff Layton <jlayton@redhat.com>:
> > On Wed, 21 Apr 2010 16:16:26 +0200
> > Stef Bon <stefbon@gmail.com> wrote:
> >
> >> I'm sorry but what is a multisession mount?
> >>
> >> Stef
> >>
> >
> > Sorry, I guess I should have been more clear.
> 
> Well you dio not have to apologise!
> There is nothing wrong with asking.
> 
> >I'll try to flesh out the
> > description a bit more on the next respin of this set:
> >
> > Currently, CIFS will only uses a single set of credentials on a
> > mountpoint, and those credentials are decided at mount time. This is
> > fine if you only ever have a single user using that mountpoint. In many
> > cases though, multiple users on a client may access the mount. When
> > this happens, those users share the mount's credentials. This means
> > that you can't enforce permissions on a per-user basis on a CIFS mount.
> >
> > Now, CIFS tries to do several kludgey things to get around this
> > limitation. It tries to enforce permissions locally, particularly if
> > you have unix extensions enabled (which allows the client to fetch
> > ownership and mode info from the server), but this is an inherently
> > broken and racy proposition -- you have to be able to map local uid's
> > to the server's, for instance and you also are faced with the
> > possibility that permissions can change after you check them.
> >
> > There are also problems with inode creation. If you create a file, the
> > ownership on the server is generally set to whatever the mount creds
> > map to, and that has no relation to the user actually accessing the
> > mount. This leads to a very confusing problem that users sometimes hit
> > where they "touch" a new file on a mount, and get an error back. The
> > file is created, but the ownership and mode are set in such a way that
> > utimes() on it fails when the client tries to enforce permissions.
> >
> > The idea with this set is to address the root cause and allow the
> > client to use multiple sets of credentials based on the fsuid of the
> > task accessing the mount. This is a little more involved than with a
> > filesystem like NFS -- you have to establish a "session" with the
> > server for each set of credentials.
> >
> > Clear as mud?
> 
> Yes very clear, what you want, but to me the whole problem is strange!
> 
> Using more than one set of credentials (if using those) looks to me a not logic.
> NOt only because my construction (mount.md5key) is using seperate
> mountpoints per user, pure
> for securiity reasons. Another user is not allowed to access my mounts
> (not only to smb shares but every mount)
> 
> But apart from that, I think all the data (files,permissions,..)
> depend on the credentials provided. The server "decides"
> what the client can see. Now you want to make the mounpoint present
> all the different "views" in one?
> 
> I do not know this is possible. The client should maintain different
> views (or sessions as you call it) and present the view to the user.
> But what if a user which is not linked to any credentials on the
> client accesses the mountpiont?

Fwiw, I originally agreed with Jeff's idea but now prefer Stef's :-)

In some ways this is an automount type of problem: When a new user
accesses the mount, creating a new session (and asking for user
credentials) is not unlike creating a new mount.

If automount supported "per-user" style mounts, magically resolving to
a different mounted fs depending in the accessing user's credentials,
like the automounters of old could sometimes do :-) Would that solve
the kernel part of this problem?

I think it probably would.

fsuid is probably the wrong decision input for this.  For simple
setups, yes, but if you have the same user logged in but one instance
has diferent credentials such as using "newgrp", auxiliary groups,
SElinux and so on... each of those should be able to influence whether
separate sessions are needed.

As non-kerberos setups need some userspace to support asking for the
password or whatever, perhaps this is a general purpose way forward
with it: An autofs-like capability to intercept mountpoint traversals
and upcall to userspace.

Perhaps extending FUSE on the user side, if autofs isn't appropriate.
FUSE is very programmable, and the kernel side can cache some things.
If better caching is needed, that would be to everyone's benefit.

That kind of approach would help other filesystems as much as CIFS.

Of course all of this still needs the ability to create new CIFS
sessions when needed :-)  But triggering it from userspace has a lot of
advantages.

- Jamie

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

* Re: [PATCH 00/11] cifs: implement multisession mounts (try #2)
  2010-04-22 15:39       ` Jamie Lokier
@ 2010-04-22 16:57         ` Steve French
  2010-04-24  2:30           ` [linux-cifs-client] " Jamie Lokier
  2010-04-22 19:25         ` Jeff Layton
  1 sibling, 1 reply; 24+ messages in thread
From: Steve French @ 2010-04-22 16:57 UTC (permalink / raw)
  To: Jamie Lokier; +Cc: linux-fsdevel, linux-cifs-client, Jeff Layton

On Thu, Apr 22, 2010 at 10:39 AM, Jamie Lokier <jamie@shareable.org> wrote:
> Stef Bon wrote:

>> >I'll try to flesh out the
>> > description a bit more on the next respin of this set:
>> >
>> > Currently, CIFS will only uses a single set of credentials on a
>> > mountpoint, and those credentials are decided at mount time. This is
>> > fine if you only ever have a single user using that mountpoint. In many
>> > cases though, multiple users on a client may access the mount. When
>> > this happens, those users share the mount's credentials. This means
>> > that you can't enforce permissions on a per-user basis on a CIFS mount.
>> >
>> > Now, CIFS tries to do several kludgey things to get around this
>> > limitation. It tries to enforce permissions locally, particularly if
>> > you have unix extensions enabled (which allows the client to fetch
>> > ownership and mode info from the server), but this is an inherently
>> > broken and racy proposition -- you have to be able to map local uid's
>> > to the server's, for instance and you also are faced with the
>> > possibility that permissions can change after you check them.
>> >
>> > There are also problems with inode creation. If you create a file, the
>> > ownership on the server is generally set to whatever the mount creds
>> > map to, and that has no relation to the user actually accessing the
>> > mount. This leads to a very confusing problem that users sometimes hit
>> > where they "touch" a new file on a mount, and get an error back. The
>> > file is created, but the ownership and mode are set in such a way that
>> > utimes() on it fails when the client tries to enforce permissions.
>> >
>> > The idea with this set is to address the root cause and allow the
>> > client to use multiple sets of credentials based on the fsuid of the
>> > task accessing the mount. This is a little more involved than with a
>> > filesystem like NFS -- you have to establish a "session" with the
>> > server for each set of credentials.
>> >
>> > Clear as mud?
>>
>> Yes very clear, what you want, but to me the whole problem is strange!
>>
>> Using more than one set of credentials (if using those) looks to me a not logic.
>> NOt only because my construction (mount.md5key) is using seperate
>> mountpoints per user, pure
>> for securiity reasons. Another user is not allowed to access my mounts
>> (not only to smb shares but every mount)
>>
>> But apart from that, I think all the data (files,permissions,..)
>> depend on the credentials provided. The server "decides"
>> what the client can see. Now you want to make the mounpoint present
>> all the different "views" in one?
>>
>> I do not know this is possible. The client should maintain different
>> views (or sessions as you call it) and present the view to the user.
>> But what if a user which is not linked to any credentials on the
>> client accesses the mountpiont?
>
> Fwiw, I originally agreed with Jeff's idea but now prefer Stef's :-)
>
> In some ways this is an automount type of problem: When a new user
> accesses the mount, creating a new session (and asking for user
> credentials) is not unlike creating a new mount.
>
> If automount supported "per-user" style mounts, magically resolving to
> a different mounted fs depending in the accessing user's credentials,
> like the automounters of old could sometimes do :-) Would that solve
> the kernel part of this problem?
>
> I think it probably would.
>
> fsuid is probably the wrong decision input for this.  For simple
> setups, yes, but if you have the same user logged in but one instance
> has diferent credentials such as using "newgrp", auxiliary groups,
> SElinux and so on... each of those should be able to influence whether
> separate sessions are needed.
>
> As non-kerberos setups need some userspace to support asking for the
> password or whatever, perhaps this is a general purpose way forward
> with it: An autofs-like capability to intercept mountpoint traversals
> and upcall to userspace.
>
> Perhaps extending FUSE on the user side, if autofs isn't appropriate.
> FUSE is very programmable, and the kernel side can cache some things.
> If better caching is needed, that would be to everyone's benefit.

Caching as in cache-fs? or as in caching user credentials?

> That kind of approach would help other filesystems as much as CIFS.
>
> Of course all of this still needs the ability to create new CIFS
> sessions when needed :-)  But triggering it from userspace has a lot of
> advantages.

Yes, but not as easy as it sounds to ask the user anything
(e.g. on "find /") even if kde/gnome desktop would popups on
fist attempt to access each directory mounted to servers we don't
have credentials or userid/password for (for this user).
We need the userid/password or krb5 ticket to use to
setup the session (we could ask winbind or the kernel keyring to
provide this).  I prefer longterm that cifs or its helpers don't do password
storage, but rather some service such as winbind working with
the kernel keyring do this - so it can be analyzed by more eyes
to make sure it is secure.


-- 
Thanks,

Steve

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

* Re: [linux-cifs-client] [PATCH 00/11] cifs: implement multisession mounts (try #2)
  2010-04-22 14:56     ` Stef Bon
  2010-04-22 15:39       ` Jamie Lokier
@ 2010-04-22 17:51       ` Jeff Layton
  2010-04-22 19:55         ` Stef Bon
  1 sibling, 1 reply; 24+ messages in thread
From: Jeff Layton @ 2010-04-22 17:51 UTC (permalink / raw)
  To: Stef Bon; +Cc: linux-cifs-client, linux-fsdevel, smfrench

On Thu, 22 Apr 2010 16:56:55 +0200
Stef Bon <stefbon@gmail.com> wrote:

> 2010/4/21 Jeff Layton <jlayton@redhat.com>:
> > On Wed, 21 Apr 2010 16:16:26 +0200
> > Stef Bon <stefbon@gmail.com> wrote:
> >
> >> I'm sorry but what is a multisession mount?
> >>
> >> Stef
> >>
> >
> > Sorry, I guess I should have been more clear.
> 
> Well you dio not have to apologise!
> There is nothing wrong with asking.
> 
> >I'll try to flesh out the
> > description a bit more on the next respin of this set:
> >
> > Currently, CIFS will only uses a single set of credentials on a
> > mountpoint, and those credentials are decided at mount time. This is
> > fine if you only ever have a single user using that mountpoint. In many
> > cases though, multiple users on a client may access the mount. When
> > this happens, those users share the mount's credentials. This means
> > that you can't enforce permissions on a per-user basis on a CIFS mount.
> >
> > Now, CIFS tries to do several kludgey things to get around this
> > limitation. It tries to enforce permissions locally, particularly if
> > you have unix extensions enabled (which allows the client to fetch
> > ownership and mode info from the server), but this is an inherently
> > broken and racy proposition -- you have to be able to map local uid's
> > to the server's, for instance and you also are faced with the
> > possibility that permissions can change after you check them.
> >
> > There are also problems with inode creation. If you create a file, the
> > ownership on the server is generally set to whatever the mount creds
> > map to, and that has no relation to the user actually accessing the
> > mount. This leads to a very confusing problem that users sometimes hit
> > where they "touch" a new file on a mount, and get an error back. The
> > file is created, but the ownership and mode are set in such a way that
> > utimes() on it fails when the client tries to enforce permissions.
> >
> > The idea with this set is to address the root cause and allow the
> > client to use multiple sets of credentials based on the fsuid of the
> > task accessing the mount. This is a little more involved than with a
> > filesystem like NFS -- you have to establish a "session" with the
> > server for each set of credentials.
> >
> > Clear as mud?
> 
> Yes very clear, what you want, but to me the whole problem is strange!
> 
> Using more than one set of credentials (if using those) looks to me a not logic.
> NOt only because my construction (mount.md5key) is using seperate
> mountpoints per user, pure
> for securiity reasons. Another user is not allowed to access my mounts
> (not only to smb shares but every mount)
> 

I'm sure your solution solves some problems, but it's I don't think it
precludes this work. We have users of CIFS who do something similar
today (albeit much more manually).

There are certainly cases where someone has a shared directory that
they need multiple users to access. Having to have a separate
mountpoint for each of those users seems rather cumbersome, IMO.

In either case, this is simply a different way to solve that issue.
This solution will not preclude you from using CIFS in the way you wish
(with a single set of credentials per mount).

> But apart from that, I think all the data (files,permissions,..)
> depend on the credentials provided. The server "decides"
> what the client can see. Now you want to make the mounpoint present
> all the different "views" in one?
> 

CIFS does not cache readdir info, so the server will still decide what
each user can "see" based on the credentials that call the FIND_FILE
ops. In the event of a syscall against a dentry that's visible to one
user but not another, a call will still go out over the wire before
that syscall is satisfied. Therefore I don't think this patchset will
allow information "leakage" to users that shouldn't have it.

> I do not know this is possible. The client should maintain different
> views (or sessions as you call it) and present the view to the user.
> But what if a user which is not linked to any credentials on the
> client accesses the mountpiont?
> 

There are a couple of possibilties. In the current patchset, they'll
get back an error when they try to access the mount -- -ENOKEY
currently in most cases, but I will likely need to translate that to
something that more syscalls will expect, such as -EACCES.

As a future feature, it might be helpful to establish an anonymous
session to the server and map users without credentials to that.

-- 
Jeff Layton <jlayton@redhat.com>

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

* Re: [PATCH 00/11] cifs: implement multisession mounts (try #2)
  2010-04-22 15:39       ` Jamie Lokier
  2010-04-22 16:57         ` Steve French
@ 2010-04-22 19:25         ` Jeff Layton
  2010-04-22 19:55           ` Steve French
  1 sibling, 1 reply; 24+ messages in thread
From: Jeff Layton @ 2010-04-22 19:25 UTC (permalink / raw)
  To: Jamie Lokier; +Cc: linux-fsdevel, smfrench, linux-cifs-client

On Thu, 22 Apr 2010 16:39:48 +0100
Jamie Lokier <jamie@shareable.org> wrote:

> Stef Bon wrote:
> > 2010/4/21 Jeff Layton <jlayton@redhat.com>:
> > > On Wed, 21 Apr 2010 16:16:26 +0200
> > > Stef Bon <stefbon@gmail.com> wrote:
> > >
> > >> I'm sorry but what is a multisession mount?
> > >>
> > >> Stef
> > >>
> > >
> > > Sorry, I guess I should have been more clear.
> > 
> > Well you dio not have to apologise!
> > There is nothing wrong with asking.
> > 
> > >I'll try to flesh out the
> > > description a bit more on the next respin of this set:
> > >
> > > Currently, CIFS will only uses a single set of credentials on a
> > > mountpoint, and those credentials are decided at mount time. This is
> > > fine if you only ever have a single user using that mountpoint. In many
> > > cases though, multiple users on a client may access the mount. When
> > > this happens, those users share the mount's credentials. This means
> > > that you can't enforce permissions on a per-user basis on a CIFS mount.
> > >
> > > Now, CIFS tries to do several kludgey things to get around this
> > > limitation. It tries to enforce permissions locally, particularly if
> > > you have unix extensions enabled (which allows the client to fetch
> > > ownership and mode info from the server), but this is an inherently
> > > broken and racy proposition -- you have to be able to map local uid's
> > > to the server's, for instance and you also are faced with the
> > > possibility that permissions can change after you check them.
> > >
> > > There are also problems with inode creation. If you create a file, the
> > > ownership on the server is generally set to whatever the mount creds
> > > map to, and that has no relation to the user actually accessing the
> > > mount. This leads to a very confusing problem that users sometimes hit
> > > where they "touch" a new file on a mount, and get an error back. The
> > > file is created, but the ownership and mode are set in such a way that
> > > utimes() on it fails when the client tries to enforce permissions.
> > >
> > > The idea with this set is to address the root cause and allow the
> > > client to use multiple sets of credentials based on the fsuid of the
> > > task accessing the mount. This is a little more involved than with a
> > > filesystem like NFS -- you have to establish a "session" with the
> > > server for each set of credentials.
> > >
> > > Clear as mud?
> > 
> > Yes very clear, what you want, but to me the whole problem is strange!
> > 
> > Using more than one set of credentials (if using those) looks to me a not logic.
> > NOt only because my construction (mount.md5key) is using seperate
> > mountpoints per user, pure
> > for securiity reasons. Another user is not allowed to access my mounts
> > (not only to smb shares but every mount)
> > 
> > But apart from that, I think all the data (files,permissions,..)
> > depend on the credentials provided. The server "decides"
> > what the client can see. Now you want to make the mounpoint present
> > all the different "views" in one?
> > 
> > I do not know this is possible. The client should maintain different
> > views (or sessions as you call it) and present the view to the user.
> > But what if a user which is not linked to any credentials on the
> > client accesses the mountpiont?
> 
> Fwiw, I originally agreed with Jeff's idea but now prefer Stef's :-)
> 
> In some ways this is an automount type of problem: When a new user
> accesses the mount, creating a new session (and asking for user
> credentials) is not unlike creating a new mount.
> 

I see no reason why we need to limit a superblock to use a single
CIFS session (and hence a single set of credentials). Adding extra
layers of userspace stuff is just working around a limitation of the
filesystem. Why shouldn't CIFS just use a proper set of credentials in
the first place? I think multi-user CIFS should be as easy to deploy as
NFS.

> If automount supported "per-user" style mounts, magically resolving to
> a different mounted fs depending in the accessing user's credentials,
> like the automounters of old could sometimes do :-) Would that solve
> the kernel part of this problem?
> 
> I think it probably would.
> 

Maybe, but that seems like we're just adding userspace layers to work
around a fundamental design limitation of Linux CIFS. There are good
reasons to allow different users to access the same mountpoint. The
main one being that it's simply more intuitive for administrators. We
don't need these extra layers for other network filesystems (such as
NFS). Why should CIFS be any different here?

> fsuid is probably the wrong decision input for this.  For simple
> setups, yes, but if you have the same user logged in but one instance
> has diferent credentials such as using "newgrp", auxiliary groups,
> SElinux and so on... each of those should be able to influence whether
> separate sessions are needed.
> 

I was thinking last night about changing this and trying to do this a
little more cleanly using task credentials. I'm still trying to
understand what I should key the lookup off of however. When a task
tries to get access to the mount, what should we use to determine
whether it uses a given session?

Note that kerberized NFS uses the fsuid too, so there is some precedent
for that.

> As non-kerberos setups need some userspace to support asking for the
> password or whatever, perhaps this is a general purpose way forward
> with it: An autofs-like capability to intercept mountpoint traversals
> and upcall to userspace.
> 

What will you do if there is no user to type in the password? Consider
crontab jobs, for instance. This is something we could certainly
consider for the future but it's really a separate project I think.

In fact, I may be mentoring someone for GSoC to add some infrastructure
to allow storage NTLM creds via keyctl that CIFS could then use to
establish sessions. The limitation of this to kerberos may not be
long-lived.

> Perhaps extending FUSE on the user side, if autofs isn't appropriate.
> FUSE is very programmable, and the kernel side can cache some things.
> If better caching is needed, that would be to everyone's benefit.
> 
> That kind of approach would help other filesystems as much as CIFS.
> 
> Of course all of this still needs the ability to create new CIFS
> sessions when needed :-)  But triggering it from userspace has a lot of
> advantages.
> 

Sounds like it might be useful, but I'm not sure it's a general enough
solution for this problem.

It has some disadvantages. Extra setup and administration overhead
being the big ones. It also means that you can't have a "shared"
directory since you're requiring separate mountpoints for each local
user.

The solution I'm proposing will make a shared CIFS mount as easy to set
up and deal with as it is with NFS. Which is to say, non-trivial but
doable for the average sysadmin with a clue.

-- 
Jeff Layton <jlayton@redhat.com>

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

* Re: [PATCH 00/11] cifs: implement multisession mounts (try #2)
  2010-04-22 17:51       ` Jeff Layton
@ 2010-04-22 19:55         ` Stef Bon
  0 siblings, 0 replies; 24+ messages in thread
From: Stef Bon @ 2010-04-22 19:55 UTC (permalink / raw)
  To: Jeff Layton; +Cc: linux-fsdevel, smfrench, linux-cifs-client

2010/4/22 Jeff Layton <jlayton@redhat.com>:
> On Thu, 22 Apr 2010 16:56:55 +0200
> Stef Bon <stefbon@gmail.com> wrote:
>
>> 2010/4/21 Jeff Layton <jlayton@redhat.com>:
>> > On Wed, 21 Apr 2010 16:16:26 +0200
>> > Stef Bon <stefbon@gmail.com> wrote:
>> >
>> >> I'm sorry but what is a multisession mount?
>> >>
>> >> Stef

>> for securiity reasons. Another user is not allowed to access my mounts
>> (not only to smb shares but every mount)
>>
>
> I'm sure your solution solves some problems, but it's I don't think it
> precludes this work. We have users of CIFS who do something similar
> today (albeit much more manually).
>
> There are certainly cases where someone has a shared directory that
> they need multiple users to access. Having to have a separate
> mountpoint for each of those users seems rather cumbersome, IMO.
>
> In either case, this is simply a different way to solve that issue.
> This solution will not preclude you from using CIFS in the way you wish
> (with a single set of credentials per mount).

Yes I understand. This is another way to provide data on the remote server,
but its just so not my idea of mounting.
But now when I read and think futher about this, I see that's a
providing new functionality
I can understand.

>
>> But apart from that, I think all the data (files,permissions,..)
>> depend on the credentials provided. The server "decides"
>> what the client can see. Now you want to make the mounpoint present
>> all the different "views" in one?
>>
>
> CIFS does not cache readdir info, so the server will still decide what
> each user can "see" based on the credentials that call the FIND_FILE
> ops. In the event of a syscall against a dentry that's visible to one
> user but not another, a call will still go out over the wire before
> that syscall is satisfied. Therefore I don't think this patchset will
> allow information "leakage" to users that shouldn't have it

So in this situation the amount of mountpoints is never more than the
number of smb shares available in the network, and does not depend
on the number of users, which in my construction is.

>
>> I do not know this is possible. The client should maintain different
>> views (or sessions as you call it) and present the view to the user.
>> But what if a user which is not linked to any credentials on the
>> client accesses the mountpiont?
>>
>
> There are a couple of possibilties. In the current patchset, they'll
> get back an error when they try to access the mount -- -ENOKEY
> currently in most cases, but I will likely need to translate that to
> something that more syscalls will expect, such as -EACCES.
>
> As a future feature, it might be helpful to establish an anonymous
> session to the server and map users without credentials to that.

That's a sound idea.

Stef

>
> --
> Jeff Layton <jlayton@redhat.com>
>

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

* Re: [PATCH 00/11] cifs: implement multisession mounts (try #2)
  2010-04-22 19:25         ` Jeff Layton
@ 2010-04-22 19:55           ` Steve French
  2010-04-24  2:26             ` [linux-cifs-client] " Jamie Lokier
  0 siblings, 1 reply; 24+ messages in thread
From: Steve French @ 2010-04-22 19:55 UTC (permalink / raw)
  To: Jeff Layton; +Cc: linux-fsdevel, linux-cifs-client, Jamie Lokier

On Thu, Apr 22, 2010 at 2:25 PM, Jeff Layton <jlayton@redhat.com> wrote:
> The solution I'm proposing will make a shared CIFS mount as easy to set
> up and deal with as it is with NFS. Which is to say, non-trivial but
> doable for the average sysadmin with a clue.

Probably easier, since for the krb5 case ActiveDirectory kerberos
(Windows or Samba 4 KDC) with cifs is not too bad to setup.

For the NTLMv2 case it is very easy to setup.

-- 
Thanks,

Steve

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

* Re: [linux-cifs-client] [PATCH 00/11] cifs: implement multisession mounts (try #2)
  2010-04-22 19:55           ` Steve French
@ 2010-04-24  2:26             ` Jamie Lokier
  0 siblings, 0 replies; 24+ messages in thread
From: Jamie Lokier @ 2010-04-24  2:26 UTC (permalink / raw)
  To: Steve French; +Cc: Jeff Layton, Stef Bon, linux-cifs-client, linux-fsdevel

Steve French wrote:
> On Thu, Apr 22, 2010 at 2:25 PM, Jeff Layton <jlayton@redhat.com> wrote:
> > The solution I'm proposing will make a shared CIFS mount as easy to set
> > up and deal with as it is with NFS. Which is to say, non-trivial but
> > doable for the average sysadmin with a clue.
> 
> Probably easier, since for the krb5 case ActiveDirectory kerberos
> (Windows or Samba 4 KDC) with cifs is not too bad to setup.
> 
> For the NTLMv2 case it is very easy to setup.

Neither of those are as easy as setting up basic NFS - by a long way.

But maybe easier than setting up kerberized NFS :-)

-- Jamie



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

* Re: [linux-cifs-client] [PATCH 00/11] cifs: implement multisession mounts (try #2)
  2010-04-22 16:57         ` Steve French
@ 2010-04-24  2:30           ` Jamie Lokier
  0 siblings, 0 replies; 24+ messages in thread
From: Jamie Lokier @ 2010-04-24  2:30 UTC (permalink / raw)
  To: Steve French; +Cc: Stef Bon, Jeff Layton, linux-cifs-client, linux-fsdevel

Steve French wrote:
> > Perhaps extending FUSE on the user side, if autofs isn't appropriate.
> > FUSE is very programmable, and the kernel side can cache some things.
> > If better caching is needed, that would be to everyone's benefit.
> 
> Caching as in cache-fs? or as in caching user credentials?

User credentials in this case.  I don't know if FUSE actually does
that - only that the architecture could go in that direction if useful.

> > That kind of approach would help other filesystems as much as CIFS.
> >
> > Of course all of this still needs the ability to create new CIFS
> > sessions when needed :-)  But triggering it from userspace has a lot of
> > advantages.
> 
> Yes, but not as easy as it sounds to ask the user anything
> (e.g. on "find /") even if kde/gnome desktop would popups on
> fist attempt to access each directory mounted to servers we don't
> have credentials or userid/password for (for this user).
> We need the userid/password or krb5 ticket to use to
> setup the session (we could ask winbind or the kernel keyring to
> provide this).  I prefer longterm that cifs or its helpers don't do password
> storage, but rather some service such as winbind working with
> the kernel keyring do this - so it can be analyzed by more eyes
> to make sure it is secure.

I agree it's not particularly easy, and I agree with _not_ storing
passwords in the kernel.

You seem to agree that a userspace helper should be involved
(winbind), and the keyring seems a natural thing to use kernel side,
which is really the same as what I've suggested, only I'd put a bit
more of the mount-traversal decision making and session setup into
'winbind-plus'.

-- Jamie
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

end of thread, other threads:[~2010-04-24  2:30 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-04-20 20:07 [PATCH 00/11] cifs: implement multisession mounts (try #2) Jeff Layton
2010-04-20 20:07 ` [PATCH 01/11] cifs: add function to get a tcon from cifs_sb Jeff Layton
2010-04-20 20:07 ` [PATCH 02/11] cifs: add tcon field to cifsFileInfo struct Jeff Layton
2010-04-20 20:07 ` [PATCH 03/11] cifs: make various routines use the cifsFileInfo->tcon pointer Jeff Layton
2010-04-20 20:07 ` [PATCH 04/11] cifs: have find_readable/writable_file filter by fsuid Jeff Layton
2010-04-20 20:07 ` [PATCH 05/11] cifs: fix cifs_show_options to show "username=" or "multises" Jeff Layton
2010-04-20 20:07 ` [PATCH 06/11] cifs: have cifs_new_fileinfo take a tcon arg Jeff Layton
2010-04-20 20:07 ` [PATCH 07/11] cifs: allow for cifs_sb_tcon() to return an error Jeff Layton
2010-04-20 20:07 ` [PATCH 08/11] cifs: fix handling of signing with writepages Jeff Layton
2010-04-20 20:07 ` [PATCH 09/11] cifs: add routines to build sessions and tcons on the fly Jeff Layton
2010-04-20 20:07 ` [PATCH 10/11] cifs: on multises mount, set ownership to current_fsuid/current_fsgid Jeff Layton
2010-04-20 20:07 ` [PATCH 11/11] cifs: add "multises" mount option Jeff Layton
2010-04-21  2:42 ` [PATCH 00/11] cifs: implement multisession mounts (try #2) Steve French
2010-04-21 14:16 ` Stef Bon
2010-04-21 18:13   ` [linux-cifs-client] " Jeff Layton
2010-04-22 14:56     ` Stef Bon
2010-04-22 15:39       ` Jamie Lokier
2010-04-22 16:57         ` Steve French
2010-04-24  2:30           ` [linux-cifs-client] " Jamie Lokier
2010-04-22 19:25         ` Jeff Layton
2010-04-22 19:55           ` Steve French
2010-04-24  2:26             ` [linux-cifs-client] " Jamie Lokier
2010-04-22 17:51       ` Jeff Layton
2010-04-22 19:55         ` Stef Bon

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.