All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/45] SMB2 base operation support
@ 2012-07-18 15:48 Pavel Shilovsky
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
  0 siblings, 1 reply; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

This patchset is the second part of big SMB2 merge (after smb2-mount). It adds SMB2 support for
file and inode operation as well as rewrites existing part of their code to make it use ops
server struct of protocol specific callbacks.

The patchset is tested by cthon tests: basic and general parts.

Pavel Shilovsky (45):
  CIFS: Make CAP_* checks protocol independent
  CIFS: Simpliify cifs_mkdir call
  CIFS: Separate protocol specific part from mkdir
  CIFS: Add SMB2 support for mkdir operation
  CIFS: Move rmdir code to ops struct
  CIFS: Add SMB2 support for rmdir
  CIFS: Protect i_nlink from being negative
  CIFS: Move unlink code to ops struct
  CIFS: Add SMB2 support for unlink
  CIFS: Replace netfid with cifs_fid struct in cifsFileInfo
  CIFS: Move open code to ops struct
  CIFS: Move close code to ops struct
  CIFS: Add open/close file support for SMB2
  CIFS: Move guery file info code to ops struct
  CIFS: Add SMB2 support for query_file_info
  CIFS: Move create code use ops struct
  CIFS: Move reopen code to ops struct
  CIFS: Make flush code use ops struct
  CIFS: Add SMB2 support for flush
  CIFS: Move r/wsize negotiating to ops struct
  CIFS: Add SMB2 r/wsize negotiating
  CIFS: Move async read to ops struct
  CIFS: Add SMB2 support for cifs_iovec_read
  CIFS: Move async write to ops struct
  CIFS: Add SMB2 support for cifs_iovec_write
  CIFS: Move readpage code to ops struct
  CIFS: Add readpage support for SMB2
  CIFS: Move writepage to ops struct
  CIFS: Add writepage support for SMB2
  CIFS: Enable signing in SMB2
  CIFS: Move rename to ops struct
  CIFS: Add SMB2 support for rename operation
  CIFS: Move hardlink to ops struct
  CIFS: Add SMB2 support for hardlink operation
  CIFS: Move set_file_size to ops struct
  CIFS: Add SMB2 support for set_file_size
  CIFS: Move set_file_info to ops struct
  CIFS: Add set_file_info support for SMB2
  CIFS: Move readdir code to ops struct
  CIFS: Add readdir support for SMB2
  CIFS: Process oplocks for SMB2
  CIFS: Move oplock break to ops struct
  CIFS: Add oplock break support for SMB2
  CIFS: Move statfs to ops struct
  CIFS: Add statfs support for SMB2

 fs/cifs/Kconfig         |    1 +
 fs/cifs/Makefile        |    2 +-
 fs/cifs/cifsacl.c       |    2 +-
 fs/cifs/cifsencrypt.c   |   30 ++-
 fs/cifs/cifsfs.c        |   31 +--
 fs/cifs/cifsglob.h      |  241 ++++++++++++-
 fs/cifs/cifsproto.h     |   96 ++----
 fs/cifs/cifssmb.c       |  171 ++++-----
 fs/cifs/connect.c       |  154 +-------
 fs/cifs/dir.c           |  108 +++---
 fs/cifs/file.c          |  473 +++++++++++++-----------
 fs/cifs/inode.c         |  652 ++++++++++++++++----------------
 fs/cifs/ioctl.c         |   13 +-
 fs/cifs/link.c          |   80 +++--
 fs/cifs/misc.c          |    2 +-
 fs/cifs/netmisc.c       |    3 +-
 fs/cifs/readdir.c       |  179 +++++----
 fs/cifs/smb1ops.c       |  351 +++++++++++++++++-
 fs/cifs/smb2file.c      |  106 ++++++
 fs/cifs/smb2glob.h      |   14 +
 fs/cifs/smb2inode.c     |  137 +++++++-
 fs/cifs/smb2maperror.c  |    3 +-
 fs/cifs/smb2misc.c      |   86 ++++-
 fs/cifs/smb2ops.c       |  267 +++++++++++++-
 fs/cifs/smb2pdu.c       |  957 ++++++++++++++++++++++++++++++++++++++++++++++-
 fs/cifs/smb2pdu.h       |  178 +++++++++
 fs/cifs/smb2proto.h     |   71 ++++-
 fs/cifs/smb2transport.c |  157 ++++++++-
 fs/cifs/transport.c     |   24 +-
 29 files changed, 3499 insertions(+), 1090 deletions(-)
 create mode 100644 fs/cifs/smb2file.c

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

* [PATCH 01/45] CIFS: Make CAP_* checks protocol independent
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
@ 2012-07-18 15:48   ` Pavel Shilovsky
       [not found]     ` <1342626541-29872-2-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
  2012-07-18 15:48   ` [PATCH 02/45] CIFS: Simpliify cifs_mkdir call Pavel Shilovsky
                     ` (44 subsequent siblings)
  45 siblings, 1 reply; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Since both CIFS and SMB2 use ses->capabilities (server->capabilities)
field but flags are different we should make such checks protocol
independent.

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/cifsglob.h |   10 ++++++++++
 fs/cifs/connect.c  |    6 +++---
 fs/cifs/dir.c      |    3 +--
 fs/cifs/file.c     |   33 ++++++++++++++++-----------------
 fs/cifs/inode.c    |   26 ++++++++++++--------------
 fs/cifs/link.c     |    6 +++---
 fs/cifs/readdir.c  |   16 ++++++++--------
 fs/cifs/smb1ops.c  |    3 +++
 fs/cifs/smb2ops.c  |    3 +++
 fs/cifs/smb2pdu.c  |    2 ++
 fs/cifs/smb2pdu.h  |    3 +++
 11 files changed, 64 insertions(+), 47 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 12b1176..5695693 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -258,6 +258,9 @@ struct smb_version_values {
 	size_t		max_header_size;
 	size_t		read_rsp_size;
 	__le16		lock_cmd;
+	int		cap_unix;
+	int		cap_nt_find;
+	int		cap_large_files;
 };
 
 #define HEADER_SIZE(server) (server->vals->header_size)
@@ -554,6 +557,13 @@ struct cifs_ses {
    which do not negotiate NTLM or POSIX dialects, but instead
    negotiate one of the older LANMAN dialects */
 #define CIFS_SES_LANMAN 8
+
+static inline bool
+cap_unix(struct cifs_ses *ses)
+{
+	return ses->server->vals->cap_unix & ses->capabilities;
+}
+
 /*
  * there is one of these for each connection to a resource on a particular
  * session
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index b1ab89a..99d50bf 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -3633,7 +3633,7 @@ try_mount_again:
 	}
 
 	/* tell server which Unix caps we support */
-	if (tcon->ses->capabilities & CAP_UNIX) {
+	if (cap_unix(tcon->ses)) {
 		/* reset of caps checks mount to see if unix extensions
 		   disabled for just this mount */
 		reset_cifs_unix_caps(xid, tcon, cifs_sb, volume_info);
@@ -3992,7 +3992,7 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
 	ses->flags = 0;
 	ses->capabilities = server->capabilities;
 	if (linuxExtEnabled == 0)
-		ses->capabilities &= (~CAP_UNIX);
+		ses->capabilities &= (~server->vals->cap_unix);
 
 	cFYI(1, "Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
 		 server->sec_mode, server->capabilities, server->timeAdj);
@@ -4099,7 +4099,7 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid)
 		goto out;
 	}
 
-	if (ses->capabilities & CAP_UNIX)
+	if (cap_unix(ses))
 		reset_cifs_unix_caps(0, tcon, NULL, vol_info);
 out:
 	kfree(vol_info->username);
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 2caba0b..cbe709a 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -182,8 +182,7 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
 		goto out;
 	}
 
-	if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
-	    !tcon->broken_posix_open &&
+	if (tcon->unix_ext && cap_unix(tcon->ses) && !tcon->broken_posix_open &&
 	    (CIFS_UNIX_POSIX_PATH_OPS_CAP &
 			le64_to_cpu(tcon->fsUnixInfo.Capability))) {
 		rc = cifs_posix_open(full_path, &newinode,
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index ea1bb66..1712794 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -385,9 +385,8 @@ int cifs_open(struct inode *inode, struct file *file)
 		oplock = 0;
 
 	if (!tcon->broken_posix_open && tcon->unix_ext &&
-	    (tcon->ses->capabilities & CAP_UNIX) &&
-	    (CIFS_UNIX_POSIX_PATH_OPS_CAP &
-			le64_to_cpu(tcon->fsUnixInfo.Capability))) {
+	    cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
+				le64_to_cpu(tcon->fsUnixInfo.Capability))) {
 		/* can not refresh inode info since size could be stale */
 		rc = cifs_posix_open(full_path, &inode, inode->i_sb,
 				cifs_sb->mnt_file_mode /* ignored */,
@@ -509,10 +508,9 @@ static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
 	else
 		oplock = 0;
 
-	if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
+	if (tcon->unix_ext && cap_unix(tcon->ses) &&
 	    (CIFS_UNIX_POSIX_PATH_OPS_CAP &
-			le64_to_cpu(tcon->fsUnixInfo.Capability))) {
-
+				le64_to_cpu(tcon->fsUnixInfo.Capability))) {
 		/*
 		 * O_CREAT, O_EXCL and O_TRUNC already had their effect on the
 		 * original open. Must mask them off for a reopen.
@@ -1073,7 +1071,7 @@ cifs_push_locks(struct cifsFileInfo *cfile)
 	struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->dentry->d_sb);
 	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
 
-	if ((tcon->ses->capabilities & CAP_UNIX) &&
+	if (cap_unix(tcon->ses) &&
 	    (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
 	    ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
 		return cifs_push_posix_locks(cfile);
@@ -1421,7 +1419,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock)
 	netfid = cfile->netfid;
 	cinode = CIFS_I(file->f_path.dentry->d_inode);
 
-	if ((tcon->ses->capabilities & CAP_UNIX) &&
+	if (cap_unix(tcon->ses) &&
 	    (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
 	    ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
 		posix_lck = true;
@@ -2747,7 +2745,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
 	unsigned int current_read_size;
 	unsigned int rsize;
 	struct cifs_sb_info *cifs_sb;
-	struct cifs_tcon *pTcon;
+	struct cifs_tcon *tcon;
 	unsigned int xid;
 	char *current_offset;
 	struct cifsFileInfo *open_file;
@@ -2767,7 +2765,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
 		return rc;
 	}
 	open_file = file->private_data;
-	pTcon = tlink_tcon(open_file->tlink);
+	tcon = tlink_tcon(open_file->tlink);
 
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
 		pid = open_file->pid;
@@ -2781,11 +2779,12 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
 	     read_size > total_read;
 	     total_read += bytes_read, current_offset += bytes_read) {
 		current_read_size = min_t(uint, read_size - total_read, rsize);
-
-		/* For windows me and 9x we do not want to request more
-		than it negotiated since it will refuse the read then */
-		if ((pTcon->ses) &&
-			!(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
+		/*
+		 * For windows me and 9x we do not want to request more than it
+		 * negotiated since it will refuse the read then.
+		 */
+		if ((tcon->ses) && !(tcon->ses->capabilities |
+				tcon->ses->server->vals->cap_large_files)) {
 			current_read_size = min_t(uint, current_read_size,
 					CIFSMaxBufSize);
 		}
@@ -2798,7 +2797,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
 			}
 			io_parms.netfid = open_file->netfid;
 			io_parms.pid = pid;
-			io_parms.tcon = pTcon;
+			io_parms.tcon = tcon;
 			io_parms.offset = *poffset;
 			io_parms.length = current_read_size;
 			rc = CIFSSMBRead(xid, &io_parms, &bytes_read,
@@ -2812,7 +2811,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
 				return rc;
 			}
 		} else {
-			cifs_stats_bytes_read(pTcon, total_read);
+			cifs_stats_bytes_read(tcon, total_read);
 			*poffset += bytes_read;
 		}
 	}
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index def1006..35cb6a3 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1149,9 +1149,8 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
 		goto unlink_out;
 	}
 
-	if ((tcon->ses->capabilities & CAP_UNIX) &&
-		(CIFS_UNIX_POSIX_PATH_OPS_CAP &
-			le64_to_cpu(tcon->fsUnixInfo.Capability))) {
+	if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
+				le64_to_cpu(tcon->fsUnixInfo.Capability))) {
 		rc = CIFSPOSIXDelFile(xid, tcon, full_path,
 			SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls,
 			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -1226,7 +1225,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
 	unsigned int xid;
 	struct cifs_sb_info *cifs_sb;
 	struct tcon_link *tlink;
-	struct cifs_tcon *pTcon;
+	struct cifs_tcon *tcon;
 	char *full_path = NULL;
 	struct inode *newinode = NULL;
 	struct cifs_fattr fattr;
@@ -1237,7 +1236,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
 	tlink = cifs_sb_tlink(cifs_sb);
 	if (IS_ERR(tlink))
 		return PTR_ERR(tlink);
-	pTcon = tlink_tcon(tlink);
+	tcon = tlink_tcon(tlink);
 
 	xid = get_xid();
 
@@ -1247,9 +1246,8 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
 		goto mkdir_out;
 	}
 
-	if ((pTcon->ses->capabilities & CAP_UNIX) &&
-		(CIFS_UNIX_POSIX_PATH_OPS_CAP &
-			le64_to_cpu(pTcon->fsUnixInfo.Capability))) {
+	if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
+				le64_to_cpu(tcon->fsUnixInfo.Capability))) {
 		u32 oplock = 0;
 		FILE_UNIX_BASIC_INFO *pInfo =
 			kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
@@ -1259,7 +1257,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
 		}
 
 		mode &= ~current_umask();
-		rc = CIFSPOSIXCreate(xid, pTcon, SMB_O_DIRECTORY | SMB_O_CREAT,
+		rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT,
 				mode, NULL /* netfid */, pInfo, &oplock,
 				full_path, cifs_sb->local_nls,
 				cifs_sb->mnt_cifs_flags &
@@ -1303,14 +1301,14 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
 	}
 mkdir_retry_old:
 	/* BB add setting the equivalent of mode via CreateX w/ACLs */
-	rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls,
+	rc = CIFSSMBMkDir(xid, tcon, full_path, cifs_sb->local_nls,
 			  cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 	if (rc) {
 		cFYI(1, "cifs_mkdir returned 0x%x", rc);
 		d_drop(direntry);
 	} else {
 mkdir_get_info:
-		if (pTcon->unix_ext)
+		if (tcon->unix_ext)
 			rc = cifs_get_inode_info_unix(&newinode, full_path,
 						      inode->i_sb, xid);
 		else
@@ -1328,7 +1326,7 @@ mkdir_get_info:
 		if (inode->i_mode & S_ISGID)
 			mode |= S_ISGID;
 
-		if (pTcon->unix_ext) {
+		if (tcon->unix_ext) {
 			struct cifs_unix_set_info_args args = {
 				.mode	= mode,
 				.ctime	= NO_CHANGE_64,
@@ -1346,7 +1344,7 @@ mkdir_get_info:
 				args.uid = NO_CHANGE_64;
 				args.gid = NO_CHANGE_64;
 			}
-			CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args,
+			CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
 					       cifs_sb->local_nls,
 					       cifs_sb->mnt_cifs_flags &
 						CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -1361,7 +1359,7 @@ mkdir_get_info:
 				cifsInode = CIFS_I(newinode);
 				dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
 				pInfo.Attributes = cpu_to_le32(dosattrs);
-				tmprc = CIFSSMBSetPathInfo(xid, pTcon,
+				tmprc = CIFSSMBSetPathInfo(xid, tcon,
 						full_path, &pInfo,
 						cifs_sb->local_nls,
 						cifs_sb->mnt_cifs_flags &
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index 77d781a..d08b76c 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -495,8 +495,8 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
 	 * but there doesn't seem to be any harm in allowing the client to
 	 * read them.
 	 */
-	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
-	    && !(tcon->ses->capabilities & CAP_UNIX)) {
+	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) &&
+	    !cap_unix(tcon->ses)) {
 		rc = -EACCES;
 		goto out;
 	}
@@ -518,7 +518,7 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
 					cifs_sb->mnt_cifs_flags &
 						CIFS_MOUNT_MAP_SPECIAL_CHR);
 
-	if ((rc != 0) && (tcon->ses->capabilities & CAP_UNIX))
+	if ((rc != 0) && cap_unix(tcon->ses))
 		rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, &target_path,
 					     cifs_sb->local_nls);
 
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index da30d96..d87f826 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -228,7 +228,7 @@ static int initiate_cifs_search(const unsigned int xid, struct file *file)
 	struct cifsFileInfo *cifsFile;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
 	struct tcon_link *tlink = NULL;
-	struct cifs_tcon *pTcon;
+	struct cifs_tcon *tcon;
 
 	if (file->private_data == NULL) {
 		tlink = cifs_sb_tlink(cifs_sb);
@@ -242,10 +242,10 @@ static int initiate_cifs_search(const unsigned int xid, struct file *file)
 		}
 		file->private_data = cifsFile;
 		cifsFile->tlink = cifs_get_tlink(tlink);
-		pTcon = tlink_tcon(tlink);
+		tcon = tlink_tcon(tlink);
 	} else {
 		cifsFile = file->private_data;
-		pTcon = tlink_tcon(cifsFile->tlink);
+		tcon = tlink_tcon(cifsFile->tlink);
 	}
 
 	cifsFile->invalidHandle = true;
@@ -262,11 +262,11 @@ static int initiate_cifs_search(const unsigned int xid, struct file *file)
 ffirst_retry:
 	/* test for Unix extensions */
 	/* but now check for them on the share/mount not on the SMB session */
-/*	if (pTcon->ses->capabilities & CAP_UNIX) { */
-	if (pTcon->unix_ext)
+	/* if (cap_unix(tcon->ses) { */
+	if (tcon->unix_ext)
 		cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX;
-	else if ((pTcon->ses->capabilities &
-			(CAP_NT_SMBS | CAP_NT_FIND)) == 0) {
+	else if ((tcon->ses->capabilities &
+		  tcon->ses->server->vals->cap_nt_find) == 0) {
 		cifsFile->srch_inf.info_level = SMB_FIND_FILE_INFO_STANDARD;
 	} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
 		cifsFile->srch_inf.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO;
@@ -278,7 +278,7 @@ ffirst_retry:
 	if (backup_cred(cifs_sb))
 		search_flags |= CIFS_SEARCH_BACKUP_SEARCH;
 
-	rc = CIFSFindFirst(xid, pTcon, full_path, cifs_sb->local_nls,
+	rc = CIFSFindFirst(xid, tcon, full_path, cifs_sb->local_nls,
 		&cifsFile->netfid, search_flags, &cifsFile->srch_inf,
 		cifs_sb->mnt_cifs_flags &
 			CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 5817409..c40356d 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -632,4 +632,7 @@ struct smb_version_values smb1_values = {
 	.max_header_size = MAX_CIFS_HDR_SIZE,
 	.read_rsp_size = sizeof(READ_RSP),
 	.lock_cmd = cpu_to_le16(SMB_COM_LOCKING_ANDX),
+	.cap_unix = CAP_UNIX,
+	.cap_nt_find = CAP_NT_SMBS | CAP_NT_FIND,
+	.cap_large_files = CAP_LARGE_FILES,
 };
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 1018c5c..410cf92 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -325,4 +325,7 @@ struct smb_version_values smb21_values = {
 	.header_size = sizeof(struct smb2_hdr),
 	.max_header_size = MAX_SMB2_HDR_SIZE,
 	.lock_cmd = SMB2_LOCK,
+	.cap_unix = 0,
+	.cap_nt_find = SMB2_NT_FIND,
+	.cap_large_files = SMB2_LARGE_FILES,
 };
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index e4eb1d3..62b3f17 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -428,6 +428,8 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
 	/* BB Do we need to validate the SecurityMode? */
 	server->sec_mode = le16_to_cpu(rsp->SecurityMode);
 	server->capabilities = le32_to_cpu(rsp->Capabilities);
+	/* Internal types */
+	server->capabilities |= SMB2_NT_FIND | SMB2_LARGE_FILES;
 
 	security_blob = smb2_get_data_area_len(&blob_offset, &blob_length,
 					       &rsp->hdr);
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 59aae60..f37a1b4 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -167,6 +167,9 @@ struct smb2_negotiate_req {
 #define SMB2_GLOBAL_CAP_DFS		0x00000001
 #define SMB2_GLOBAL_CAP_LEASING		0x00000002 /* Resp only New to SMB2.1 */
 #define SMB2_GLOBAL_CAP_LARGE_MTU	0X00000004 /* Resp only New to SMB2.1 */
+/* Internal types */
+#define SMB2_NT_FIND			0x00100000
+#define SMB2_LARGE_FILES		0x00200000
 
 struct smb2_negotiate_rsp {
 	struct smb2_hdr hdr;
-- 
1.7.1

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

* [PATCH 02/45] CIFS: Simpliify cifs_mkdir call
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
  2012-07-18 15:48   ` [PATCH 01/45] CIFS: Make CAP_* checks protocol independent Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
       [not found]     ` <1342626541-29872-3-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
  2012-07-18 15:48   ` [PATCH 03/45] CIFS: Separate protocol specific part from mkdir Pavel Shilovsky
                     ` (43 subsequent siblings)
  45 siblings, 1 reply; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
 fs/cifs/cifsproto.h |    4 +-
 fs/cifs/cifssmb.c   |    8 +-
 fs/cifs/inode.c     |  295 ++++++++++++++++++++++++++++-----------------------
 3 files changed, 167 insertions(+), 140 deletions(-)

diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 5aadeec..51fbdf2 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -289,10 +289,10 @@ extern int CIFSSMBUnixSetFileInfo(const unsigned int xid,
 				  u16 fid, u32 pid_of_opener);
 
 extern int CIFSSMBUnixSetPathInfo(const unsigned int xid,
-				  struct cifs_tcon *tcon, char *file_name,
+				  struct cifs_tcon *tcon, const char *file_name,
 				  const struct cifs_unix_set_info_args *args,
 				  const struct nls_table *nls_codepage,
-				  int remap_special_chars);
+				  int remap);
 
 extern int CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon,
 			const char *newName,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 846b803..ed472aa 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -5945,7 +5945,7 @@ CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
 
 int
 CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
-		       char *fileName,
+		       const char *file_name,
 		       const struct cifs_unix_set_info_args *args,
 		       const struct nls_table *nls_codepage, int remap)
 {
@@ -5966,14 +5966,14 @@ setPermsRetry:
 
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
 		name_len =
-		    cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
+		    cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
 				       PATH_MAX, nls_codepage, remap);
 		name_len++;	/* trailing null */
 		name_len *= 2;
 	} else {	/* BB improve the check for buffer overruns BB */
-		name_len = strnlen(fileName, PATH_MAX);
+		name_len = strnlen(file_name, PATH_MAX);
 		name_len++;	/* trailing null */
-		strncpy(pSMB->FileName, fileName, name_len);
+		strncpy(pSMB->FileName, file_name, name_len);
 	}
 
 	params = 6 + name_len;
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 35cb6a3..e9ba1a1 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1219,16 +1219,165 @@ unlink_out:
 	return rc;
 }
 
+static int
+cifs_mkdir_qinfo(struct inode *inode, struct dentry *dentry, umode_t mode,
+		 const char *full_path, struct cifs_sb_info *cifs_sb,
+		 struct cifs_tcon *tcon, const unsigned int xid)
+{
+	int rc = 0;
+	struct inode *newinode = NULL;
+
+	if (tcon->unix_ext)
+		rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb,
+					      xid);
+	else
+		rc = cifs_get_inode_info(&newinode, full_path, NULL,
+					 inode->i_sb, xid, NULL);
+	if (rc)
+		return rc;
+
+	d_instantiate(dentry, newinode);
+	/*
+	 * setting nlink not necessary except in cases where we failed to get it
+	 * from the server or was set bogus
+	 */
+	if ((dentry->d_inode) && (dentry->d_inode->i_nlink < 2))
+		set_nlink(dentry->d_inode, 2);
+
+	mode &= ~current_umask();
+	/* must turn on setgid bit if parent dir has it */
+	if (inode->i_mode & S_ISGID)
+		mode |= S_ISGID;
+
+	if (tcon->unix_ext) {
+		struct cifs_unix_set_info_args args = {
+			.mode	= mode,
+			.ctime	= NO_CHANGE_64,
+			.atime	= NO_CHANGE_64,
+			.mtime	= NO_CHANGE_64,
+			.device	= 0,
+		};
+		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
+			args.uid = (__u64)current_fsuid();
+			if (inode->i_mode & S_ISGID)
+				args.gid = (__u64)inode->i_gid;
+			else
+				args.gid = (__u64)current_fsgid();
+		} else {
+			args.uid = NO_CHANGE_64;
+			args.gid = NO_CHANGE_64;
+		}
+		CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
+				       cifs_sb->local_nls,
+				       cifs_sb->mnt_cifs_flags &
+				       CIFS_MOUNT_MAP_SPECIAL_CHR);
+	} else {
+		if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
+		    (mode & S_IWUGO) == 0) {
+			FILE_BASIC_INFO info;
+			struct cifsInodeInfo *cifsInode;
+			u32 dosattrs;
+			int tmprc;
+
+			memset(&info, 0, sizeof(info));
+			cifsInode = CIFS_I(newinode);
+			dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
+			info.Attributes = cpu_to_le32(dosattrs);
+			tmprc = CIFSSMBSetPathInfo(xid, tcon, full_path, &info,
+						   cifs_sb->local_nls,
+						   cifs_sb->mnt_cifs_flags &
+						   CIFS_MOUNT_MAP_SPECIAL_CHR);
+			if (tmprc == 0)
+				cifsInode->cifsAttrs = dosattrs;
+		}
+		if (dentry->d_inode) {
+			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
+				dentry->d_inode->i_mode = (mode | S_IFDIR);
+
+			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
+				dentry->d_inode->i_uid = current_fsuid();
+				if (inode->i_mode & S_ISGID)
+					dentry->d_inode->i_gid = inode->i_gid;
+				else
+					dentry->d_inode->i_gid =
+								current_fsgid();
+			}
+		}
+	}
+	return rc;
+}
+
+static int
+cifs_posix_mkdir(struct inode *inode, struct dentry *dentry, umode_t mode,
+		 const char *full_path, struct cifs_sb_info *cifs_sb,
+		 struct cifs_tcon *tcon, const unsigned int xid)
+{
+	int rc = 0;
+	u32 oplock = 0;
+	FILE_UNIX_BASIC_INFO *info = NULL;
+	struct inode *newinode = NULL;
+	struct cifs_fattr fattr;
+
+	info = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
+	if (info == NULL) {
+		rc = -ENOMEM;
+		goto posix_mkdir_out;
+	}
+
+	mode &= ~current_umask();
+	rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT, mode,
+			     NULL /* netfid */, info, &oplock, full_path,
+			     cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
+			     CIFS_MOUNT_MAP_SPECIAL_CHR);
+	if (rc == -EOPNOTSUPP)
+		goto posix_mkdir_out;
+	else if (rc) {
+		cFYI(1, "posix mkdir returned 0x%x", rc);
+		d_drop(dentry);
+		goto posix_mkdir_out;
+	}
+
+	if (info->Type == cpu_to_le32(-1))
+		/* no return info, go query for it */
+		goto posix_mkdir_get_info;
+	/*
+	 * BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if
+	 * need to set uid/gid.
+	 */
+
+	cifs_unix_basic_to_fattr(&fattr, info, cifs_sb);
+	cifs_fill_uniqueid(inode->i_sb, &fattr);
+	newinode = cifs_iget(inode->i_sb, &fattr);
+	if (!newinode)
+		goto posix_mkdir_get_info;
+
+	d_instantiate(dentry, newinode);
+
+#ifdef CONFIG_CIFS_DEBUG2
+	cFYI(1, "instantiated dentry %p %s to inode %p", dentry,
+	     dentry->d_name.name, newinode);
+
+	if (newinode->i_nlink != 2)
+		cFYI(1, "unexpected number of links %d", newinode->i_nlink);
+#endif
+
+posix_mkdir_out:
+	kfree(info);
+	return rc;
+posix_mkdir_get_info:
+	rc = cifs_mkdir_qinfo(inode, dentry, mode, full_path, cifs_sb, tcon,
+			      xid);
+	goto posix_mkdir_out;
+}
+
 int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
 {
-	int rc = 0, tmprc;
+	int rc = 0;
 	unsigned int xid;
 	struct cifs_sb_info *cifs_sb;
 	struct tcon_link *tlink;
 	struct cifs_tcon *tcon;
-	char *full_path = NULL;
-	struct inode *newinode = NULL;
-	struct cifs_fattr fattr;
+	char *full_path;
 
 	cFYI(1, "In cifs_mkdir, mode = 0x%hx inode = 0x%p", mode, inode);
 
@@ -1248,145 +1397,23 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
 
 	if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
 				le64_to_cpu(tcon->fsUnixInfo.Capability))) {
-		u32 oplock = 0;
-		FILE_UNIX_BASIC_INFO *pInfo =
-			kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
-		if (pInfo == NULL) {
-			rc = -ENOMEM;
+		rc = cifs_posix_mkdir(inode, direntry, mode, full_path, cifs_sb,
+				      tcon, xid);
+		if (rc != -EOPNOTSUPP)
 			goto mkdir_out;
-		}
-
-		mode &= ~current_umask();
-		rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT,
-				mode, NULL /* netfid */, pInfo, &oplock,
-				full_path, cifs_sb->local_nls,
-				cifs_sb->mnt_cifs_flags &
-					CIFS_MOUNT_MAP_SPECIAL_CHR);
-		if (rc == -EOPNOTSUPP) {
-			kfree(pInfo);
-			goto mkdir_retry_old;
-		} else if (rc) {
-			cFYI(1, "posix mkdir returned 0x%x", rc);
-			d_drop(direntry);
-		} else {
-			if (pInfo->Type == cpu_to_le32(-1)) {
-				/* no return info, go query for it */
-				kfree(pInfo);
-				goto mkdir_get_info;
-			}
-/*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need
-	to set uid/gid */
-
-			cifs_unix_basic_to_fattr(&fattr, pInfo, cifs_sb);
-			cifs_fill_uniqueid(inode->i_sb, &fattr);
-			newinode = cifs_iget(inode->i_sb, &fattr);
-			if (!newinode) {
-				kfree(pInfo);
-				goto mkdir_get_info;
-			}
-
-			d_instantiate(direntry, newinode);
-
-#ifdef CONFIG_CIFS_DEBUG2
-			cFYI(1, "instantiated dentry %p %s to inode %p",
-				direntry, direntry->d_name.name, newinode);
-
-			if (newinode->i_nlink != 2)
-				cFYI(1, "unexpected number of links %d",
-					newinode->i_nlink);
-#endif
-		}
-		kfree(pInfo);
-		goto mkdir_out;
 	}
-mkdir_retry_old:
+
 	/* BB add setting the equivalent of mode via CreateX w/ACLs */
 	rc = CIFSSMBMkDir(xid, tcon, full_path, cifs_sb->local_nls,
 			  cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 	if (rc) {
 		cFYI(1, "cifs_mkdir returned 0x%x", rc);
 		d_drop(direntry);
-	} else {
-mkdir_get_info:
-		if (tcon->unix_ext)
-			rc = cifs_get_inode_info_unix(&newinode, full_path,
-						      inode->i_sb, xid);
-		else
-			rc = cifs_get_inode_info(&newinode, full_path, NULL,
-						 inode->i_sb, xid, NULL);
-
-		d_instantiate(direntry, newinode);
-		 /* setting nlink not necessary except in cases where we
-		  * failed to get it from the server or was set bogus */
-		if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2))
-			set_nlink(direntry->d_inode, 2);
-
-		mode &= ~current_umask();
-		/* must turn on setgid bit if parent dir has it */
-		if (inode->i_mode & S_ISGID)
-			mode |= S_ISGID;
-
-		if (tcon->unix_ext) {
-			struct cifs_unix_set_info_args args = {
-				.mode	= mode,
-				.ctime	= NO_CHANGE_64,
-				.atime	= NO_CHANGE_64,
-				.mtime	= NO_CHANGE_64,
-				.device	= 0,
-			};
-			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
-				args.uid = (__u64)current_fsuid();
-				if (inode->i_mode & S_ISGID)
-					args.gid = (__u64)inode->i_gid;
-				else
-					args.gid = (__u64)current_fsgid();
-			} else {
-				args.uid = NO_CHANGE_64;
-				args.gid = NO_CHANGE_64;
-			}
-			CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
-					       cifs_sb->local_nls,
-					       cifs_sb->mnt_cifs_flags &
-						CIFS_MOUNT_MAP_SPECIAL_CHR);
-		} else {
-			if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
-			    (mode & S_IWUGO) == 0) {
-				FILE_BASIC_INFO pInfo;
-				struct cifsInodeInfo *cifsInode;
-				u32 dosattrs;
-
-				memset(&pInfo, 0, sizeof(pInfo));
-				cifsInode = CIFS_I(newinode);
-				dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
-				pInfo.Attributes = cpu_to_le32(dosattrs);
-				tmprc = CIFSSMBSetPathInfo(xid, tcon,
-						full_path, &pInfo,
-						cifs_sb->local_nls,
-						cifs_sb->mnt_cifs_flags &
-						CIFS_MOUNT_MAP_SPECIAL_CHR);
-				if (tmprc == 0)
-					cifsInode->cifsAttrs = dosattrs;
-			}
-			if (direntry->d_inode) {
-				if (cifs_sb->mnt_cifs_flags &
-				     CIFS_MOUNT_DYNPERM)
-					direntry->d_inode->i_mode =
-						(mode | S_IFDIR);
-
-				if (cifs_sb->mnt_cifs_flags &
-				     CIFS_MOUNT_SET_UID) {
-					direntry->d_inode->i_uid =
-						current_fsuid();
-					if (inode->i_mode & S_ISGID)
-						direntry->d_inode->i_gid =
-							inode->i_gid;
-					else
-						direntry->d_inode->i_gid =
-							current_fsgid();
-				}
-			}
-		}
+		goto mkdir_out;
 	}
+
+	rc = cifs_mkdir_qinfo(inode, direntry, mode, full_path, cifs_sb, tcon,
+			      xid);
 mkdir_out:
 	/*
 	 * Force revalidate to get parent dir info when needed since cached
-- 
1.7.1

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

* [PATCH 03/45] CIFS: Separate protocol specific part from mkdir
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
  2012-07-18 15:48   ` [PATCH 01/45] CIFS: Make CAP_* checks protocol independent Pavel Shilovsky
  2012-07-18 15:48   ` [PATCH 02/45] CIFS: Simpliify cifs_mkdir call Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
       [not found]     ` <1342626541-29872-4-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
  2012-07-18 15:48   ` [PATCH 04/45] CIFS: Add SMB2 support for mkdir operation Pavel Shilovsky
                     ` (42 subsequent siblings)
  45 siblings, 1 reply; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA; +Cc: Pavel Shilovsky

From: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>

Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
 fs/cifs/cifsglob.h  |    7 +++++++
 fs/cifs/cifsproto.h |    4 +---
 fs/cifs/cifssmb.c   |    8 +++++---
 fs/cifs/inode.c     |   32 +++++++++++++-------------------
 fs/cifs/smb1ops.c   |   23 +++++++++++++++++++++++
 5 files changed, 49 insertions(+), 25 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 5695693..1ae7531 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -246,6 +246,13 @@ struct smb_version_operations {
 	bool (*can_echo)(struct TCP_Server_Info *);
 	/* send echo request */
 	int (*echo)(struct TCP_Server_Info *);
+	/* create directory */
+	int (*mkdir)(const unsigned int, struct cifs_tcon *, const char *,
+		     struct cifs_sb_info *);
+	/* set info on created directory */
+	void (*mkdir_setinfo)(struct inode *, const char *,
+			      struct cifs_sb_info *, struct cifs_tcon *,
+			      const unsigned int);
 };
 
 struct smb_version_values {
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 51fbdf2..7e02362 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -295,9 +295,7 @@ extern int CIFSSMBUnixSetPathInfo(const unsigned int xid,
 				  int remap);
 
 extern int CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon,
-			const char *newName,
-			const struct nls_table *nls_codepage,
-			int remap_special_chars);
+			const char *name, struct cifs_sb_info *cifs_sb);
 extern int CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon,
 			const char *name, const struct nls_table *nls_codepage,
 			int remap_special_chars);
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index ed472aa..d49eedf 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -992,14 +992,15 @@ RmDirRetry:
 }
 
 int
-CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon,
-	     const char *name, const struct nls_table *nls_codepage, int remap)
+CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
+	     struct cifs_sb_info *cifs_sb)
 {
 	int rc = 0;
 	CREATE_DIRECTORY_REQ *pSMB = NULL;
 	CREATE_DIRECTORY_RSP *pSMBr = NULL;
 	int bytes_returned;
 	int name_len;
+	int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
 
 	cFYI(1, "In CIFSSMBMkDir");
 MkDirRetry:
@@ -1010,7 +1011,8 @@ MkDirRetry:
 
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
 		name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
-					      PATH_MAX, nls_codepage, remap);
+					      PATH_MAX, cifs_sb->local_nls,
+					      remap);
 		name_len++;	/* trailing null */
 		name_len *= 2;
 	} else {		/* BB improve check for buffer overruns BB */
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index e9ba1a1..d7e74b1 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1272,24 +1272,11 @@ cifs_mkdir_qinfo(struct inode *inode, struct dentry *dentry, umode_t mode,
 				       cifs_sb->mnt_cifs_flags &
 				       CIFS_MOUNT_MAP_SPECIAL_CHR);
 	} else {
+		struct TCP_Server_Info *server = tcon->ses->server;
 		if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
-		    (mode & S_IWUGO) == 0) {
-			FILE_BASIC_INFO info;
-			struct cifsInodeInfo *cifsInode;
-			u32 dosattrs;
-			int tmprc;
-
-			memset(&info, 0, sizeof(info));
-			cifsInode = CIFS_I(newinode);
-			dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
-			info.Attributes = cpu_to_le32(dosattrs);
-			tmprc = CIFSSMBSetPathInfo(xid, tcon, full_path, &info,
-						   cifs_sb->local_nls,
-						   cifs_sb->mnt_cifs_flags &
-						   CIFS_MOUNT_MAP_SPECIAL_CHR);
-			if (tmprc == 0)
-				cifsInode->cifsAttrs = dosattrs;
-		}
+		    (mode & S_IWUGO) == 0 && server->ops->mkdir_setinfo)
+			server->ops->mkdir_setinfo(newinode, full_path, cifs_sb,
+						   tcon, xid);
 		if (dentry->d_inode) {
 			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
 				dentry->d_inode->i_mode = (mode | S_IFDIR);
@@ -1377,6 +1364,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
 	struct cifs_sb_info *cifs_sb;
 	struct tcon_link *tlink;
 	struct cifs_tcon *tcon;
+	struct TCP_Server_Info *server;
 	char *full_path;
 
 	cFYI(1, "In cifs_mkdir, mode = 0x%hx inode = 0x%p", mode, inode);
@@ -1403,9 +1391,15 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
 			goto mkdir_out;
 	}
 
+	server = tcon->ses->server;
+
+	if (!server->ops->mkdir) {
+		rc = -ENOSYS;
+		goto mkdir_out;
+	}
+
 	/* BB add setting the equivalent of mode via CreateX w/ACLs */
-	rc = CIFSSMBMkDir(xid, tcon, full_path, cifs_sb->local_nls,
-			  cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+	rc = server->ops->mkdir(xid, tcon, full_path, cifs_sb);
 	if (rc) {
 		cFYI(1, "cifs_mkdir returned 0x%x", rc);
 		d_drop(direntry);
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index c40356d..861e2df 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -586,6 +586,27 @@ cifs_print_stats(struct seq_file *m, struct cifs_tcon *tcon)
 #endif
 }
 
+static void
+cifs_mkdir_setinfo(struct inode *inode, const char *full_path,
+		   struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon,
+		   const unsigned int xid)
+{
+	FILE_BASIC_INFO info;
+	struct cifsInodeInfo *cifsInode;
+	u32 dosattrs;
+	int rc;
+
+	memset(&info, 0, sizeof(info));
+	cifsInode = CIFS_I(inode);
+	dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
+	info.Attributes = cpu_to_le32(dosattrs);
+	rc = CIFSSMBSetPathInfo(xid, tcon, full_path, &info, cifs_sb->local_nls,
+				cifs_sb->mnt_cifs_flags &
+						CIFS_MOUNT_MAP_SPECIAL_CHR);
+	if (rc == 0)
+		cifsInode->cifsAttrs = dosattrs;
+}
+
 struct smb_version_operations smb1_operations = {
 	.send_cancel = send_nt_cancel,
 	.compare_fids = cifs_compare_fids,
@@ -620,6 +641,8 @@ struct smb_version_operations smb1_operations = {
 	.get_srv_inum = cifs_get_srv_inum,
 	.build_path_to_root = cifs_build_path_to_root,
 	.echo = CIFSSMBEcho,
+	.mkdir = CIFSSMBMkDir,
+	.mkdir_setinfo = cifs_mkdir_setinfo,
 };
 
 struct smb_version_values smb1_values = {
-- 
1.7.1

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

* [PATCH 04/45] CIFS: Add SMB2 support for mkdir operation
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (2 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 03/45] CIFS: Separate protocol specific part from mkdir Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
       [not found]     ` <1342626541-29872-5-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
  2012-07-18 15:48   ` [PATCH 05/45] CIFS: Move rmdir code to ops struct Pavel Shilovsky
                     ` (41 subsequent siblings)
  45 siblings, 1 reply; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA; +Cc: Pavel Shilovsky

From: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

Signed-off-by: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 fs/cifs/smb2inode.c |   30 ++++++++++++++++++++++++++++++
 fs/cifs/smb2ops.c   |    2 ++
 fs/cifs/smb2proto.h |    6 ++++++
 3 files changed, 38 insertions(+), 0 deletions(-)

diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index 1ba5c40..e129527 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -122,3 +122,33 @@ out:
 	kfree(smb2_data);
 	return rc;
 }
+
+int
+smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
+	   struct cifs_sb_info *cifs_sb)
+{
+	return smb2_open_op_close(xid, tcon, cifs_sb, name,
+				  FILE_WRITE_ATTRIBUTES, FILE_CREATE, 0,
+				  CREATE_NOT_FILE, NULL, SMB2_OP_MKDIR);
+}
+
+void
+smb2_mkdir_setinfo(struct inode *inode, const char *name,
+		   struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon,
+		   const unsigned int xid)
+{
+	FILE_BASIC_INFO data;
+	struct cifsInodeInfo *cifs_i;
+	u32 dosattrs;
+	int tmprc;
+
+	memset(&data, 0, sizeof(data));
+	cifs_i = CIFS_I(inode);
+	dosattrs = cifs_i->cifsAttrs | ATTR_READONLY;
+	data.Attributes = cpu_to_le32(dosattrs);
+	tmprc = smb2_open_op_close(xid, tcon, cifs_sb, name,
+				   FILE_WRITE_ATTRIBUTES, FILE_CREATE, 0,
+				   CREATE_NOT_FILE, &data, SMB2_OP_SET_INFO);
+	if (tmprc == 0)
+		cifs_i->cifsAttrs = dosattrs;
+}
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 410cf92..cc74871 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -318,6 +318,8 @@ struct smb_version_operations smb21_operations = {
 	.query_path_info = smb2_query_path_info,
 	.get_srv_inum = smb2_get_srv_inum,
 	.build_path_to_root = smb2_build_path_to_root,
+	.mkdir = smb2_mkdir,
+	.mkdir_setinfo = smb2_mkdir_setinfo,
 };
 
 struct smb_version_values smb21_values = {
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 902bbe2..f992508 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -52,6 +52,12 @@ extern int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
 				struct cifs_sb_info *cifs_sb,
 				const char *full_path, FILE_ALL_INFO *data,
 				bool *adjust_tz);
+extern int smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon,
+		      const char *name, struct cifs_sb_info *cifs_sb);
+extern void smb2_mkdir_setinfo(struct inode *inode, const char *full_path,
+			       struct cifs_sb_info *cifs_sb,
+			       struct cifs_tcon *tcon, const unsigned int xid);
+
 /*
  * SMB2 Worker functions - most of protocol specific implementation details
  * are contained within these calls.
-- 
1.7.1

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

* [PATCH 05/45] CIFS: Move rmdir code to ops struct
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (3 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 04/45] CIFS: Add SMB2 support for mkdir operation Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
       [not found]     ` <1342626541-29872-6-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
  2012-07-18 15:48   ` [PATCH 06/45] CIFS: Add SMB2 support for rmdir Pavel Shilovsky
                     ` (40 subsequent siblings)
  45 siblings, 1 reply; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/cifsglob.h  |    3 +++
 fs/cifs/cifsproto.h |    3 +--
 fs/cifs/cifssmb.c   |   15 ++++++++-------
 fs/cifs/inode.c     |   15 +++++++++++----
 fs/cifs/smb1ops.c   |    1 +
 5 files changed, 24 insertions(+), 13 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 1ae7531..a5b4e82 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -253,6 +253,9 @@ struct smb_version_operations {
 	void (*mkdir_setinfo)(struct inode *, const char *,
 			      struct cifs_sb_info *, struct cifs_tcon *,
 			      const unsigned int);
+	/* remove directory */
+	int (*rmdir)(const unsigned int, struct cifs_tcon *, const char *,
+		     struct cifs_sb_info *);
 };
 
 struct smb_version_values {
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 7e02362..43784ee 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -297,8 +297,7 @@ extern int CIFSSMBUnixSetPathInfo(const unsigned int xid,
 extern int CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon,
 			const char *name, struct cifs_sb_info *cifs_sb);
 extern int CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon,
-			const char *name, const struct nls_table *nls_codepage,
-			int remap_special_chars);
+			const char *name, struct cifs_sb_info *cifs_sb);
 extern int CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
 			const char *name, __u16 type,
 			const struct nls_table *nls_codepage,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index d49eedf..9fb21cd 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -948,15 +948,15 @@ DelFileRetry:
 }
 
 int
-CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon,
-	     const char *dirName, const struct nls_table *nls_codepage,
-	     int remap)
+CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
+	     struct cifs_sb_info *cifs_sb)
 {
 	DELETE_DIRECTORY_REQ *pSMB = NULL;
 	DELETE_DIRECTORY_RSP *pSMBr = NULL;
 	int rc = 0;
 	int bytes_returned;
 	int name_len;
+	int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
 
 	cFYI(1, "In CIFSSMBRmDir");
 RmDirRetry:
@@ -966,14 +966,15 @@ RmDirRetry:
 		return rc;
 
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
-		name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, dirName,
-					      PATH_MAX, nls_codepage, remap);
+		name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
+					      PATH_MAX, cifs_sb->local_nls,
+					      remap);
 		name_len++;	/* trailing null */
 		name_len *= 2;
 	} else {		/* BB improve check for buffer overruns BB */
-		name_len = strnlen(dirName, PATH_MAX);
+		name_len = strnlen(name, PATH_MAX);
 		name_len++;	/* trailing null */
-		strncpy(pSMB->DirName, dirName, name_len);
+		strncpy(pSMB->DirName, name, name_len);
 	}
 
 	pSMB->BufferFormat = 0x04;
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index d7e74b1..7354877 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1426,7 +1426,8 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
 	unsigned int xid;
 	struct cifs_sb_info *cifs_sb;
 	struct tcon_link *tlink;
-	struct cifs_tcon *pTcon;
+	struct cifs_tcon *tcon;
+	struct TCP_Server_Info *server;
 	char *full_path = NULL;
 	struct cifsInodeInfo *cifsInode;
 
@@ -1446,10 +1447,16 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
 		rc = PTR_ERR(tlink);
 		goto rmdir_exit;
 	}
-	pTcon = tlink_tcon(tlink);
+	tcon = tlink_tcon(tlink);
+	server = tcon->ses->server;
+
+	if (!server->ops->rmdir) {
+		rc = -ENOSYS;
+		cifs_put_tlink(tlink);
+		goto rmdir_exit;
+	}
 
-	rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls,
-			  cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+	rc = server->ops->rmdir(xid, tcon, full_path, cifs_sb);
 	cifs_put_tlink(tlink);
 
 	if (!rc) {
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 861e2df..3129ac7 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -643,6 +643,7 @@ struct smb_version_operations smb1_operations = {
 	.echo = CIFSSMBEcho,
 	.mkdir = CIFSSMBMkDir,
 	.mkdir_setinfo = cifs_mkdir_setinfo,
+	.rmdir = CIFSSMBRmDir,
 };
 
 struct smb_version_values smb1_values = {
-- 
1.7.1

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

* [PATCH 06/45] CIFS: Add SMB2 support for rmdir
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (4 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 05/45] CIFS: Move rmdir code to ops struct Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
       [not found]     ` <1342626541-29872-7-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
  2012-07-18 15:48   ` [PATCH 07/45] CIFS: Protect i_nlink from being negative Pavel Shilovsky
                     ` (39 subsequent siblings)
  45 siblings, 1 reply; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/smb2inode.c |    9 +++++++++
 fs/cifs/smb2ops.c   |    1 +
 fs/cifs/smb2proto.h |    2 ++
 3 files changed, 12 insertions(+), 0 deletions(-)

diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index e129527..2aa5cb0 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -152,3 +152,12 @@ smb2_mkdir_setinfo(struct inode *inode, const char *name,
 	if (tmprc == 0)
 		cifs_i->cifsAttrs = dosattrs;
 }
+
+int
+smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
+	   struct cifs_sb_info *cifs_sb)
+{
+	return smb2_open_op_close(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
+				  0, CREATE_NOT_FILE | CREATE_DELETE_ON_CLOSE,
+				  NULL, SMB2_OP_DELETE);
+}
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index cc74871..826209b 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -320,6 +320,7 @@ struct smb_version_operations smb21_operations = {
 	.build_path_to_root = smb2_build_path_to_root,
 	.mkdir = smb2_mkdir,
 	.mkdir_setinfo = smb2_mkdir_setinfo,
+	.rmdir = smb2_rmdir,
 };
 
 struct smb_version_values smb21_values = {
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index f992508..bfaa7b1 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -57,6 +57,8 @@ extern int smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon,
 extern void smb2_mkdir_setinfo(struct inode *inode, const char *full_path,
 			       struct cifs_sb_info *cifs_sb,
 			       struct cifs_tcon *tcon, const unsigned int xid);
+extern int smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon,
+		      const char *name, struct cifs_sb_info *cifs_sb);
 
 /*
  * SMB2 Worker functions - most of protocol specific implementation details
-- 
1.7.1

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

* [PATCH 07/45] CIFS: Protect i_nlink from being negative
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (5 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 06/45] CIFS: Add SMB2 support for rmdir Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
       [not found]     ` <1342626541-29872-8-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
  2012-07-18 15:48   ` [PATCH 08/45] CIFS: Move unlink code to ops struct Pavel Shilovsky
                     ` (38 subsequent siblings)
  45 siblings, 1 reply; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

that can cause warning messages.

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/inode.c |   13 +++++++++++--
 1 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 7354877..88afb1a 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1110,6 +1110,15 @@ undo_setattr:
 	goto out_close;
 }
 
+/* copied from fs/nfs/dir.c with small changes */
+static void
+cifs_drop_nlink(struct inode *inode)
+{
+	spin_lock(&inode->i_lock);
+	if (inode->i_nlink > 0)
+		drop_nlink(inode);
+	spin_unlock(&inode->i_lock);
+}
 
 /*
  * If dentry->d_inode is null (usually meaning the cached dentry
@@ -1166,13 +1175,13 @@ retry_std_delete:
 psx_del_no_retry:
 	if (!rc) {
 		if (inode)
-			drop_nlink(inode);
+			cifs_drop_nlink(inode);
 	} else if (rc == -ENOENT) {
 		d_drop(dentry);
 	} else if (rc == -ETXTBSY) {
 		rc = cifs_rename_pending_delete(full_path, dentry, xid);
 		if (rc == 0)
-			drop_nlink(inode);
+			cifs_drop_nlink(inode);
 	} else if ((rc == -EACCES) && (dosattr == 0) && inode) {
 		attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
 		if (attrs == NULL) {
-- 
1.7.1

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

* [PATCH 08/45] CIFS: Move unlink code to ops struct
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (6 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 07/45] CIFS: Protect i_nlink from being negative Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
       [not found]     ` <1342626541-29872-9-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
  2012-07-18 15:48   ` [PATCH 09/45] CIFS: Add SMB2 support for unlink Pavel Shilovsky
                     ` (37 subsequent siblings)
  45 siblings, 1 reply; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/cifsglob.h  |    6 ++++++
 fs/cifs/cifsproto.h |    9 ++++++---
 fs/cifs/cifssmb.c   |   16 ++++++++--------
 fs/cifs/inode.c     |   32 +++++++++++++++++++++-----------
 fs/cifs/smb1ops.c   |    2 ++
 5 files changed, 43 insertions(+), 22 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index a5b4e82..bd53d97 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -256,6 +256,12 @@ struct smb_version_operations {
 	/* remove directory */
 	int (*rmdir)(const unsigned int, struct cifs_tcon *, const char *,
 		     struct cifs_sb_info *);
+	/* unlink file */
+	int (*unlink)(const unsigned int, struct cifs_tcon *, const char *,
+		      struct cifs_sb_info *);
+	/* open, rename and delete file */
+	int (*rename_pending_delete)(const char *, struct dentry *,
+				     const unsigned int);
 };
 
 struct smb_version_values {
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 43784ee..e9349af 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -144,6 +144,11 @@ extern int cifs_get_file_info_unix(struct file *filp);
 extern int cifs_get_inode_info_unix(struct inode **pinode,
 			const unsigned char *search_path,
 			struct super_block *sb, unsigned int xid);
+extern int cifs_set_file_info(struct inode *inode, struct iattr *attrs,
+			      unsigned int xid, char *full_path, __u32 dosattr);
+extern int cifs_rename_pending_delete(const char *full_path,
+				      struct dentry *dentry,
+				      const unsigned int xid);
 extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb,
 			      struct cifs_fattr *fattr, struct inode *inode,
 			      const char *path, const __u16 *pfid);
@@ -303,9 +308,7 @@ extern int CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
 			const struct nls_table *nls_codepage,
 			int remap_special_chars);
 extern int CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon,
-			const char *name,
-			const struct nls_table *nls_codepage,
-			int remap_special_chars);
+			  const char *name, struct cifs_sb_info *cifs_sb);
 extern int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
 			const char *fromName, const char *toName,
 			const struct nls_table *nls_codepage,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 9fb21cd..395f3e2 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -902,15 +902,15 @@ PsxDelete:
 }
 
 int
-CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon,
-	       const char *fileName, const struct nls_table *nls_codepage,
-	       int remap)
+CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
+	       struct cifs_sb_info *cifs_sb)
 {
 	DELETE_FILE_REQ *pSMB = NULL;
 	DELETE_FILE_RSP *pSMBr = NULL;
 	int rc = 0;
 	int bytes_returned;
 	int name_len;
+	int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
 
 DelFileRetry:
 	rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
@@ -919,15 +919,15 @@ DelFileRetry:
 		return rc;
 
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
-		name_len =
-		    cifsConvertToUTF16((__le16 *) pSMB->fileName, fileName,
-				       PATH_MAX, nls_codepage, remap);
+		name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
+					      PATH_MAX, cifs_sb->local_nls,
+					      remap);
 		name_len++;	/* trailing null */
 		name_len *= 2;
 	} else {		/* BB improve check for buffer overruns BB */
-		name_len = strnlen(fileName, PATH_MAX);
+		name_len = strnlen(name, PATH_MAX);
 		name_len++;	/* trailing null */
-		strncpy(pSMB->fileName, fileName, name_len);
+		strncpy(pSMB->fileName, name, name_len);
 	}
 	pSMB->SearchAttributes =
 	    cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 88afb1a..9685eb1 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -878,9 +878,9 @@ out:
 	return inode;
 }
 
-static int
+int
 cifs_set_file_info(struct inode *inode, struct iattr *attrs, unsigned int xid,
-		    char *full_path, __u32 dosattr)
+		   char *full_path, __u32 dosattr)
 {
 	int rc;
 	int oplock = 0;
@@ -995,13 +995,13 @@ out:
 }
 
 /*
- * open the given file (if it isn't already), set the DELETE_ON_CLOSE bit
+ * Open the given file (if it isn't already), set the DELETE_ON_CLOSE bit
  * and rename it to a random name that hopefully won't conflict with
  * anything else.
  */
-static int
-cifs_rename_pending_delete(char *full_path, struct dentry *dentry,
-			   unsigned int xid)
+int
+cifs_rename_pending_delete(const char *full_path, struct dentry *dentry,
+			   const unsigned int xid)
 {
 	int oplock = 0;
 	int rc;
@@ -1138,6 +1138,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
 	struct tcon_link *tlink;
 	struct cifs_tcon *tcon;
+	struct TCP_Server_Info *server;
 	struct iattr *attrs = NULL;
 	__u32 dosattr = 0, origattr = 0;
 
@@ -1147,6 +1148,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
 	if (IS_ERR(tlink))
 		return PTR_ERR(tlink);
 	tcon = tlink_tcon(tlink);
+	server = tcon->ses->server;
 
 	xid = get_xid();
 
@@ -1169,8 +1171,12 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
 	}
 
 retry_std_delete:
-	rc = CIFSSMBDelFile(xid, tcon, full_path, cifs_sb->local_nls,
-			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+	if (!server->ops->unlink) {
+		rc = -ENOSYS;
+		goto psx_del_no_retry;
+	}
+
+	rc = server->ops->unlink(xid, tcon, full_path, cifs_sb);
 
 psx_del_no_retry:
 	if (!rc) {
@@ -1179,9 +1185,13 @@ psx_del_no_retry:
 	} else if (rc == -ENOENT) {
 		d_drop(dentry);
 	} else if (rc == -ETXTBSY) {
-		rc = cifs_rename_pending_delete(full_path, dentry, xid);
-		if (rc == 0)
-			cifs_drop_nlink(inode);
+		if (server->ops->rename_pending_delete) {
+			rc = server->ops->rename_pending_delete(full_path,
+								dentry, xid);
+			if (rc == 0)
+				cifs_drop_nlink(inode);
+		} else
+			rc = -ENOSYS;
 	} else if ((rc == -EACCES) && (dosattr == 0) && inode) {
 		attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
 		if (attrs == NULL) {
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 3129ac7..725fa61 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -644,6 +644,8 @@ struct smb_version_operations smb1_operations = {
 	.mkdir = CIFSSMBMkDir,
 	.mkdir_setinfo = cifs_mkdir_setinfo,
 	.rmdir = CIFSSMBRmDir,
+	.unlink = CIFSSMBDelFile,
+	.rename_pending_delete = cifs_rename_pending_delete,
 };
 
 struct smb_version_values smb1_values = {
-- 
1.7.1

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

* [PATCH 09/45] CIFS: Add SMB2 support for unlink
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (7 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 08/45] CIFS: Move unlink code to ops struct Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
       [not found]     ` <1342626541-29872-10-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
  2012-07-18 15:48   ` [PATCH 10/45] CIFS: Replace netfid with cifs_fid struct in cifsFileInfo Pavel Shilovsky
                     ` (36 subsequent siblings)
  45 siblings, 1 reply; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/smb2inode.c |    9 +++++++++
 fs/cifs/smb2ops.c   |    1 +
 fs/cifs/smb2proto.h |    2 ++
 3 files changed, 12 insertions(+), 0 deletions(-)

diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index 2aa5cb0..02a9bda 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -161,3 +161,12 @@ smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
 				  0, CREATE_NOT_FILE | CREATE_DELETE_ON_CLOSE,
 				  NULL, SMB2_OP_DELETE);
 }
+
+int
+smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
+	    struct cifs_sb_info *cifs_sb)
+{
+	return smb2_open_op_close(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
+				  0, CREATE_DELETE_ON_CLOSE, NULL,
+				  SMB2_OP_DELETE);
+}
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 826209b..bf9b318 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -321,6 +321,7 @@ struct smb_version_operations smb21_operations = {
 	.mkdir = smb2_mkdir,
 	.mkdir_setinfo = smb2_mkdir_setinfo,
 	.rmdir = smb2_rmdir,
+	.unlink = smb2_unlink,
 };
 
 struct smb_version_values smb21_values = {
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index bfaa7b1..f4ac727 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -59,6 +59,8 @@ extern void smb2_mkdir_setinfo(struct inode *inode, const char *full_path,
 			       struct cifs_tcon *tcon, const unsigned int xid);
 extern int smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon,
 		      const char *name, struct cifs_sb_info *cifs_sb);
+extern int smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon,
+		       const char *name, struct cifs_sb_info *cifs_sb);
 
 /*
  * SMB2 Worker functions - most of protocol specific implementation details
-- 
1.7.1

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

* [PATCH 10/45] CIFS: Replace netfid with cifs_fid struct in cifsFileInfo
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (8 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 09/45] CIFS: Add SMB2 support for unlink Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
       [not found]     ` <1342626541-29872-11-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
  2012-07-18 15:48   ` [PATCH 11/45] CIFS: Move open code to ops struct Pavel Shilovsky
                     ` (35 subsequent siblings)
  45 siblings, 1 reply; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

This is help us to extend the code for future protocols that can use
another fid mechanism (as SMB2 that has it divided into two parts:
persistent and violatile).

Also rename variables and refactor the code around the changes.

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/cifsacl.c  |    2 +-
 fs/cifs/cifsglob.h |    6 ++-
 fs/cifs/cifssmb.c  |    4 +-
 fs/cifs/file.c     |  116 ++++++++++++++++++++++++++--------------------------
 fs/cifs/inode.c    |   10 ++--
 fs/cifs/ioctl.c    |   13 ++++--
 fs/cifs/misc.c     |    2 +-
 fs/cifs/readdir.c  |   10 ++--
 fs/cifs/smb1ops.c  |    2 +-
 9 files changed, 87 insertions(+), 78 deletions(-)

diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
index f8c8464..d98a7c3 100644
--- a/fs/cifs/cifsacl.c
+++ b/fs/cifs/cifsacl.c
@@ -1222,7 +1222,7 @@ struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
 	if (!open_file)
 		return get_cifs_acl_by_path(cifs_sb, path, pacllen);
 
-	pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->netfid, pacllen);
+	pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->fid.netfid, pacllen);
 	cifsFileInfo_put(open_file);
 	return pntsd;
 }
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index bd53d97..01ee8d2 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -746,6 +746,10 @@ struct cifs_search_info {
 	bool smallBuf:1; /* so we know which buf_release function to call */
 };
 
+struct cifs_fid {
+	__u16 netfid;
+};
+
 struct cifsFileInfo {
 	struct list_head tlist;	/* pointer to next fid owned by tcon */
 	struct list_head flist;	/* next fid (file instance) for this inode */
@@ -755,7 +759,7 @@ struct cifsFileInfo {
 				 */
 	unsigned int uid;	/* allows finding which FileInfo structure */
 	__u32 pid;		/* process id who opened file */
-	__u16 netfid;		/* file id from remote */
+	struct cifs_fid fid;	/* file id from remote */
 	/* BB add lock scope info here if needed */ ;
 	/* lock scope id (0 if none) */
 	struct dentry *dentry;
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 395f3e2..2936875 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -1627,7 +1627,7 @@ cifs_async_readv(struct cifs_readdata *rdata)
 	smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
 
 	smb->AndXCommand = 0xFF;	/* none */
-	smb->Fid = rdata->cfile->netfid;
+	smb->Fid = rdata->cfile->fid.netfid;
 	smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
 	if (wct == 12)
 		smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
@@ -2079,7 +2079,7 @@ cifs_async_writev(struct cifs_writedata *wdata)
 	smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
 
 	smb->AndXCommand = 0xFF;	/* none */
-	smb->Fid = wdata->cfile->netfid;
+	smb->Fid = wdata->cfile->fid.netfid;
 	smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
 	if (wct == 14)
 		smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 1712794..f542574 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -247,39 +247,39 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file,
 {
 	struct dentry *dentry = file->f_path.dentry;
 	struct inode *inode = dentry->d_inode;
-	struct cifsInodeInfo *pCifsInode = CIFS_I(inode);
-	struct cifsFileInfo *pCifsFile;
-
-	pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
-	if (pCifsFile == NULL)
-		return pCifsFile;
-
-	pCifsFile->count = 1;
-	pCifsFile->netfid = fileHandle;
-	pCifsFile->pid = current->tgid;
-	pCifsFile->uid = current_fsuid();
-	pCifsFile->dentry = dget(dentry);
-	pCifsFile->f_flags = file->f_flags;
-	pCifsFile->invalidHandle = false;
-	pCifsFile->tlink = cifs_get_tlink(tlink);
-	mutex_init(&pCifsFile->fh_mutex);
-	INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break);
-	INIT_LIST_HEAD(&pCifsFile->llist);
+	struct cifsInodeInfo *cinode = CIFS_I(inode);
+	struct cifsFileInfo *cfile;
+
+	cfile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
+	if (cfile == NULL)
+		return cfile;
+
+	cfile->count = 1;
+	cfile->fid.netfid = fileHandle;
+	cfile->pid = current->tgid;
+	cfile->uid = current_fsuid();
+	cfile->dentry = dget(dentry);
+	cfile->f_flags = file->f_flags;
+	cfile->invalidHandle = false;
+	cfile->tlink = cifs_get_tlink(tlink);
+	mutex_init(&cfile->fh_mutex);
+	INIT_WORK(&cfile->oplock_break, cifs_oplock_break);
+	INIT_LIST_HEAD(&cfile->llist);
 
 	spin_lock(&cifs_file_list_lock);
-	list_add(&pCifsFile->tlist, &(tlink_tcon(tlink)->openFileList));
+	list_add(&cfile->tlist, &(tlink_tcon(tlink)->openFileList));
 	/* if readable file instance put first in list*/
 	if (file->f_mode & FMODE_READ)
-		list_add(&pCifsFile->flist, &pCifsInode->openFileList);
+		list_add(&cfile->flist, &cinode->openFileList);
 	else
-		list_add_tail(&pCifsFile->flist, &pCifsInode->openFileList);
+		list_add_tail(&cfile->flist, &cinode->openFileList);
 	spin_unlock(&cifs_file_list_lock);
 
-	cifs_set_oplock_level(pCifsInode, oplock);
-	pCifsInode->can_cache_brlcks = pCifsInode->clientCanCacheAll;
+	cifs_set_oplock_level(cinode, oplock);
+	cinode->can_cache_brlcks = cinode->clientCanCacheAll;
 
-	file->private_data = pCifsFile;
-	return pCifsFile;
+	file->private_data = cfile;
+	return cfile;
 }
 
 static void cifs_del_lock_waiters(struct cifsLockInfo *lock);
@@ -327,7 +327,7 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
 		unsigned int xid;
 		int rc;
 		xid = get_xid();
-		rc = CIFSSMBClose(xid, tcon, cifs_file->netfid);
+		rc = CIFSSMBClose(xid, tcon, cifs_file->fid.netfid);
 		free_xid(xid);
 	}
 
@@ -552,7 +552,7 @@ static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
 	}
 
 reopen_success:
-	pCifsFile->netfid = netfid;
+	pCifsFile->fid.netfid = netfid;
 	pCifsFile->invalidHandle = false;
 	mutex_unlock(&pCifsFile->fh_mutex);
 	pCifsInode = CIFS_I(inode);
@@ -600,39 +600,37 @@ int cifs_closedir(struct inode *inode, struct file *file)
 {
 	int rc = 0;
 	unsigned int xid;
-	struct cifsFileInfo *pCFileStruct = file->private_data;
-	char *ptmp;
+	struct cifsFileInfo *cfile = file->private_data;
+	char *tmp;
 
 	cFYI(1, "Closedir inode = 0x%p", inode);
 
 	xid = get_xid();
 
-	if (pCFileStruct) {
-		struct cifs_tcon *pTcon = tlink_tcon(pCFileStruct->tlink);
+	if (cfile) {
+		struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
 
 		cFYI(1, "Freeing private data in close dir");
 		spin_lock(&cifs_file_list_lock);
-		if (!pCFileStruct->srch_inf.endOfSearch &&
-		    !pCFileStruct->invalidHandle) {
-			pCFileStruct->invalidHandle = true;
+		if (!cfile->srch_inf.endOfSearch && !cfile->invalidHandle) {
+			cfile->invalidHandle = true;
 			spin_unlock(&cifs_file_list_lock);
-			rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
-			cFYI(1, "Closing uncompleted readdir with rc %d",
-				 rc);
+			rc = CIFSFindClose(xid, tcon, cfile->fid.netfid);
+			cFYI(1, "Closing uncompleted readdir with rc %d", rc);
 			/* not much we can do if it fails anyway, ignore rc */
 			rc = 0;
 		} else
 			spin_unlock(&cifs_file_list_lock);
-		ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
-		if (ptmp) {
+		tmp = cfile->srch_inf.ntwrk_buf_start;
+		if (tmp) {
 			cFYI(1, "closedir free smb buf in srch struct");
-			pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
-			if (pCFileStruct->srch_inf.smallBuf)
-				cifs_small_buf_release(ptmp);
+			cfile->srch_inf.ntwrk_buf_start = NULL;
+			if (cfile->srch_inf.smallBuf)
+				cifs_small_buf_release(tmp);
 			else
-				cifs_buf_release(ptmp);
+				cifs_buf_release(tmp);
 		}
-		cifs_put_tlink(pCFileStruct->tlink);
+		cifs_put_tlink(cfile->tlink);
 		kfree(file->private_data);
 		file->private_data = NULL;
 	}
@@ -923,7 +921,8 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
 			cur->OffsetLow = cpu_to_le32((u32)li->offset);
 			cur->OffsetHigh = cpu_to_le32((u32)(li->offset>>32));
 			if (++num == max_num) {
-				stored_rc = cifs_lockv(xid, tcon, cfile->netfid,
+				stored_rc = cifs_lockv(xid, tcon,
+						       cfile->fid.netfid,
 						       (__u8)li->type, 0, num,
 						       buf);
 				if (stored_rc)
@@ -935,7 +934,7 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
 		}
 
 		if (num) {
-			stored_rc = cifs_lockv(xid, tcon, cfile->netfid,
+			stored_rc = cifs_lockv(xid, tcon, cfile->fid.netfid,
 					       (__u8)types[i], 0, num, buf);
 			if (stored_rc)
 				rc = stored_rc;
@@ -1029,7 +1028,7 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)
 			type = CIFS_WRLCK;
 		lck = list_entry(el, struct lock_to_push, llist);
 		lck->pid = flock->fl_pid;
-		lck->netfid = cfile->netfid;
+		lck->netfid = cfile->fid.netfid;
 		lck->length = length;
 		lck->type = type;
 		lck->offset = flock->fl_start;
@@ -1130,7 +1129,7 @@ static int
 cifs_mandatory_lock(unsigned int xid, struct cifsFileInfo *cfile, __u64 offset,
 		    __u64 length, __u32 type, int lock, int unlock, bool wait)
 {
-	return CIFSSMBLock(xid, tlink_tcon(cfile->tlink), cfile->netfid,
+	return CIFSSMBLock(xid, tlink_tcon(cfile->tlink), cfile->fid.netfid,
 			   current->tgid, length, offset, unlock, lock,
 			   (__u8)type, wait, 0);
 }
@@ -1144,7 +1143,7 @@ cifs_getlk(struct file *file, struct file_lock *flock, __u32 type,
 	struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data;
 	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
 	struct TCP_Server_Info *server = tcon->ses->server;
-	__u16 netfid = cfile->netfid;
+	__u16 netfid = cfile->fid.netfid;
 
 	if (posix_lck) {
 		int posix_lock_type;
@@ -1288,7 +1287,8 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
 			 */
 			list_move(&li->llist, &tmp_llist);
 			if (++num == max_num) {
-				stored_rc = cifs_lockv(xid, tcon, cfile->netfid,
+				stored_rc = cifs_lockv(xid, tcon,
+						       cfile->fid.netfid,
 						       li->type, num, 0, buf);
 				if (stored_rc) {
 					/*
@@ -1311,7 +1311,7 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
 				cur++;
 		}
 		if (num) {
-			stored_rc = cifs_lockv(xid, tcon, cfile->netfid,
+			stored_rc = cifs_lockv(xid, tcon, cfile->fid.netfid,
 					       types[i], num, 0, buf);
 			if (stored_rc) {
 				cifs_move_llist(&tmp_llist, &cfile->llist);
@@ -1336,7 +1336,7 @@ cifs_setlk(struct file *file,  struct file_lock *flock, __u32 type,
 	struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data;
 	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
 	struct TCP_Server_Info *server = tcon->ses->server;
-	__u16 netfid = cfile->netfid;
+	__u16 netfid = cfile->fid.netfid;
 
 	if (posix_lck) {
 		int posix_lock_type;
@@ -1416,7 +1416,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock)
 			tcon->ses->server);
 
 	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
-	netfid = cfile->netfid;
+	netfid = cfile->fid.netfid;
 	cinode = CIFS_I(file->f_path.dentry->d_inode);
 
 	if (cap_unix(tcon->ses) &&
@@ -1507,7 +1507,7 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, __u32 pid,
 			/* iov[0] is reserved for smb header */
 			iov[1].iov_base = (char *)write_data + total_written;
 			iov[1].iov_len = len;
-			io_parms.netfid = open_file->netfid;
+			io_parms.netfid = open_file->fid.netfid;
 			io_parms.pid = pid;
 			io_parms.tcon = pTcon;
 			io_parms.offset = *poffset;
@@ -2071,7 +2071,7 @@ int cifs_strict_fsync(struct file *file, loff_t start, loff_t end,
 
 	tcon = tlink_tcon(smbfile->tlink);
 	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
-		rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
+		rc = CIFSSMBFlush(xid, tcon, smbfile->fid.netfid);
 
 	free_xid(xid);
 	mutex_unlock(&inode->i_mutex);
@@ -2099,7 +2099,7 @@ int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 
 	tcon = tlink_tcon(smbfile->tlink);
 	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
-		rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
+		rc = CIFSSMBFlush(xid, tcon, smbfile->fid.netfid);
 
 	free_xid(xid);
 	mutex_unlock(&inode->i_mutex);
@@ -2795,7 +2795,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
 				if (rc != 0)
 					break;
 			}
-			io_parms.netfid = open_file->netfid;
+			io_parms.netfid = open_file->fid.netfid;
 			io_parms.pid = pid;
 			io_parms.tcon = tcon;
 			io_parms.offset = *poffset;
@@ -3369,7 +3369,7 @@ void cifs_oplock_break(struct work_struct *work)
 	 * disconnected since oplock already released by the server
 	 */
 	if (!cfile->oplock_break_cancelled) {
-		rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid,
+		rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->fid.netfid,
 				 current->tgid, 0, 0, 0, 0,
 				 LOCKING_ANDX_OPLOCK_RELEASE, false,
 				 cinode->clientCanCacheRead ? 1 : 0);
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 9685eb1..1eeb6a0 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -298,7 +298,7 @@ int cifs_get_file_info_unix(struct file *filp)
 	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
 
 	xid = get_xid();
-	rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->netfid, &find_data);
+	rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->fid.netfid, &find_data);
 	if (!rc) {
 		cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb);
 	} else if (rc == -EREMOTE) {
@@ -566,7 +566,7 @@ int cifs_get_file_info(struct file *filp)
 	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
 
 	xid = get_xid();
-	rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data);
+	rc = CIFSSMBQFileInfo(xid, tcon, cfile->fid.netfid, &find_data);
 	switch (rc) {
 	case 0:
 		cifs_all_info_to_fattr(&fattr, &find_data, cifs_sb, false);
@@ -932,7 +932,7 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, unsigned int xid,
 	 */
 	open_file = find_writable_file(cifsInode, true);
 	if (open_file) {
-		netfid = open_file->netfid;
+		netfid = open_file->fid.netfid;
 		netpid = open_file->pid;
 		pTcon = tlink_tcon(open_file->tlink);
 		goto set_via_filehandle;
@@ -1887,7 +1887,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
 	 */
 	open_file = find_writable_file(cifsInode, true);
 	if (open_file) {
-		__u16 nfid = open_file->netfid;
+		__u16 nfid = open_file->fid.netfid;
 		__u32 npid = open_file->pid;
 		pTcon = tlink_tcon(open_file->tlink);
 		rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, nfid,
@@ -2061,7 +2061,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
 	args->device = 0;
 	open_file = find_writable_file(cifsInode, true);
 	if (open_file) {
-		u16 nfid = open_file->netfid;
+		u16 nfid = open_file->fid.netfid;
 		u32 npid = open_file->pid;
 		pTcon = tlink_tcon(open_file->tlink);
 		rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid);
diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c
index ae082a6..5b3481b 100644
--- a/fs/cifs/ioctl.c
+++ b/fs/cifs/ioctl.c
@@ -75,8 +75,9 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
 			tcon = tlink_tcon(pSMBFile->tlink);
 			caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
 			if (CIFS_UNIX_EXTATTR_CAP & caps) {
-				rc = CIFSGetExtAttr(xid, tcon, pSMBFile->netfid,
-					&ExtAttrBits, &ExtAttrMask);
+				rc = CIFSGetExtAttr(xid, tcon,
+						    pSMBFile->fid.netfid,
+						    &ExtAttrBits, &ExtAttrMask);
 				if (rc == 0)
 					rc = put_user(ExtAttrBits &
 						FS_FL_USER_VISIBLE,
@@ -94,8 +95,12 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
 					rc = -EFAULT;
 					break;
 				}
-				/* rc= CIFSGetExtAttr(xid,tcon,pSMBFile->netfid,
-					extAttrBits, &ExtAttrMask);*/
+				/*
+				 * rc = CIFSGetExtAttr(xid, tcon,
+				 *		       pSMBFile->fid.netfid,
+				 *		       extAttrBits,
+				 *		       &ExtAttrMask);
+				 */
 			}
 			cFYI(1, "set flags not implemented yet");
 			break;
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index ce41fee..a921b07 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -466,7 +466,7 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
 			list_for_each(tmp2, &tcon->openFileList) {
 				netfile = list_entry(tmp2, struct cifsFileInfo,
 						     tlist);
-				if (pSMB->Fid != netfile->netfid)
+				if (pSMB->Fid != netfile->fid.netfid)
 					continue;
 
 				cFYI(1, "file id match, oplock break");
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index d87f826..9e76e3b 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -279,7 +279,7 @@ ffirst_retry:
 		search_flags |= CIFS_SEARCH_BACKUP_SEARCH;
 
 	rc = CIFSFindFirst(xid, tcon, full_path, cifs_sb->local_nls,
-		&cifsFile->netfid, search_flags, &cifsFile->srch_inf,
+		&cifsFile->fid.netfid, search_flags, &cifsFile->srch_inf,
 		cifs_sb->mnt_cifs_flags &
 			CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
 	if (rc == 0)
@@ -545,7 +545,7 @@ static int find_cifs_entry(const unsigned int xid, struct cifs_tcon *pTcon,
 		    !cifsFile->invalidHandle) {
 			cifsFile->invalidHandle = true;
 			spin_unlock(&cifs_file_list_lock);
-			CIFSFindClose(xid, pTcon, cifsFile->netfid);
+			CIFSFindClose(xid, pTcon, cifsFile->fid.netfid);
 		} else
 			spin_unlock(&cifs_file_list_lock);
 		if (cifsFile->srch_inf.ntwrk_buf_start) {
@@ -577,8 +577,8 @@ static int find_cifs_entry(const unsigned int xid, struct cifs_tcon *pTcon,
 	while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) &&
 	      (rc == 0) && !cifsFile->srch_inf.endOfSearch) {
 		cFYI(1, "calling findnext2");
-		rc = CIFSFindNext(xid, pTcon, cifsFile->netfid, search_flags,
-				  &cifsFile->srch_inf);
+		rc = CIFSFindNext(xid, pTcon, cifsFile->fid.netfid,
+				  search_flags, &cifsFile->srch_inf);
 		/* FindFirst/Next set last_entry to NULL on malformed reply */
 		if (cifsFile->srch_inf.last_entry)
 			cifs_save_resume_key(cifsFile->srch_inf.last_entry,
@@ -781,7 +781,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
 			}
 		} /* else {
 			cifsFile->invalidHandle = true;
-			CIFSFindClose(xid, pTcon, cifsFile->netfid);
+			CIFSFindClose(xid, pTcon, cifsFile->fid.netfid);
 		} */
 
 		pTcon = tlink_tcon(cifsFile->tlink);
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 725fa61..b170da0 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -63,7 +63,7 @@ send_nt_cancel(struct TCP_Server_Info *server, void *buf,
 static bool
 cifs_compare_fids(struct cifsFileInfo *ob1, struct cifsFileInfo *ob2)
 {
-	return ob1->netfid == ob2->netfid;
+	return ob1->fid.netfid == ob2->fid.netfid;
 }
 
 static unsigned int
-- 
1.7.1

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

* [PATCH 11/45] CIFS: Move open code to ops struct
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (9 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 10/45] CIFS: Replace netfid with cifs_fid struct in cifsFileInfo Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
       [not found]     ` <1342626541-29872-12-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
  2012-07-18 15:48   ` [PATCH 12/45] CIFS: Move close " Pavel Shilovsky
                     ` (34 subsequent siblings)
  45 siblings, 1 reply; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/cifsglob.h  |    7 +++++
 fs/cifs/cifsproto.h |    7 +++--
 fs/cifs/dir.c       |   17 +++++++------
 fs/cifs/file.c      |   63 ++++++++++++++++++++++++--------------------------
 fs/cifs/smb1ops.c   |   29 +++++++++++++++++++++++
 5 files changed, 79 insertions(+), 44 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 01ee8d2..c4375d8 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -171,6 +171,7 @@ struct cifs_tcon;
 struct dfs_info3_param;
 struct cifs_fattr;
 struct smb_vol;
+struct cifs_fid;
 
 struct smb_version_operations {
 	int (*send_cancel)(struct TCP_Server_Info *, void *,
@@ -262,6 +263,12 @@ struct smb_version_operations {
 	/* open, rename and delete file */
 	int (*rename_pending_delete)(const char *, struct dentry *,
 				     const unsigned int);
+	/* open a file for non-posix mounts */
+	int (*open)(const unsigned int, struct cifs_tcon *, const char *, int,
+		    int, int, struct cifs_fid *, __u32 *, FILE_ALL_INFO *,
+		    struct cifs_sb_info *);
+	/* set fid protocol-specific info */
+	void (*set_fid)(struct cifsFileInfo *, struct cifs_fid *, __u32);
 };
 
 struct smb_version_values {
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index e9349af..80b0e40 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -121,9 +121,10 @@ extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time,
 				      int offset);
 extern void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock);
 
-extern struct cifsFileInfo *cifs_new_fileinfo(__u16 fileHandle,
-				struct file *file, struct tcon_link *tlink,
-				__u32 oplock);
+extern struct cifsFileInfo *cifs_new_fileinfo(struct cifs_fid *fid,
+					      struct file *file,
+					      struct tcon_link *tlink,
+					      __u32 oplock);
 extern int cifs_posix_open(char *full_path, struct inode **inode,
 			   struct super_block *sb, int mode,
 			   unsigned int f_flags, __u32 *oplock, __u16 *netfid,
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index cbe709a..eebffaf 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -384,11 +384,12 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
 	unsigned int xid;
 	struct tcon_link *tlink;
 	struct cifs_tcon *tcon;
-	__u16 fileHandle;
+	struct cifs_fid fid;
 	__u32 oplock;
-	struct cifsFileInfo *pfile_info;
+	struct cifsFileInfo *file_info;
 
-	/* Posix open is only called (at lookup time) for file create now.  For
+	/*
+	 * Posix open is only called (at lookup time) for file create now. For
 	 * opens (rather than creates), because we do not know if it is a file
 	 * or directory yet, and current Samba no longer allows us to do posix
 	 * open on dirs, we could end up wasting an open call on what turns out
@@ -422,20 +423,20 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
 	tcon = tlink_tcon(tlink);
 
 	rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode,
-			    &oplock, &fileHandle, opened);
+			    &oplock, &fid.netfid, opened);
 
 	if (rc)
 		goto out;
 
 	rc = finish_open(file, direntry, generic_file_open, opened);
 	if (rc) {
-		CIFSSMBClose(xid, tcon, fileHandle);
+		CIFSSMBClose(xid, tcon, fid.netfid);
 		goto out;
 	}
 
-	pfile_info = cifs_new_fileinfo(fileHandle, file, tlink, oplock);
-	if (pfile_info == NULL) {
-		CIFSSMBClose(xid, tcon, fileHandle);
+	file_info = cifs_new_fileinfo(&fid, file, tlink, oplock);
+	if (file_info == NULL) {
+		CIFSSMBClose(xid, tcon, fid.netfid);
 		rc = -ENOMEM;
 	}
 
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index f542574..3f4b4ba 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -169,16 +169,19 @@ posix_open_ret:
 
 static int
 cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
-	     struct cifs_tcon *tcon, unsigned int f_flags, __u32 *poplock,
-	     __u16 *pnetfid, unsigned int xid)
+	     struct cifs_tcon *tcon, unsigned int f_flags, __u32 *oplock,
+	     struct cifs_fid *fid, unsigned int xid)
 {
 	int rc;
-	int desiredAccess;
+	int desired_access;
 	int disposition;
 	int create_options = CREATE_NOT_DIR;
 	FILE_ALL_INFO *buf;
 
-	desiredAccess = cifs_convert_flags(f_flags);
+	if (!tcon->ses->server->ops->open)
+		return -ENOSYS;
+
+	desired_access = cifs_convert_flags(f_flags);
 
 /*********************************************************************
  *  open flag mapping table:
@@ -215,16 +218,9 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
 	if (backup_cred(cifs_sb))
 		create_options |= CREATE_OPEN_BACKUP_INTENT;
 
-	if (tcon->ses->capabilities & CAP_NT_SMBS)
-		rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
-			 desiredAccess, create_options, pnetfid, poplock, buf,
-			 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
-				 & CIFS_MOUNT_MAP_SPECIAL_CHR);
-	else
-		rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
-			desiredAccess, CREATE_NOT_DIR, pnetfid, poplock, buf,
-			cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
-				& CIFS_MOUNT_MAP_SPECIAL_CHR);
+	rc = tcon->ses->server->ops->open(xid, tcon, full_path, disposition,
+					  desired_access, create_options, fid,
+					  oplock, buf, cifs_sb);
 
 	if (rc)
 		goto out;
@@ -234,7 +230,7 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
 					      xid);
 	else
 		rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb,
-					 xid, pnetfid);
+					 xid, &fid->netfid);
 
 out:
 	kfree(buf);
@@ -242,7 +238,7 @@ out:
 }
 
 struct cifsFileInfo *
-cifs_new_fileinfo(__u16 fileHandle, struct file *file,
+cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
 		  struct tcon_link *tlink, __u32 oplock)
 {
 	struct dentry *dentry = file->f_path.dentry;
@@ -255,7 +251,6 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file,
 		return cfile;
 
 	cfile->count = 1;
-	cfile->fid.netfid = fileHandle;
 	cfile->pid = current->tgid;
 	cfile->uid = current_fsuid();
 	cfile->dentry = dget(dentry);
@@ -265,6 +260,7 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file,
 	mutex_init(&cfile->fh_mutex);
 	INIT_WORK(&cfile->oplock_break, cifs_oplock_break);
 	INIT_LIST_HEAD(&cfile->llist);
+	tlink_tcon(tlink)->ses->server->ops->set_fid(cfile, fid, oplock);
 
 	spin_lock(&cifs_file_list_lock);
 	list_add(&cfile->tlist, &(tlink_tcon(tlink)->openFileList));
@@ -275,9 +271,6 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file,
 		list_add_tail(&cfile->flist, &cinode->openFileList);
 	spin_unlock(&cifs_file_list_lock);
 
-	cifs_set_oplock_level(cinode, oplock);
-	cinode->can_cache_brlcks = cinode->clientCanCacheAll;
-
 	file->private_data = cfile;
 	return cfile;
 }
@@ -355,10 +348,10 @@ int cifs_open(struct inode *inode, struct file *file)
 	struct cifs_sb_info *cifs_sb;
 	struct cifs_tcon *tcon;
 	struct tcon_link *tlink;
-	struct cifsFileInfo *pCifsFile = NULL;
+	struct cifsFileInfo *cfile = NULL;
 	char *full_path = NULL;
 	bool posix_open_ok = false;
-	__u16 netfid;
+	struct cifs_fid fid;
 
 	xid = get_xid();
 
@@ -390,7 +383,7 @@ int cifs_open(struct inode *inode, struct file *file)
 		/* can not refresh inode info since size could be stale */
 		rc = cifs_posix_open(full_path, &inode, inode->i_sb,
 				cifs_sb->mnt_file_mode /* ignored */,
-				file->f_flags, &oplock, &netfid, xid);
+				file->f_flags, &oplock, &fid.netfid, xid);
 		if (rc == 0) {
 			cFYI(1, "posix open succeeded");
 			posix_open_ok = true;
@@ -406,20 +399,22 @@ int cifs_open(struct inode *inode, struct file *file)
 		} else if ((rc != -EIO) && (rc != -EREMOTE) &&
 			 (rc != -EOPNOTSUPP)) /* path not found or net err */
 			goto out;
-		/* else fallthrough to retry open the old way on network i/o
-		   or DFS errors */
+		/*
+		 * Else fallthrough to retry open the old way on network i/o
+		 * or DFS errors.
+		 */
 	}
 
 	if (!posix_open_ok) {
 		rc = cifs_nt_open(full_path, inode, cifs_sb, tcon,
-				  file->f_flags, &oplock, &netfid, xid);
+				  file->f_flags, &oplock, &fid, xid);
 		if (rc)
 			goto out;
 	}
 
-	pCifsFile = cifs_new_fileinfo(netfid, file, tlink, oplock);
-	if (pCifsFile == NULL) {
-		CIFSSMBClose(xid, tcon, netfid);
+	cfile = cifs_new_fileinfo(&fid, file, tlink, oplock);
+	if (cfile == NULL) {
+		CIFSSMBClose(xid, tcon, fid.netfid);
 		rc = -ENOMEM;
 		goto out;
 	}
@@ -427,8 +422,10 @@ int cifs_open(struct inode *inode, struct file *file)
 	cifs_fscache_set_inode_cookie(inode, file);
 
 	if ((oplock & CIFS_CREATE_ACTION) && !posix_open_ok && tcon->unix_ext) {
-		/* time to set mode which we can not set earlier due to
-		   problems creating new read-only files */
+		/*
+		 * Time to set mode which we can not set earlier due to
+		 * problems creating new read-only files.
+		 */
 		struct cifs_unix_set_info_args args = {
 			.mode	= inode->i_mode,
 			.uid	= NO_CHANGE_64,
@@ -438,8 +435,8 @@ int cifs_open(struct inode *inode, struct file *file)
 			.mtime	= NO_CHANGE_64,
 			.device	= 0,
 		};
-		CIFSSMBUnixSetFileInfo(xid, tcon, &args, netfid,
-					pCifsFile->pid);
+		CIFSSMBUnixSetFileInfo(xid, tcon, &args, fid.netfid,
+				       cfile->pid);
 	}
 
 out:
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index b170da0..907b308 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -607,6 +607,33 @@ cifs_mkdir_setinfo(struct inode *inode, const char *full_path,
 		cifsInode->cifsAttrs = dosattrs;
 }
 
+static int
+cifs_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
+	       int disposition, int desired_access, int create_options,
+	       struct cifs_fid *fid, __u32 *oplock, FILE_ALL_INFO *buf,
+	       struct cifs_sb_info *cifs_sb)
+{
+	if (!(tcon->ses->capabilities & CAP_NT_SMBS))
+		return SMBLegacyOpen(xid, tcon, path, disposition,
+				     desired_access, CREATE_NOT_DIR,
+				     &fid->netfid, oplock, buf,
+				     cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
+						& CIFS_MOUNT_MAP_SPECIAL_CHR);
+	return CIFSSMBOpen(xid, tcon, path, disposition, desired_access,
+			   create_options, &fid->netfid, oplock, buf,
+			   cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
+						CIFS_MOUNT_MAP_SPECIAL_CHR);
+}
+
+static void
+cifs_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock)
+{
+	struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
+	cfile->fid.netfid = fid->netfid;
+	cifs_set_oplock_level(cinode, oplock);
+	cinode->can_cache_brlcks = cinode->clientCanCacheAll;
+}
+
 struct smb_version_operations smb1_operations = {
 	.send_cancel = send_nt_cancel,
 	.compare_fids = cifs_compare_fids,
@@ -646,6 +673,8 @@ struct smb_version_operations smb1_operations = {
 	.rmdir = CIFSSMBRmDir,
 	.unlink = CIFSSMBDelFile,
 	.rename_pending_delete = cifs_rename_pending_delete,
+	.open = cifs_open_file,
+	.set_fid = cifs_set_fid,
 };
 
 struct smb_version_values smb1_values = {
-- 
1.7.1

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

* [PATCH 12/45] CIFS: Move close code to ops struct
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (10 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 11/45] CIFS: Move open code to ops struct Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
       [not found]     ` <1342626541-29872-13-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
  2012-07-18 15:48   ` [PATCH 13/45] CIFS: Add open/close file support for SMB2 Pavel Shilovsky
                     ` (33 subsequent siblings)
  45 siblings, 1 reply; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/cifsglob.h |    2 ++
 fs/cifs/file.c     |   10 +++++++---
 fs/cifs/smb1ops.c  |    8 ++++++++
 3 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index c4375d8..b3cbce6 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -269,6 +269,8 @@ struct smb_version_operations {
 		    struct cifs_sb_info *);
 	/* set fid protocol-specific info */
 	void (*set_fid)(struct cifsFileInfo *, struct cifs_fid *, __u32);
+	/* close a file */
+	int (*close)(const unsigned int, struct cifs_tcon *, struct cifs_fid *);
 };
 
 struct smb_version_values {
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 3f4b4ba..b18b36a 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -317,10 +317,13 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
 	cancel_work_sync(&cifs_file->oplock_break);
 
 	if (!tcon->need_reconnect && !cifs_file->invalidHandle) {
+		struct TCP_Server_Info *server = tcon->ses->server;
 		unsigned int xid;
-		int rc;
+		int rc = -ENOSYS;
+
 		xid = get_xid();
-		rc = CIFSSMBClose(xid, tcon, cifs_file->fid.netfid);
+		if (server->ops->close)
+			rc = server->ops->close(xid, tcon, &cifs_file->fid);
 		free_xid(xid);
 	}
 
@@ -414,7 +417,8 @@ int cifs_open(struct inode *inode, struct file *file)
 
 	cfile = cifs_new_fileinfo(&fid, file, tlink, oplock);
 	if (cfile == NULL) {
-		CIFSSMBClose(xid, tcon, fid.netfid);
+		if (tcon->ses->server->ops->close)
+			tcon->ses->server->ops->close(xid, tcon, &fid);
 		rc = -ENOMEM;
 		goto out;
 	}
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 907b308..bb75847 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -634,6 +634,13 @@ cifs_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock)
 	cinode->can_cache_brlcks = cinode->clientCanCacheAll;
 }
 
+static int
+cifs_close_file(const unsigned int xid, struct cifs_tcon *tcon,
+		struct cifs_fid *fid)
+{
+	return CIFSSMBClose(xid, tcon, fid->netfid);
+}
+
 struct smb_version_operations smb1_operations = {
 	.send_cancel = send_nt_cancel,
 	.compare_fids = cifs_compare_fids,
@@ -675,6 +682,7 @@ struct smb_version_operations smb1_operations = {
 	.rename_pending_delete = cifs_rename_pending_delete,
 	.open = cifs_open_file,
 	.set_fid = cifs_set_fid,
+	.close = cifs_close_file,
 };
 
 struct smb_version_values smb1_values = {
-- 
1.7.1

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

* [PATCH 13/45] CIFS: Add open/close file support for SMB2
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (11 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 12/45] CIFS: Move close " Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
  2012-07-18 15:48   ` [PATCH 14/45] CIFS: Move guery file info code to ops struct Pavel Shilovsky
                     ` (32 subsequent siblings)
  45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/Makefile    |    2 +-
 fs/cifs/cifsglob.h  |    4 ++
 fs/cifs/smb2file.c  |   86 +++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/cifs/smb2inode.c |    4 +-
 fs/cifs/smb2ops.c   |   22 ++++++++++++-
 fs/cifs/smb2pdu.c   |   53 ++++++++++++++++++++++++-------
 fs/cifs/smb2pdu.h   |    4 ++
 fs/cifs/smb2proto.h |   14 ++++++++-
 8 files changed, 172 insertions(+), 17 deletions(-)
 create mode 100644 fs/cifs/smb2file.c

diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile
index feee943..aa0d68b 100644
--- a/fs/cifs/Makefile
+++ b/fs/cifs/Makefile
@@ -17,4 +17,4 @@ cifs-$(CONFIG_CIFS_DFS_UPCALL) += dns_resolve.o cifs_dfs_ref.o
 cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o
 
 cifs-$(CONFIG_CIFS_SMB2) += smb2ops.o smb2maperror.o smb2transport.o \
-			    smb2misc.o smb2pdu.o smb2inode.o
+			    smb2misc.o smb2pdu.o smb2inode.o smb2file.o
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index b3cbce6..bd2b397 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -757,6 +757,10 @@ struct cifs_search_info {
 
 struct cifs_fid {
 	__u16 netfid;
+#ifdef CONFIG_CIFS_SMB2
+	__u64 persistent_fid;	/* persist file id for smb2 */
+	__u64 volatile_fid;	/* volatile file id for smb2 */
+#endif
 };
 
 struct cifsFileInfo {
diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c
new file mode 100644
index 0000000..a7618df
--- /dev/null
+++ b/fs/cifs/smb2file.c
@@ -0,0 +1,86 @@
+/*
+ *   fs/cifs/smb2file.c
+ *
+ *   Copyright (C) International Business Machines  Corp., 2002, 2011
+ *   Author(s): Steve French (sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org),
+ *              Pavel Shilovsky ((pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org) 2012
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/slab.h>
+#include <linux/pagemap.h>
+#include <asm/div64.h>
+#include "cifsfs.h"
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifs_debug.h"
+#include "cifs_fs_sb.h"
+#include "cifs_unicode.h"
+#include "fscache.h"
+#include "smb2proto.h"
+
+int
+smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
+	       int disposition, int desired_access, int create_options,
+	       struct cifs_fid *fid, __u32 *oplock, FILE_ALL_INFO *buf,
+	       struct cifs_sb_info *cifs_sb)
+{
+	int rc;
+	__le16 *smb2_path;
+	struct smb2_file_all_info *smb2_data = NULL;
+
+	smb2_path = cifs_convert_path_to_utf16(path, cifs_sb);
+	if (smb2_path == NULL) {
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + MAX_NAME * 2,
+			    GFP_KERNEL);
+	if (smb2_data == NULL) {
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	desired_access |= FILE_READ_ATTRIBUTES;
+
+	rc = SMB2_open(xid, tcon, smb2_path, &fid->persistent_fid,
+		       &fid->volatile_fid, desired_access, disposition,
+		       0, 0, smb2_data);
+	if (rc)
+		goto out;
+
+	if (buf) {
+		/* open response does not have IndexNumber field - get it */
+		rc = SMB2_get_srv_num(xid, tcon, fid->persistent_fid,
+				      fid->volatile_fid,
+				      &smb2_data->IndexNumber);
+		if (rc) {
+			/* let get_inode_info disable server inode numbers */
+			smb2_data->IndexNumber = 0;
+			rc = 0;
+		}
+		move_smb2_info_to_cifs(buf, smb2_data);
+	}
+
+out:
+	*oplock = 0;
+	kfree(smb2_data);
+	kfree(smb2_path);
+	return rc;
+}
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index 02a9bda..ee3a1ef 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -54,7 +54,7 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
 
 	rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid,
 		       desired_access, create_disposition, file_attributes,
-		       create_options);
+		       create_options, NULL);
 	if (rc) {
 		kfree(utf16_path);
 		return rc;
@@ -86,7 +86,7 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
 	return rc;
 }
 
-static void
+void
 move_smb2_info_to_cifs(FILE_ALL_INFO *dst, struct smb2_file_all_info *src)
 {
 	memcpy(dst, src, (size_t)(&src->CurrentByteOffset) - (size_t)src);
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index bf9b318..eba12b3 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -170,7 +170,7 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
 		return -ENOMEM;
 
 	rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid,
-		       FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0);
+		       FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0, NULL);
 	if (rc) {
 		kfree(utf16_path);
 		return rc;
@@ -292,6 +292,23 @@ smb2_print_stats(struct seq_file *m, struct cifs_tcon *tcon)
 #endif
 }
 
+static void
+smb2_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock)
+{
+	/* struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); */
+	cfile->fid.persistent_fid = fid->persistent_fid;
+	cfile->fid.volatile_fid = fid->volatile_fid;
+	/* cifs_set_oplock_level(cinode, oplock); */
+	/* cinode->can_cache_brlcks = cinode->clientCanCacheAll; */
+}
+
+static int
+smb2_close_file(const unsigned int xid, struct cifs_tcon *tcon,
+		struct cifs_fid *fid)
+{
+	return SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid);
+}
+
 struct smb_version_operations smb21_operations = {
 	.setup_request = smb2_setup_request,
 	.setup_async_request = smb2_setup_async_request,
@@ -322,6 +339,9 @@ struct smb_version_operations smb21_operations = {
 	.mkdir_setinfo = smb2_mkdir_setinfo,
 	.rmdir = smb2_rmdir,
 	.unlink = smb2_unlink,
+	.open = smb2_open_file,
+	.set_fid = smb2_set_fid,
+	.close = smb2_close_file,
 };
 
 struct smb_version_values smb21_values = {
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 62b3f17..231e970 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -833,7 +833,8 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
 int
 SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
 	  u64 *persistent_fid, u64 *volatile_fid, __u32 desired_access,
-	  __u32 create_disposition, __u32 file_attributes, __u32 create_options)
+	  __u32 create_disposition, __u32 file_attributes, __u32 create_options,
+	  struct smb2_file_all_info *buf)
 {
 	struct smb2_create_req *req;
 	struct smb2_create_rsp *rsp;
@@ -856,9 +857,9 @@ SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
 	if (rc)
 		return rc;
 
-	if (enable_oplocks)
+	/* if (server->oplocks)
 		req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_BATCH;
-	else
+	else */
 		req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_NONE;
 	req->ImpersonationLevel = IL_IMPERSONATION;
 	req->DesiredAccess = cpu_to_le32(desired_access);
@@ -906,6 +907,15 @@ SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
 	}
 	*persistent_fid = rsp->PersistentFileId;
 	*volatile_fid = rsp->VolatileFileId;
+
+	if (buf) {
+		memcpy(buf, &rsp->CreationTime, 32);
+		buf->AllocationSize = rsp->AllocationSize;
+		buf->EndOfFile = rsp->EndofFile;
+		buf->Attributes = rsp->FileAttributes;
+		buf->NumberOfLinks = cpu_to_le32(1);
+		buf->DeletePending = 0;
+	}
 creat_exit:
 	free_rsp_buf(resp_buftype, rsp);
 	return rc;
@@ -1019,10 +1029,10 @@ validate_and_copy_buf(unsigned int offset, unsigned int buffer_length,
 	return 0;
 }
 
-int
-SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
-		u64 persistent_fid, u64 volatile_fid,
-		struct smb2_file_all_info *data)
+static int
+query_info(const unsigned int xid, struct cifs_tcon *tcon,
+	   u64 persistent_fid, u64 volatile_fid, u8 info_class,
+	   size_t output_len, size_t min_len, void *data)
 {
 	struct smb2_query_info_req *req;
 	struct smb2_query_info_rsp *rsp = NULL;
@@ -1044,14 +1054,13 @@ SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
 		return rc;
 
 	req->InfoType = SMB2_O_INFO_FILE;
-	req->FileInfoClass = FILE_ALL_INFORMATION;
+	req->FileInfoClass = info_class;
 	req->PersistentFileId = persistent_fid;
 	req->VolatileFileId = volatile_fid;
 	/* 4 for rfc1002 length field and 1 for Buffer */
 	req->InputBufferOffset =
 		cpu_to_le16(sizeof(struct smb2_query_info_req) - 1 - 4);
-	req->OutputBufferLength =
-		cpu_to_le32(sizeof(struct smb2_file_all_info) + MAX_NAME * 2);
+	req->OutputBufferLength = cpu_to_le32(output_len);
 
 	iov[0].iov_base = (char *)req;
 	/* 4 for rfc1002 length field */
@@ -1067,14 +1076,34 @@ SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
 
 	rc = validate_and_copy_buf(le16_to_cpu(rsp->OutputBufferOffset),
 				   le32_to_cpu(rsp->OutputBufferLength),
-				   &rsp->hdr, sizeof(struct smb2_file_all_info),
-				   (char *)data);
+				   &rsp->hdr, min_len, data);
 
 qinf_exit:
 	free_rsp_buf(resp_buftype, rsp);
 	return rc;
 }
 
+int
+SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
+		u64 persistent_fid, u64 volatile_fid,
+		struct smb2_file_all_info *data)
+{
+	return query_info(xid, tcon, persistent_fid, volatile_fid,
+			  FILE_ALL_INFORMATION,
+			  sizeof(struct smb2_file_all_info) + MAX_NAME * 2,
+			  sizeof(struct smb2_file_all_info), data);
+}
+
+int
+SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon,
+		 u64 persistent_fid, u64 volatile_fid, __le64 *uniqueid)
+{
+	return query_info(xid, tcon, persistent_fid, volatile_fid,
+			  FILE_INTERNAL_INFORMATION,
+			  sizeof(struct smb2_file_internal_info),
+			  sizeof(struct smb2_file_internal_info), uniqueid);
+}
+
 /*
  * This is a no-op for now. We're not really interested in the reply, but
  * rather in the fact that the server sent one and that server->lstrp
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index f37a1b4..7f1caff 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -546,6 +546,10 @@ struct smb2_query_info_rsp {
 #define FILEID_GLOBAL_TX_DIRECTORY_INFORMATION 50
 #define FILE_STANDARD_LINK_INFORMATION	54
 
+struct smb2_file_internal_info {
+	__le64 IndexNumber;
+} __packed; /* level 6 Query */
+
 /*
  * This level 18, although with struct with same name is different from cifs
  * level 0x107. Level 0x107 has an extra u64 between AccessFlags and
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index f4ac727..624d344 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -48,6 +48,8 @@ extern int smb2_setup_async_request(struct TCP_Server_Info *server,
 				    struct mid_q_entry **ret_mid);
 extern void smb2_echo_request(struct work_struct *work);
 
+extern void move_smb2_info_to_cifs(FILE_ALL_INFO *dst,
+				   struct smb2_file_all_info *src);
 extern int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
 				struct cifs_sb_info *cifs_sb,
 				const char *full_path, FILE_ALL_INFO *data,
@@ -62,6 +64,12 @@ extern int smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon,
 extern int smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon,
 		       const char *name, struct cifs_sb_info *cifs_sb);
 
+extern int smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon,
+			  const char *full_path, int disposition,
+			  int desired_access, int create_options,
+			  struct cifs_fid *fid, __u32 *oplock,
+			  FILE_ALL_INFO *buf, struct cifs_sb_info *cifs_sb);
+
 /*
  * SMB2 Worker functions - most of protocol specific implementation details
  * are contained within these calls.
@@ -77,12 +85,16 @@ extern int SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon);
 extern int SMB2_open(const unsigned int xid, struct cifs_tcon *tcon,
 		     __le16 *path, u64 *persistent_fid, u64 *volatile_fid,
 		     __u32 desired_access, __u32 create_disposition,
-		     __u32 file_attributes, __u32 create_options);
+		     __u32 file_attributes, __u32 create_options,
+		     struct smb2_file_all_info *buf);
 extern int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
 		      u64 persistent_file_id, u64 volatile_file_id);
 extern int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
 			   u64 persistent_file_id, u64 volatile_file_id,
 			   struct smb2_file_all_info *data);
+extern int SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon,
+			    u64 persistent_fid, u64 volatile_fid,
+			    __le64 *uniqueid);
 extern int SMB2_echo(struct TCP_Server_Info *server);
 
 #endif			/* _SMB2PROTO_H */
-- 
1.7.1

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

* [PATCH 14/45] CIFS: Move guery file info code to ops struct
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (12 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 13/45] CIFS: Add open/close file support for SMB2 Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
  2012-07-18 15:48   ` [PATCH 15/45] CIFS: Add SMB2 support for query_file_info Pavel Shilovsky
                     ` (31 subsequent siblings)
  45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

and make cifs_get_file_info(_unix) calls static.

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/cifsglob.h  |    3 +++
 fs/cifs/cifsproto.h |    2 --
 fs/cifs/inode.c     |   12 +++++++++---
 fs/cifs/smb1ops.c   |    8 ++++++++
 4 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index bd2b397..0467e38 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -236,6 +236,9 @@ struct smb_version_operations {
 	int (*query_path_info)(const unsigned int, struct cifs_tcon *,
 			       struct cifs_sb_info *, const char *,
 			       FILE_ALL_INFO *, bool *);
+	/* query file data from the server */
+	int (*query_file_info)(const unsigned int, struct cifs_tcon *,
+			       struct cifs_fid *, FILE_ALL_INFO *);
 	/* get server index number */
 	int (*get_srv_inum)(const unsigned int, struct cifs_tcon *,
 			    struct cifs_sb_info *, const char *,
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 80b0e40..c811f66 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -137,11 +137,9 @@ extern void cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr);
 extern struct inode *cifs_iget(struct super_block *sb,
 			       struct cifs_fattr *fattr);
 
-extern int cifs_get_file_info(struct file *filp);
 extern int cifs_get_inode_info(struct inode **inode, const char *full_path,
 			       FILE_ALL_INFO *data, struct super_block *sb,
 			       int xid, const __u16 *fid);
-extern int cifs_get_file_info_unix(struct file *filp);
 extern int cifs_get_inode_info_unix(struct inode **pinode,
 			const unsigned char *search_path,
 			struct super_block *sb, unsigned int xid);
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 1eeb6a0..39ef1a6 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -286,7 +286,8 @@ cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb)
 	fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL;
 }
 
-int cifs_get_file_info_unix(struct file *filp)
+static int
+cifs_get_file_info_unix(struct file *filp)
 {
 	int rc;
 	unsigned int xid;
@@ -554,7 +555,8 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
 	fattr->cf_gid = cifs_sb->mnt_gid;
 }
 
-int cifs_get_file_info(struct file *filp)
+static int
+cifs_get_file_info(struct file *filp)
 {
 	int rc;
 	unsigned int xid;
@@ -564,9 +566,13 @@ int cifs_get_file_info(struct file *filp)
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 	struct cifsFileInfo *cfile = filp->private_data;
 	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
+	struct TCP_Server_Info *server = tcon->ses->server;
+
+	if (!server->ops->query_file_info)
+		return -ENOSYS;
 
 	xid = get_xid();
-	rc = CIFSSMBQFileInfo(xid, tcon, cfile->fid.netfid, &find_data);
+	rc = server->ops->query_file_info(xid, tcon, &cfile->fid, &find_data);
 	switch (rc) {
 	case 0:
 		cifs_all_info_to_fattr(&fattr, &find_data, cifs_sb, false);
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index bb75847..cbbc122 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -489,6 +489,13 @@ cifs_get_srv_inum(const unsigned int xid, struct cifs_tcon *tcon,
 						CIFS_MOUNT_MAP_SPECIAL_CHR);
 }
 
+static int
+cifs_query_file_info(const unsigned int xid, struct cifs_tcon *tcon,
+		     struct cifs_fid *fid, FILE_ALL_INFO *data)
+{
+	return CIFSSMBQFileInfo(xid, tcon, fid->netfid, data);
+}
+
 static char *
 cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
 			struct cifs_tcon *tcon)
@@ -672,6 +679,7 @@ struct smb_version_operations smb1_operations = {
 	.qfs_tcon = cifs_qfs_tcon,
 	.is_path_accessible = cifs_is_path_accessible,
 	.query_path_info = cifs_query_path_info,
+	.query_file_info = cifs_query_file_info,
 	.get_srv_inum = cifs_get_srv_inum,
 	.build_path_to_root = cifs_build_path_to_root,
 	.echo = CIFSSMBEcho,
-- 
1.7.1

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

* [PATCH 15/45] CIFS: Add SMB2 support for query_file_info
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (13 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 14/45] CIFS: Move guery file info code to ops struct Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
  2012-07-18 15:48   ` [PATCH 16/45] CIFS: Move create code use ops struct Pavel Shilovsky
                     ` (30 subsequent siblings)
  45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/smb2ops.c |   21 +++++++++++++++++++++
 1 files changed, 21 insertions(+), 0 deletions(-)

diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index eba12b3..0fd5801 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -190,6 +190,26 @@ smb2_get_srv_inum(const unsigned int xid, struct cifs_tcon *tcon,
 	return 0;
 }
 
+static int
+smb2_query_file_info(const unsigned int xid, struct cifs_tcon *tcon,
+		     struct cifs_fid *fid, FILE_ALL_INFO *data)
+{
+	int rc;
+	struct smb2_file_all_info *smb2_data;
+
+	smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + MAX_NAME * 2,
+			    GFP_KERNEL);
+	if (smb2_data == NULL)
+		return -ENOMEM;
+
+	rc = SMB2_query_info(xid, tcon, fid->persistent_fid, fid->volatile_fid,
+			     smb2_data);
+	if (!rc)
+		move_smb2_info_to_cifs(data, smb2_data);
+	kfree(smb2_data);
+	return rc;
+}
+
 static char *
 smb2_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
 			struct cifs_tcon *tcon)
@@ -334,6 +354,7 @@ struct smb_version_operations smb21_operations = {
 	.echo = SMB2_echo,
 	.query_path_info = smb2_query_path_info,
 	.get_srv_inum = smb2_get_srv_inum,
+	.query_file_info = smb2_query_file_info,
 	.build_path_to_root = smb2_build_path_to_root,
 	.mkdir = smb2_mkdir,
 	.mkdir_setinfo = smb2_mkdir_setinfo,
-- 
1.7.1

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

* [PATCH 16/45] CIFS: Move create code use ops struct
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (14 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 15/45] CIFS: Add SMB2 support for query_file_info Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
  2012-07-18 15:48   ` [PATCH 17/45] CIFS: Move reopen code to " Pavel Shilovsky
                     ` (29 subsequent siblings)
  45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/dir.c     |   94 ++++++++++++++++++++++++++++------------------------
 fs/cifs/file.c    |   10 +++---
 fs/cifs/smb1ops.c |    2 +-
 3 files changed, 57 insertions(+), 49 deletions(-)

diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index eebffaf..7265e5a 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -160,17 +160,18 @@ check_name(struct dentry *direntry)
 static int
 cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
 	       struct tcon_link *tlink, unsigned oflags, umode_t mode,
-	       __u32 *oplock, __u16 *fileHandle, int *created)
+	       __u32 *oplock, struct cifs_fid *fid, int *created)
 {
 	int rc = -ENOENT;
 	int create_options = CREATE_NOT_DIR;
-	int desiredAccess;
+	int desired_access;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 	struct cifs_tcon *tcon = tlink_tcon(tlink);
 	char *full_path = NULL;
 	FILE_ALL_INFO *buf = NULL;
 	struct inode *newinode = NULL;
 	int disposition;
+	struct TCP_Server_Info *server = tcon->ses->server;
 
 	*oplock = 0;
 	if (tcon->ses->server->oplocks)
@@ -185,8 +186,8 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
 	if (tcon->unix_ext && cap_unix(tcon->ses) && !tcon->broken_posix_open &&
 	    (CIFS_UNIX_POSIX_PATH_OPS_CAP &
 			le64_to_cpu(tcon->fsUnixInfo.Capability))) {
-		rc = cifs_posix_open(full_path, &newinode,
-			inode->i_sb, mode, oflags, oplock, fileHandle, xid);
+		rc = cifs_posix_open(full_path, &newinode, inode->i_sb, mode,
+				     oflags, oplock, &fid->netfid, xid);
 		switch (rc) {
 		case 0:
 			if (newinode == NULL) {
@@ -202,7 +203,7 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
 				 * close it and proceed as if it were a normal
 				 * lookup.
 				 */
-				CIFSSMBClose(xid, tcon, *fileHandle);
+				CIFSSMBClose(xid, tcon, fid->netfid);
 				goto cifs_create_get_file_info;
 			}
 			/* success, no need to query */
@@ -244,11 +245,11 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
 		 */
 	}
 
-	desiredAccess = 0;
+	desired_access = 0;
 	if (OPEN_FMODE(oflags) & FMODE_READ)
-		desiredAccess |= GENERIC_READ; /* is this too little? */
+		desired_access |= GENERIC_READ; /* is this too little? */
 	if (OPEN_FMODE(oflags) & FMODE_WRITE)
-		desiredAccess |= GENERIC_WRITE;
+		desired_access |= GENERIC_WRITE;
 
 	disposition = FILE_OVERWRITE_IF;
 	if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
@@ -260,8 +261,15 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
 	else
 		cFYI(1, "Create flag not set in create function");
 
-	/* BB add processing to set equivalent of mode - e.g. via CreateX with
-	   ACLs */
+	/*
+	 * BB add processing to set equivalent of mode - e.g. via CreateX with
+	 * ACLs
+	 */
+
+	if (!server->ops->open) {
+		rc = -ENOSYS;
+		goto out;
+	}
 
 	buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
 	if (buf == NULL) {
@@ -279,28 +287,18 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
 	if (backup_cred(cifs_sb))
 		create_options |= CREATE_OPEN_BACKUP_INTENT;
 
-	if (tcon->ses->capabilities & CAP_NT_SMBS)
-		rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
-			 desiredAccess, create_options,
-			 fileHandle, oplock, buf, cifs_sb->local_nls,
-			 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
-	else
-		rc = -EIO; /* no NT SMB support fall into legacy open below */
-
-	if (rc == -EIO) {
-		/* old server, retry the open legacy style */
-		rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
-			desiredAccess, create_options,
-			fileHandle, oplock, buf, cifs_sb->local_nls,
-			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
-	}
+	rc = server->ops->open(xid, tcon, full_path, disposition,
+			       desired_access, create_options, fid, oplock,
+			       buf, cifs_sb);
 	if (rc) {
 		cFYI(1, "cifs_create returned 0x%x", rc);
 		goto out;
 	}
 
-	/* If Open reported that we actually created a file
-	   then we now have to set the mode if possible */
+	/*
+	 * If Open reported that we actually created a file then we now have to
+	 * set the mode if possible.
+	 */
 	if ((tcon->unix_ext) && (*oplock & CIFS_CREATE_ACTION)) {
 		struct cifs_unix_set_info_args args = {
 				.mode	= mode,
@@ -321,11 +319,13 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
 			args.uid = NO_CHANGE_64;
 			args.gid = NO_CHANGE_64;
 		}
-		CIFSSMBUnixSetFileInfo(xid, tcon, &args, *fileHandle,
-					current->tgid);
+		CIFSSMBUnixSetFileInfo(xid, tcon, &args, fid->netfid,
+				       current->tgid);
 	} else {
-		/* BB implement mode setting via Windows security
-		   descriptors e.g. */
+		/*
+		 * BB implement mode setting via Windows security
+		 * descriptors e.g.
+		 */
 		/* CIFSSMBWinSetPerms(xid,tcon,path,mode,-1,-1,nls);*/
 
 		/* Could set r/o dos attribute if mode & 0222 == 0 */
@@ -334,11 +334,11 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
 cifs_create_get_file_info:
 	/* server might mask mode so we have to query for it */
 	if (tcon->unix_ext)
-		rc = cifs_get_inode_info_unix(&newinode, full_path,
-					      inode->i_sb, xid);
+		rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb,
+					      xid);
 	else {
-		rc = cifs_get_inode_info(&newinode, full_path, buf,
-					 inode->i_sb, xid, fileHandle);
+		rc = cifs_get_inode_info(&newinode, full_path, buf, inode->i_sb,
+					 xid, &fid->netfid);
 		if (newinode) {
 			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
 				newinode->i_mode = mode;
@@ -364,7 +364,7 @@ cifs_create_set_dentry:
 	/* ENOENT for create?  How weird... */
 	rc = -ENOENT;
 	if (!newinode) {
-		CIFSSMBClose(xid, tcon, *fileHandle);
+		CIFSSMBClose(xid, tcon, fid->netfid);
 		goto out;
 	}
 	rc = 0;
@@ -384,6 +384,7 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
 	unsigned int xid;
 	struct tcon_link *tlink;
 	struct cifs_tcon *tcon;
+	struct TCP_Server_Info *server;
 	struct cifs_fid fid;
 	__u32 oplock;
 	struct cifsFileInfo *file_info;
@@ -421,22 +422,25 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
 		goto out_free_xid;
 
 	tcon = tlink_tcon(tlink);
+	server = tcon->ses->server;
 
 	rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode,
-			    &oplock, &fid.netfid, opened);
+			    &oplock, &fid, opened);
 
 	if (rc)
 		goto out;
 
 	rc = finish_open(file, direntry, generic_file_open, opened);
 	if (rc) {
-		CIFSSMBClose(xid, tcon, fid.netfid);
+		if (server->ops->close)
+			server->ops->close(xid, tcon, &fid);
 		goto out;
 	}
 
 	file_info = cifs_new_fileinfo(&fid, file, tlink, oplock);
 	if (file_info == NULL) {
-		CIFSSMBClose(xid, tcon, fid.netfid);
+		if (server->ops->close)
+			server->ops->close(xid, tcon, &fid);
 		rc = -ENOMEM;
 	}
 
@@ -461,7 +465,9 @@ int cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
 	 */
 	unsigned oflags = O_EXCL | O_CREAT | O_RDWR;
 	struct tcon_link *tlink;
-	__u16 fileHandle;
+	struct cifs_tcon *tcon;
+	struct TCP_Server_Info *server;
+	struct cifs_fid fid;
 	__u32 oplock;
 	int created = FILE_CREATED;
 
@@ -474,9 +480,11 @@ int cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
 		goto out_free_xid;
 
 	rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode,
-			    &oplock, &fileHandle, &created);
-	if (!rc)
-		CIFSSMBClose(xid, tlink_tcon(tlink), fileHandle);
+			    &oplock, &fid, &created);
+	tcon = tlink_tcon(tlink);
+	server = tcon->ses->server;
+	if (!rc && server->ops->close)
+		server->ops->close(xid, tcon, &fid);
 
 	cifs_put_tlink(tlink);
 out_free_xid:
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index b18b36a..e11a58a 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -303,13 +303,13 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
 	if (list_empty(&cifsi->openFileList)) {
 		cFYI(1, "closing last open instance for inode %p",
 			cifs_file->dentry->d_inode);
-
-		/* in strict cache mode we need invalidate mapping on the last
-		   close  because it may cause a error when we open this file
-		   again and get at least level II oplock */
+		/*
+		 * In strict cache mode we need invalidate mapping on the last
+		 * close  because it may cause a error when we open this file
+		 * again and get at least level II oplock.
+		 */
 		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO)
 			CIFS_I(inode)->invalid_mapping = true;
-
 		cifs_set_oplock_level(cifsi, 0);
 	}
 	spin_unlock(&cifs_file_list_lock);
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index cbbc122..dd64754 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -622,7 +622,7 @@ cifs_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
 {
 	if (!(tcon->ses->capabilities & CAP_NT_SMBS))
 		return SMBLegacyOpen(xid, tcon, path, disposition,
-				     desired_access, CREATE_NOT_DIR,
+				     desired_access, create_options,
 				     &fid->netfid, oplock, buf,
 				     cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
 						& CIFS_MOUNT_MAP_SPECIAL_CHR);
-- 
1.7.1

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

* [PATCH 17/45] CIFS: Move reopen code to ops struct
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (15 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 16/45] CIFS: Move create code use ops struct Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
  2012-07-18 15:48   ` [PATCH 18/45] CIFS: Make flush code use " Pavel Shilovsky
                     ` (28 subsequent siblings)
  45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/file.c |  123 +++++++++++++++++++++++++++++--------------------------
 1 files changed, 65 insertions(+), 58 deletions(-)

diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index e11a58a..e8cca00 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -450,59 +450,66 @@ out:
 	return rc;
 }
 
-/* Try to reacquire byte range locks that were released when session */
-/* to server was lost */
+/*
+ * Try to reacquire byte range locks that were released when session
+ * to server was lost
+ */
 static int cifs_relock_file(struct cifsFileInfo *cifsFile)
 {
 	int rc = 0;
 
-/* BB list all locks open on this file and relock */
+	/* BB list all locks open on this file and relock */
 
 	return rc;
 }
 
-static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
+static int
+cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
 {
 	int rc = -EACCES;
 	unsigned int xid;
 	__u32 oplock;
 	struct cifs_sb_info *cifs_sb;
 	struct cifs_tcon *tcon;
-	struct cifsInodeInfo *pCifsInode;
+	struct TCP_Server_Info *server;
+	struct cifsInodeInfo *cinode;
 	struct inode *inode;
 	char *full_path = NULL;
-	int desiredAccess;
+	int desired_access;
 	int disposition = FILE_OPEN;
 	int create_options = CREATE_NOT_DIR;
-	__u16 netfid;
+	struct cifs_fid fid;
 
 	xid = get_xid();
-	mutex_lock(&pCifsFile->fh_mutex);
-	if (!pCifsFile->invalidHandle) {
-		mutex_unlock(&pCifsFile->fh_mutex);
+	mutex_lock(&cfile->fh_mutex);
+	if (!cfile->invalidHandle) {
+		mutex_unlock(&cfile->fh_mutex);
 		rc = 0;
 		free_xid(xid);
 		return rc;
 	}
 
-	inode = pCifsFile->dentry->d_inode;
+	inode = cfile->dentry->d_inode;
 	cifs_sb = CIFS_SB(inode->i_sb);
-	tcon = tlink_tcon(pCifsFile->tlink);
+	tcon = tlink_tcon(cfile->tlink);
+	server = tcon->ses->server;
 
-/* can not grab rename sem here because various ops, including
-   those that already have the rename sem can end up causing writepage
-   to get called and if the server was down that means we end up here,
-   and we can never tell if the caller already has the rename_sem */
-	full_path = build_path_from_dentry(pCifsFile->dentry);
+	/*
+	 * Can not grab rename sem here because various ops, including those
+	 * that already have the rename sem can end up causing writepage to get
+	 * called and if the server was down that means we end up here, and we
+	 * can never tell if the caller already has the rename_sem.
+	 */
+	full_path = build_path_from_dentry(cfile->dentry);
 	if (full_path == NULL) {
 		rc = -ENOMEM;
-		mutex_unlock(&pCifsFile->fh_mutex);
+		mutex_unlock(&cfile->fh_mutex);
 		free_xid(xid);
 		return rc;
 	}
 
-	cFYI(1, "inode = 0x%p file flags 0x%x for %s",
-		 inode, pCifsFile->f_flags, full_path);
+	cFYI(1, "inode = 0x%p file flags 0x%x for %s", inode, cfile->f_flags,
+	     full_path);
 
 	if (tcon->ses->server->oplocks)
 		oplock = REQ_OPLOCK;
@@ -516,69 +523,69 @@ static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
 		 * O_CREAT, O_EXCL and O_TRUNC already had their effect on the
 		 * original open. Must mask them off for a reopen.
 		 */
-		unsigned int oflags = pCifsFile->f_flags &
+		unsigned int oflags = cfile->f_flags &
 						~(O_CREAT | O_EXCL | O_TRUNC);
 
 		rc = cifs_posix_open(full_path, NULL, inode->i_sb,
-				cifs_sb->mnt_file_mode /* ignored */,
-				oflags, &oplock, &netfid, xid);
+				     cifs_sb->mnt_file_mode /* ignored */,
+				     oflags, &oplock, &fid.netfid, xid);
 		if (rc == 0) {
 			cFYI(1, "posix reopen succeeded");
 			goto reopen_success;
 		}
-		/* fallthrough to retry open the old way on errors, especially
-		   in the reconnect path it is important to retry hard */
+		/*
+		 * fallthrough to retry open the old way on errors, especially
+		 * in the reconnect path it is important to retry hard
+		 */
 	}
 
-	desiredAccess = cifs_convert_flags(pCifsFile->f_flags);
+	desired_access = cifs_convert_flags(cfile->f_flags);
 
 	if (backup_cred(cifs_sb))
 		create_options |= CREATE_OPEN_BACKUP_INTENT;
 
-	/* Can not refresh inode by passing in file_info buf to be returned
-	   by SMBOpen and then calling get_inode_info with returned buf
-	   since file might have write behind data that needs to be flushed
-	   and server version of file size can be stale. If we knew for sure
-	   that inode was not dirty locally we could do this */
-
-	rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess,
-			 create_options, &netfid, &oplock, NULL,
-			 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
-				CIFS_MOUNT_MAP_SPECIAL_CHR);
+	/*
+	 * Can not refresh inode by passing in file_info buf to be returned by
+	 * CIFSSMBOpen and then calling get_inode_info with returned buf since
+	 * file might have write behind data that needs to be flushed and server
+	 * version of file size can be stale. If we knew for sure that inode was
+	 * not dirty locally we could do this.
+	 */
+	rc = server->ops->open(xid, tcon, full_path, disposition,
+			       desired_access, create_options, &fid, &oplock,
+			       NULL, cifs_sb);
 	if (rc) {
-		mutex_unlock(&pCifsFile->fh_mutex);
-		cFYI(1, "cifs_open returned 0x%x", rc);
+		mutex_unlock(&cfile->fh_mutex);
+		cFYI(1, "cifs_reopen returned 0x%x", rc);
 		cFYI(1, "oplock: %d", oplock);
 		goto reopen_error_exit;
 	}
 
 reopen_success:
-	pCifsFile->fid.netfid = netfid;
-	pCifsFile->invalidHandle = false;
-	mutex_unlock(&pCifsFile->fh_mutex);
-	pCifsInode = CIFS_I(inode);
+	cfile->invalidHandle = false;
+	mutex_unlock(&cfile->fh_mutex);
+	cinode = CIFS_I(inode);
 
 	if (can_flush) {
 		rc = filemap_write_and_wait(inode->i_mapping);
 		mapping_set_error(inode->i_mapping, rc);
 
 		if (tcon->unix_ext)
-			rc = cifs_get_inode_info_unix(&inode,
-				full_path, inode->i_sb, xid);
+			rc = cifs_get_inode_info_unix(&inode, full_path,
+						      inode->i_sb, xid);
 		else
-			rc = cifs_get_inode_info(&inode,
-				full_path, NULL, inode->i_sb,
-				xid, NULL);
-	} /* else we are writing out data to server already
-	     and could deadlock if we tried to flush data, and
-	     since we do not know if we have data that would
-	     invalidate the current end of file on the server
-	     we can not go to the server to get the new inod
-	     info */
-
-	cifs_set_oplock_level(pCifsInode, oplock);
-
-	cifs_relock_file(pCifsFile);
+			rc = cifs_get_inode_info(&inode, full_path, NULL,
+						 inode->i_sb, xid, NULL);
+	}
+	/*
+	 * Else we are writing out data to server already and could deadlock if
+	 * we tried to flush data, and since we do not know if we have data that
+	 * would invalidate the current end of file on the server we can not go
+	 * to the server to get the new inode info.
+	 */
+
+	server->ops->set_fid(cfile, &fid, oplock);
+	cifs_relock_file(cfile);
 
 reopen_error_exit:
 	kfree(full_path);
-- 
1.7.1

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

* [PATCH 18/45] CIFS: Make flush code use ops struct
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (16 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 17/45] CIFS: Move reopen code to " Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
  2012-07-18 15:48   ` [PATCH 19/45] CIFS: Add SMB2 support for flush Pavel Shilovsky
                     ` (27 subsequent siblings)
  45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/cifsglob.h |    2 ++
 fs/cifs/file.c     |   20 ++++++++++++++++----
 fs/cifs/smb1ops.c  |    8 ++++++++
 3 files changed, 26 insertions(+), 4 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 0467e38..3d94397 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -274,6 +274,8 @@ struct smb_version_operations {
 	void (*set_fid)(struct cifsFileInfo *, struct cifs_fid *, __u32);
 	/* close a file */
 	int (*close)(const unsigned int, struct cifs_tcon *, struct cifs_fid *);
+	/* send a flush request to the server */
+	int (*flush)(const unsigned int, struct cifs_tcon *, struct cifs_fid *);
 };
 
 struct smb_version_values {
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index e8cca00..3f2cfb3 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -2055,6 +2055,7 @@ int cifs_strict_fsync(struct file *file, loff_t start, loff_t end,
 	unsigned int xid;
 	int rc = 0;
 	struct cifs_tcon *tcon;
+	struct TCP_Server_Info *server;
 	struct cifsFileInfo *smbfile = file->private_data;
 	struct inode *inode = file->f_path.dentry->d_inode;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
@@ -2078,8 +2079,13 @@ int cifs_strict_fsync(struct file *file, loff_t start, loff_t end,
 	}
 
 	tcon = tlink_tcon(smbfile->tlink);
-	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
-		rc = CIFSSMBFlush(xid, tcon, smbfile->fid.netfid);
+	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) {
+		server = tcon->ses->server;
+		if (server->ops->flush)
+			rc = server->ops->flush(xid, tcon, &smbfile->fid);
+		else
+			rc = -ENOSYS;
+	}
 
 	free_xid(xid);
 	mutex_unlock(&inode->i_mutex);
@@ -2091,6 +2097,7 @@ int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 	unsigned int xid;
 	int rc = 0;
 	struct cifs_tcon *tcon;
+	struct TCP_Server_Info *server;
 	struct cifsFileInfo *smbfile = file->private_data;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
 	struct inode *inode = file->f_mapping->host;
@@ -2106,8 +2113,13 @@ int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 		file->f_path.dentry->d_name.name, datasync);
 
 	tcon = tlink_tcon(smbfile->tlink);
-	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
-		rc = CIFSSMBFlush(xid, tcon, smbfile->fid.netfid);
+	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) {
+		server = tcon->ses->server;
+		if (server->ops->flush)
+			rc = server->ops->flush(xid, tcon, &smbfile->fid);
+		else
+			rc = -ENOSYS;
+	}
 
 	free_xid(xid);
 	mutex_unlock(&inode->i_mutex);
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index dd64754..df20dd9 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -648,6 +648,13 @@ cifs_close_file(const unsigned int xid, struct cifs_tcon *tcon,
 	return CIFSSMBClose(xid, tcon, fid->netfid);
 }
 
+static int
+cifs_flush_file(const unsigned int xid, struct cifs_tcon *tcon,
+		struct cifs_fid *fid)
+{
+	return CIFSSMBFlush(xid, tcon, fid->netfid);
+}
+
 struct smb_version_operations smb1_operations = {
 	.send_cancel = send_nt_cancel,
 	.compare_fids = cifs_compare_fids,
@@ -691,6 +698,7 @@ struct smb_version_operations smb1_operations = {
 	.open = cifs_open_file,
 	.set_fid = cifs_set_fid,
 	.close = cifs_close_file,
+	.flush = cifs_flush_file,
 };
 
 struct smb_version_values smb1_values = {
-- 
1.7.1

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

* [PATCH 19/45] CIFS: Add SMB2 support for flush
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (17 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 18/45] CIFS: Make flush code use " Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
  2012-07-18 15:48   ` [PATCH 20/45] CIFS: Move r/wsize negotiating to ops struct Pavel Shilovsky
                     ` (26 subsequent siblings)
  45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/smb2ops.c   |    8 ++++++++
 fs/cifs/smb2pdu.c   |   38 ++++++++++++++++++++++++++++++++++++++
 fs/cifs/smb2pdu.h   |   15 +++++++++++++++
 fs/cifs/smb2proto.h |    2 ++
 4 files changed, 63 insertions(+), 0 deletions(-)

diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 0fd5801..d81e1da 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -329,6 +329,13 @@ smb2_close_file(const unsigned int xid, struct cifs_tcon *tcon,
 	return SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid);
 }
 
+static int
+smb2_flush_file(const unsigned int xid, struct cifs_tcon *tcon,
+		struct cifs_fid *fid)
+{
+	return SMB2_flush(xid, tcon, fid->persistent_fid, fid->volatile_fid);
+}
+
 struct smb_version_operations smb21_operations = {
 	.setup_request = smb2_setup_request,
 	.setup_async_request = smb2_setup_async_request,
@@ -363,6 +370,7 @@ struct smb_version_operations smb21_operations = {
 	.open = smb2_open_file,
 	.set_fid = smb2_set_fid,
 	.close = smb2_close_file,
+	.flush = smb2_flush_file,
 };
 
 struct smb_version_values smb21_values = {
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 231e970..ff37406 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1152,3 +1152,41 @@ SMB2_echo(struct TCP_Server_Info *server)
 	cifs_small_buf_release(req);
 	return rc;
 }
+
+int
+SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
+	   u64 volatile_fid)
+{
+	struct smb2_flush_req *req;
+	struct TCP_Server_Info *server;
+	struct cifs_ses *ses = tcon->ses;
+	struct kvec iov[1];
+	int resp_buftype;
+	int rc = 0;
+
+	cFYI(1, "Flush");
+
+	if (ses && (ses->server))
+		server = ses->server;
+	else
+		return -EIO;
+
+	rc = small_smb2_init(SMB2_FLUSH, tcon, (void **) &req);
+	if (rc)
+		return rc;
+
+	req->PersistentFileId = persistent_fid;
+	req->VolatileFileId = volatile_fid;
+
+	iov[0].iov_base = (char *)req;
+	/* 4 for rfc1002 length field */
+	iov[0].iov_len = get_rfc1002_length(req) + 4;
+
+	rc = SendReceive2(xid, ses, iov, 1, &resp_buftype, 0);
+
+	if ((rc != 0) && tcon)
+		cifs_stats_fail_inc(tcon, SMB2_FLUSH_HE);
+
+	free_rsp_buf(resp_buftype, iov[0].iov_base);
+	return rc;
+}
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 7f1caff..af2c996 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -451,6 +451,21 @@ struct smb2_close_rsp {
 	__le32 Attributes;
 } __packed;
 
+struct smb2_flush_req {
+	struct smb2_hdr hdr;
+	__le16 StructureSize;	/* Must be 24 */
+	__le16 Reserved1;
+	__le32 Reserved2;
+	__u64  PersistentFileId; /* opaque endianness */
+	__u64  VolatileFileId; /* opaque endianness */
+} __packed;
+
+struct smb2_flush_rsp {
+	struct smb2_hdr hdr;
+	__le16 StructureSize;
+	__le16 Reserved;
+} __packed;
+
 struct smb2_echo_req {
 	struct smb2_hdr hdr;
 	__le16 StructureSize;	/* Must be 4 */
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 624d344..51e6cd1 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -89,6 +89,8 @@ extern int SMB2_open(const unsigned int xid, struct cifs_tcon *tcon,
 		     struct smb2_file_all_info *buf);
 extern int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
 		      u64 persistent_file_id, u64 volatile_file_id);
+extern int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon,
+		      u64 persistent_file_id, u64 volatile_file_id);
 extern int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
 			   u64 persistent_file_id, u64 volatile_file_id,
 			   struct smb2_file_all_info *data);
-- 
1.7.1

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

* [PATCH 20/45] CIFS: Move r/wsize negotiating to ops struct
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (18 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 19/45] CIFS: Add SMB2 support for flush Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
  2012-07-18 15:48   ` [PATCH 21/45] CIFS: Add SMB2 r/wsize negotiating Pavel Shilovsky
                     ` (25 subsequent siblings)
  45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

---
 fs/cifs/cifsglob.h |   61 ++++++++++++++++++++++
 fs/cifs/connect.c  |  144 +---------------------------------------------------
 fs/cifs/smb1ops.c  |   86 +++++++++++++++++++++++++++++++
 3 files changed, 149 insertions(+), 142 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 3d94397..797c17a 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -213,6 +213,10 @@ struct smb_version_operations {
 	bool (*need_neg)(struct TCP_Server_Info *);
 	/* negotiate to the server */
 	int (*negotiate)(const unsigned int, struct cifs_ses *);
+	/* set negotiated write size */
+	unsigned int (*negotiate_wsize)(struct cifs_tcon *, struct smb_vol *);
+	/* set negotiated read size */
+	unsigned int (*negotiate_rsize)(struct cifs_tcon *, struct smb_vol *);
 	/* setup smb sessionn */
 	int (*sess_setup)(const unsigned int, struct cifs_ses *,
 			  const struct nls_table *);
@@ -516,6 +520,63 @@ get_next_mid(struct TCP_Server_Info *server)
 }
 
 /*
+ * When the server supports very large reads and writes via POSIX extensions,
+ * we can allow up to 2^24-1, minus the size of a READ/WRITE_AND_X header, not
+ * including the RFC1001 length.
+ *
+ * Note that this might make for "interesting" allocation problems during
+ * writeback however as we have to allocate an array of pointers for the
+ * pages. A 16M write means ~32kb page array with PAGE_CACHE_SIZE == 4096.
+ *
+ * For reads, there is a similar problem as we need to allocate an array
+ * of kvecs to handle the receive, though that should only need to be done
+ * once.
+ */
+#define CIFS_MAX_WSIZE ((1<<24) - 1 - sizeof(WRITE_REQ) + 4)
+#define CIFS_MAX_RSIZE ((1<<24) - sizeof(READ_RSP) + 4)
+
+/*
+ * When the server doesn't allow large posix writes, only allow a rsize/wsize
+ * of 2^17-1 minus the size of the call header. That allows for a read or
+ * write up to the maximum size described by RFC1002.
+ */
+#define CIFS_MAX_RFC1002_WSIZE ((1<<17) - 1 - sizeof(WRITE_REQ) + 4)
+#define CIFS_MAX_RFC1002_RSIZE ((1<<17) - 1 - sizeof(READ_RSP) + 4)
+
+/*
+ * The default wsize is 1M. find_get_pages seems to return a maximum of 256
+ * pages in a single call. With PAGE_CACHE_SIZE == 4k, this means we can fill
+ * a single wsize request with a single call.
+ */
+#define CIFS_DEFAULT_IOSIZE (1024 * 1024)
+
+/*
+ * Windows only supports a max of 60kb reads and 65535 byte writes. Default to
+ * those values when posix extensions aren't in force. In actuality here, we
+ * use 65536 to allow for a write that is a multiple of 4k. Most servers seem
+ * to be ok with the extra byte even though Windows doesn't send writes that
+ * are that large.
+ *
+ * Citation:
+ *
+ * http://blogs.msdn.com/b/openspecification/archive/2009/04/10/smb-maximum-transmit-buffer-size-and-performance-tuning.aspx
+ */
+#define CIFS_DEFAULT_NON_POSIX_RSIZE (60 * 1024)
+#define CIFS_DEFAULT_NON_POSIX_WSIZE (65536)
+
+/*
+ * On hosts with high memory, we can't currently support wsize/rsize that are
+ * larger than we can kmap at once. Cap the rsize/wsize at
+ * LAST_PKMAP * PAGE_SIZE. We'll never be able to fill a read or write request
+ * larger than that anyway.
+ */
+#ifdef CONFIG_HIGHMEM
+#define CIFS_KMAP_SIZE_LIMIT   (LAST_PKMAP * PAGE_CACHE_SIZE)
+#else /* CONFIG_HIGHMEM */
+#define CIFS_KMAP_SIZE_LIMIT   (1<<24)
+#endif /* CONFIG_HIGHMEM */
+
+/*
  * Macros to allow the TCP_Server_Info->net field and related code to drop out
  * when CONFIG_NET_NS isn't set.
  */
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 99d50bf..bd4dcdd 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -3260,146 +3260,6 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
 			   "mount option supported");
 }
 
-/*
- * When the server supports very large reads and writes via POSIX extensions,
- * we can allow up to 2^24-1, minus the size of a READ/WRITE_AND_X header, not
- * including the RFC1001 length.
- *
- * Note that this might make for "interesting" allocation problems during
- * writeback however as we have to allocate an array of pointers for the
- * pages. A 16M write means ~32kb page array with PAGE_CACHE_SIZE == 4096.
- *
- * For reads, there is a similar problem as we need to allocate an array
- * of kvecs to handle the receive, though that should only need to be done
- * once.
- */
-#define CIFS_MAX_WSIZE ((1<<24) - 1 - sizeof(WRITE_REQ) + 4)
-#define CIFS_MAX_RSIZE ((1<<24) - sizeof(READ_RSP) + 4)
-
-/*
- * When the server doesn't allow large posix writes, only allow a rsize/wsize
- * of 2^17-1 minus the size of the call header. That allows for a read or
- * write up to the maximum size described by RFC1002.
- */
-#define CIFS_MAX_RFC1002_WSIZE ((1<<17) - 1 - sizeof(WRITE_REQ) + 4)
-#define CIFS_MAX_RFC1002_RSIZE ((1<<17) - 1 - sizeof(READ_RSP) + 4)
-
-/*
- * The default wsize is 1M. find_get_pages seems to return a maximum of 256
- * pages in a single call. With PAGE_CACHE_SIZE == 4k, this means we can fill
- * a single wsize request with a single call.
- */
-#define CIFS_DEFAULT_IOSIZE (1024 * 1024)
-
-/*
- * Windows only supports a max of 60kb reads and 65535 byte writes. Default to
- * those values when posix extensions aren't in force. In actuality here, we
- * use 65536 to allow for a write that is a multiple of 4k. Most servers seem
- * to be ok with the extra byte even though Windows doesn't send writes that
- * are that large.
- *
- * Citation:
- *
- * http://blogs.msdn.com/b/openspecification/archive/2009/04/10/smb-maximum-transmit-buffer-size-and-performance-tuning.aspx
- */
-#define CIFS_DEFAULT_NON_POSIX_RSIZE (60 * 1024)
-#define CIFS_DEFAULT_NON_POSIX_WSIZE (65536)
-
-/*
- * On hosts with high memory, we can't currently support wsize/rsize that are
- * larger than we can kmap at once. Cap the rsize/wsize at
- * LAST_PKMAP * PAGE_SIZE. We'll never be able to fill a read or write request
- * larger than that anyway.
- */
-#ifdef CONFIG_HIGHMEM
-#define CIFS_KMAP_SIZE_LIMIT	(LAST_PKMAP * PAGE_CACHE_SIZE)
-#else /* CONFIG_HIGHMEM */
-#define CIFS_KMAP_SIZE_LIMIT	(1<<24)
-#endif /* CONFIG_HIGHMEM */
-
-static unsigned int
-cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info)
-{
-	__u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
-	struct TCP_Server_Info *server = tcon->ses->server;
-	unsigned int wsize;
-
-	/* start with specified wsize, or default */
-	if (pvolume_info->wsize)
-		wsize = pvolume_info->wsize;
-	else if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_WRITE_CAP))
-		wsize = CIFS_DEFAULT_IOSIZE;
-	else
-		wsize = CIFS_DEFAULT_NON_POSIX_WSIZE;
-
-	/* can server support 24-bit write sizes? (via UNIX extensions) */
-	if (!tcon->unix_ext || !(unix_cap & CIFS_UNIX_LARGE_WRITE_CAP))
-		wsize = min_t(unsigned int, wsize, CIFS_MAX_RFC1002_WSIZE);
-
-	/*
-	 * no CAP_LARGE_WRITE_X or is signing enabled without CAP_UNIX set?
-	 * Limit it to max buffer offered by the server, minus the size of the
-	 * WRITEX header, not including the 4 byte RFC1001 length.
-	 */
-	if (!(server->capabilities & CAP_LARGE_WRITE_X) ||
-	    (!(server->capabilities & CAP_UNIX) &&
-	     (server->sec_mode & (SECMODE_SIGN_ENABLED|SECMODE_SIGN_REQUIRED))))
-		wsize = min_t(unsigned int, wsize,
-				server->maxBuf - sizeof(WRITE_REQ) + 4);
-
-	/* limit to the amount that we can kmap at once */
-	wsize = min_t(unsigned int, wsize, CIFS_KMAP_SIZE_LIMIT);
-
-	/* hard limit of CIFS_MAX_WSIZE */
-	wsize = min_t(unsigned int, wsize, CIFS_MAX_WSIZE);
-
-	return wsize;
-}
-
-static unsigned int
-cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info)
-{
-	__u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
-	struct TCP_Server_Info *server = tcon->ses->server;
-	unsigned int rsize, defsize;
-
-	/*
-	 * Set default value...
-	 *
-	 * HACK alert! Ancient servers have very small buffers. Even though
-	 * MS-CIFS indicates that servers are only limited by the client's
-	 * bufsize for reads, testing against win98se shows that it throws
-	 * INVALID_PARAMETER errors if you try to request too large a read.
-	 * OS/2 just sends back short reads.
-	 *
-	 * If the server doesn't advertise CAP_LARGE_READ_X, then assume that
-	 * it can't handle a read request larger than its MaxBufferSize either.
-	 */
-	if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_READ_CAP))
-		defsize = CIFS_DEFAULT_IOSIZE;
-	else if (server->capabilities & CAP_LARGE_READ_X)
-		defsize = CIFS_DEFAULT_NON_POSIX_RSIZE;
-	else
-		defsize = server->maxBuf - sizeof(READ_RSP);
-
-	rsize = pvolume_info->rsize ? pvolume_info->rsize : defsize;
-
-	/*
-	 * no CAP_LARGE_READ_X? Then MS-CIFS states that we must limit this to
-	 * the client's MaxBufferSize.
-	 */
-	if (!(server->capabilities & CAP_LARGE_READ_X))
-		rsize = min_t(unsigned int, CIFSMaxBufSize, rsize);
-
-	/* limit to the amount that we can kmap at once */
-	rsize = min_t(unsigned int, rsize, CIFS_KMAP_SIZE_LIMIT);
-
-	/* hard limit of CIFS_MAX_RSIZE */
-	rsize = min_t(unsigned int, rsize, CIFS_MAX_RSIZE);
-
-	return rsize;
-}
-
 static void
 cleanup_volume_info_contents(struct smb_vol *volume_info)
 {
@@ -3650,8 +3510,8 @@ try_mount_again:
 	if (!tcon->ipc && server->ops->qfs_tcon)
 		server->ops->qfs_tcon(xid, tcon);
 
-	cifs_sb->wsize = cifs_negotiate_wsize(tcon, volume_info);
-	cifs_sb->rsize = cifs_negotiate_rsize(tcon, volume_info);
+	cifs_sb->wsize = server->ops->negotiate_wsize(tcon, volume_info);
+	cifs_sb->rsize = server->ops->negotiate_rsize(tcon, volume_info);
 
 	/* tune readahead according to rsize */
 	cifs_sb->bdi.ra_pages = cifs_sb->rsize / PAGE_CACHE_SIZE;
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index df20dd9..7e8a2bd 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -17,6 +17,7 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+#include <linux/pagemap.h>
 #include "cifsglob.h"
 #include "cifsproto.h"
 #include "cifs_debug.h"
@@ -410,6 +411,89 @@ cifs_negotiate(const unsigned int xid, struct cifs_ses *ses)
 	return rc;
 }
 
+static unsigned int
+cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
+{
+	__u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
+	struct TCP_Server_Info *server = tcon->ses->server;
+	unsigned int wsize;
+
+	/* start with specified wsize, or default */
+	if (volume_info->wsize)
+		wsize = volume_info->wsize;
+	else if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_WRITE_CAP))
+		wsize = CIFS_DEFAULT_IOSIZE;
+	else
+		wsize = CIFS_DEFAULT_NON_POSIX_WSIZE;
+
+	/* can server support 24-bit write sizes? (via UNIX extensions) */
+	if (!tcon->unix_ext || !(unix_cap & CIFS_UNIX_LARGE_WRITE_CAP))
+		wsize = min_t(unsigned int, wsize, CIFS_MAX_RFC1002_WSIZE);
+
+	/*
+	 * no CAP_LARGE_WRITE_X or is signing enabled without CAP_UNIX set?
+	 * Limit it to max buffer offered by the server, minus the size of the
+	 * WRITEX header, not including the 4 byte RFC1001 length.
+	 */
+	if (!(server->capabilities & CAP_LARGE_WRITE_X) ||
+	    (!(server->capabilities & CAP_UNIX) &&
+	     (server->sec_mode & (SECMODE_SIGN_ENABLED|SECMODE_SIGN_REQUIRED))))
+		wsize = min_t(unsigned int, wsize,
+				server->maxBuf - sizeof(WRITE_REQ) + 4);
+
+	/* limit to the amount that we can kmap at once */
+	wsize = min_t(unsigned int, wsize, CIFS_KMAP_SIZE_LIMIT);
+
+	/* hard limit of CIFS_MAX_WSIZE */
+	wsize = min_t(unsigned int, wsize, CIFS_MAX_WSIZE);
+
+	return wsize;
+}
+
+static unsigned int
+cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
+{
+	__u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
+	struct TCP_Server_Info *server = tcon->ses->server;
+	unsigned int rsize, defsize;
+
+	/*
+	 * Set default value...
+	 *
+	 * HACK alert! Ancient servers have very small buffers. Even though
+	 * MS-CIFS indicates that servers are only limited by the client's
+	 * bufsize for reads, testing against win98se shows that it throws
+	 * INVALID_PARAMETER errors if you try to request too large a read.
+	 * OS/2 just sends back short reads.
+	 *
+	 * If the server doesn't advertise CAP_LARGE_READ_X, then assume that
+	 * it can't handle a read request larger than its MaxBufferSize either.
+	 */
+	if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_READ_CAP))
+		defsize = CIFS_DEFAULT_IOSIZE;
+	else if (server->capabilities & CAP_LARGE_READ_X)
+		defsize = CIFS_DEFAULT_NON_POSIX_RSIZE;
+	else
+		defsize = server->maxBuf - sizeof(READ_RSP);
+
+	rsize = volume_info->rsize ? volume_info->rsize : defsize;
+
+	/*
+	 * no CAP_LARGE_READ_X? Then MS-CIFS states that we must limit this to
+	 * the client's MaxBufferSize.
+	 */
+	if (!(server->capabilities & CAP_LARGE_READ_X))
+		rsize = min_t(unsigned int, CIFSMaxBufSize, rsize);
+
+	/* limit to the amount that we can kmap at once */
+	rsize = min_t(unsigned int, rsize, CIFS_KMAP_SIZE_LIMIT);
+
+	/* hard limit of CIFS_MAX_RSIZE */
+	rsize = min_t(unsigned int, rsize, CIFS_MAX_RSIZE);
+
+	return rsize;
+}
+
 static void
 cifs_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon)
 {
@@ -678,6 +762,8 @@ struct smb_version_operations smb1_operations = {
 	.check_trans2 = cifs_check_trans2,
 	.need_neg = cifs_need_neg,
 	.negotiate = cifs_negotiate,
+	.negotiate_wsize = cifs_negotiate_wsize,
+	.negotiate_rsize = cifs_negotiate_rsize,
 	.sess_setup = CIFS_SessSetup,
 	.logoff = CIFSSMBLogoff,
 	.tree_connect = CIFSTCon,
-- 
1.7.1

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

* [PATCH 21/45] CIFS: Add SMB2 r/wsize negotiating
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (19 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 20/45] CIFS: Move r/wsize negotiating to ops struct Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
  2012-07-18 15:48   ` [PATCH 22/45] CIFS: Move async read to ops struct Pavel Shilovsky
                     ` (24 subsequent siblings)
  45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

---
 fs/cifs/smb2ops.c |   36 ++++++++++++++++++++++++++++++++++++
 1 files changed, 36 insertions(+), 0 deletions(-)

diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index d81e1da..c0997ad 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -157,6 +157,40 @@ smb2_negotiate(const unsigned int xid, struct cifs_ses *ses)
 	return rc;
 }
 
+static unsigned int
+smb2_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
+{
+	struct TCP_Server_Info *server = tcon->ses->server;
+	unsigned int wsize;
+
+	/* start with specified wsize, or default */
+	wsize = volume_info->wsize ? volume_info->wsize : CIFS_DEFAULT_IOSIZE;
+	wsize = min_t(unsigned int, wsize, server->max_write);
+	/*
+	 * limit write size to 2 ** 16, because we don't support multicredit
+	 * requests now.
+	 */
+	wsize = min_t(unsigned int, wsize, 2 << 15);
+	return wsize;
+}
+
+static unsigned int
+smb2_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
+{
+	struct TCP_Server_Info *server = tcon->ses->server;
+	unsigned int rsize;
+
+	/* start with specified rsize, or default */
+	rsize = volume_info->rsize ? volume_info->rsize : CIFS_DEFAULT_IOSIZE;
+	rsize = min_t(unsigned int, rsize, server->max_read);
+	/*
+	 * limit write size to 2 ** 16, because we don't support multicredit
+	 * requests now.
+	 */
+	rsize = min_t(unsigned int, rsize, 2 << 15);
+	return rsize;
+}
+
 static int
 smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
 			struct cifs_sb_info *cifs_sb, const char *full_path)
@@ -352,6 +386,8 @@ struct smb_version_operations smb21_operations = {
 	.print_stats = smb2_print_stats,
 	.need_neg = smb2_need_neg,
 	.negotiate = smb2_negotiate,
+	.negotiate_wsize = smb2_negotiate_wsize,
+	.negotiate_rsize = smb2_negotiate_rsize,
 	.sess_setup = SMB2_sess_setup,
 	.logoff = SMB2_logoff,
 	.tree_connect = SMB2_tcon,
-- 
1.7.1

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

* [PATCH 22/45] CIFS: Move async read to ops struct
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (20 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 21/45] CIFS: Add SMB2 r/wsize negotiating Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
  2012-07-18 15:48   ` [PATCH 23/45] CIFS: Add SMB2 support for cifs_iovec_read Pavel Shilovsky
                     ` (23 subsequent siblings)
  45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/cifsglob.h     |    3 +++
 fs/cifs/file.c         |    8 +++++++-
 fs/cifs/smb1ops.c      |    1 +
 fs/cifs/smb2maperror.c |    3 ++-
 4 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 797c17a..e71ab49 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -172,6 +172,7 @@ struct dfs_info3_param;
 struct cifs_fattr;
 struct smb_vol;
 struct cifs_fid;
+struct cifs_readdata;
 
 struct smb_version_operations {
 	int (*send_cancel)(struct TCP_Server_Info *, void *,
@@ -280,6 +281,8 @@ struct smb_version_operations {
 	int (*close)(const unsigned int, struct cifs_tcon *, struct cifs_fid *);
 	/* send a flush request to the server */
 	int (*flush)(const unsigned int, struct cifs_tcon *, struct cifs_fid *);
+	/* async read from the server */
+	int (*async_readv)(struct cifs_readdata *);
 };
 
 struct smb_version_values {
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 3f2cfb3..81403ad 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -2481,6 +2481,9 @@ static int
 cifs_retry_async_readv(struct cifs_readdata *rdata)
 {
 	int rc;
+	struct TCP_Server_Info *server;
+
+	server = tlink_tcon(rdata->cfile->tlink)->ses->server;
 
 	do {
 		if (rdata->cfile->invalidHandle) {
@@ -2488,7 +2491,7 @@ cifs_retry_async_readv(struct cifs_readdata *rdata)
 			if (rc != 0)
 				continue;
 		}
-		rc = cifs_async_readv(rdata);
+		rc = server->ops->async_readv(rdata);
 	} while (rc == -EAGAIN);
 
 	return rc;
@@ -2640,6 +2643,9 @@ cifs_iovec_read(struct file *file, const struct iovec *iov,
 	open_file = file->private_data;
 	tcon = tlink_tcon(open_file->tlink);
 
+	if (!tcon->ses->server->ops->async_readv)
+		return -ENOSYS;
+
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
 		pid = open_file->pid;
 	else
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 7e8a2bd..e2dbd22 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -785,6 +785,7 @@ struct smb_version_operations smb1_operations = {
 	.set_fid = cifs_set_fid,
 	.close = cifs_close_file,
 	.flush = cifs_flush_file,
+	.async_readv = cifs_async_readv,
 };
 
 struct smb_version_values smb1_values = {
diff --git a/fs/cifs/smb2maperror.c b/fs/cifs/smb2maperror.c
index be41478..eaf5466 100644
--- a/fs/cifs/smb2maperror.c
+++ b/fs/cifs/smb2maperror.c
@@ -2455,7 +2455,8 @@ map_smb2_to_linux_error(char *buf, bool log_err)
 		return 0;
 
 	/* mask facility */
-	if (log_err && (smb2err != (STATUS_MORE_PROCESSING_REQUIRED)))
+	if (log_err && (smb2err != STATUS_MORE_PROCESSING_REQUIRED) &&
+	    (smb2err != STATUS_END_OF_FILE))
 		smb2_print_status(smb2err);
 	else if (cifsFYI & CIFS_RC)
 		smb2_print_status(smb2err);
-- 
1.7.1

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

* [PATCH 23/45] CIFS: Add SMB2 support for cifs_iovec_read
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (21 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 22/45] CIFS: Move async read to ops struct Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
  2012-07-18 15:48   ` [PATCH 24/45] CIFS: Move async write to ops struct Pavel Shilovsky
                     ` (22 subsequent siblings)
  45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/cifsglob.h  |   25 +++++++++
 fs/cifs/cifsproto.h |   20 +-------
 fs/cifs/cifssmb.c   |    2 +-
 fs/cifs/smb2glob.h  |    6 ++
 fs/cifs/smb2misc.c  |    3 +
 fs/cifs/smb2ops.c   |   19 +++++++
 fs/cifs/smb2pdu.c   |  136 +++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/cifs/smb2pdu.h   |   28 +++++++++++
 fs/cifs/smb2proto.h |    1 +
 9 files changed, 220 insertions(+), 20 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index e71ab49..9ce1353 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -857,12 +857,37 @@ struct cifsFileInfo {
 
 struct cifs_io_parms {
 	__u16 netfid;
+#ifdef CONFIG_CIFS_SMB2
+	__u64 persistent_fid;	/* persist file id for smb2 */
+	__u64 volatile_fid;	/* volatile file id for smb2 */
+#endif
 	__u32 pid;
 	__u64 offset;
 	unsigned int length;
 	struct cifs_tcon *tcon;
 };
 
+struct cifs_readdata;
+
+/* asynchronous read support */
+struct cifs_readdata {
+	struct kref			refcount;
+	struct list_head		list;
+	struct completion		done;
+	struct cifsFileInfo		*cfile;
+	struct address_space		*mapping;
+	__u64				offset;
+	unsigned int			bytes;
+	pid_t				pid;
+	int				result;
+	struct list_head		pages;
+	struct work_struct		work;
+	int (*marshal_iov) (struct cifs_readdata *rdata,
+			    unsigned int remaining);
+	unsigned int			nr_iov;
+	struct kvec			iov[1];
+};
+
 /*
  * Take a reference on the file private data. Must be called with
  * cifs_file_list_lock held.
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index c811f66..949be72 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -463,27 +463,9 @@ extern int E_md4hash(const unsigned char *passwd, unsigned char *p16,
 extern int SMBencrypt(unsigned char *passwd, const unsigned char *c8,
 			unsigned char *p24);
 
-/* asynchronous read support */
-struct cifs_readdata {
-	struct kref			refcount;
-	struct list_head		list;
-	struct completion		done;
-	struct cifsFileInfo		*cfile;
-	struct address_space		*mapping;
-	__u64				offset;
-	unsigned int			bytes;
-	pid_t				pid;
-	int				result;
-	struct list_head		pages;
-	struct work_struct		work;
-	int (*marshal_iov) (struct cifs_readdata *rdata,
-			    unsigned int remaining);
-	unsigned int			nr_iov;
-	struct kvec			iov[1];
-};
-
 void cifs_readdata_release(struct kref *refcount);
 int cifs_async_readv(struct cifs_readdata *rdata);
+int cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid);
 
 /* asynchronous write support */
 struct cifs_writedata {
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 2936875..e37801c 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -1440,7 +1440,7 @@ cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 	return 0;
 }
 
-static int
+int
 cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 {
 	int length, len;
diff --git a/fs/cifs/smb2glob.h b/fs/cifs/smb2glob.h
index 33c1d89..11505d7 100644
--- a/fs/cifs/smb2glob.h
+++ b/fs/cifs/smb2glob.h
@@ -41,4 +41,10 @@
 #define SMB2_OP_RENAME 6
 #define SMB2_OP_DELETE 7
 
+/* Used when constructing chained read requests. */
+#define CHAINED_REQUEST 1
+#define START_OF_CHAIN 2
+#define END_OF_CHAIN 4
+#define RELATED_REQUEST 8
+
 #endif	/* _SMB2_GLOB_H */
diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c
index a4ff5d5..cbb69e2 100644
--- a/fs/cifs/smb2misc.c
+++ b/fs/cifs/smb2misc.c
@@ -242,6 +242,9 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr)
 		    ((struct smb2_query_info_rsp *)hdr)->OutputBufferLength);
 		break;
 	case SMB2_READ:
+		*off = ((struct smb2_read_rsp *)hdr)->DataOffset;
+		*len = le32_to_cpu(((struct smb2_read_rsp *)hdr)->DataLength);
+		break;
 	case SMB2_QUERY_DIRECTORY:
 	case SMB2_IOCTL:
 	case SMB2_CHANGE_NOTIFY:
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index c0997ad..ba4adf2 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -370,6 +370,20 @@ smb2_flush_file(const unsigned int xid, struct cifs_tcon *tcon,
 	return SMB2_flush(xid, tcon, fid->persistent_fid, fid->volatile_fid);
 }
 
+static unsigned int
+smb2_read_data_offset(char *buf)
+{
+	struct smb2_read_rsp *rsp = (struct smb2_read_rsp *)buf;
+	return rsp->DataOffset;
+}
+
+static unsigned int
+smb2_read_data_length(char *buf)
+{
+	struct smb2_read_rsp *rsp = (struct smb2_read_rsp *)buf;
+	return le32_to_cpu(rsp->DataLength);
+}
+
 struct smb_version_operations smb21_operations = {
 	.setup_request = smb2_setup_request,
 	.setup_async_request = smb2_setup_async_request,
@@ -379,6 +393,9 @@ struct smb_version_operations smb21_operations = {
 	.get_credits_field = smb2_get_credits_field,
 	.get_credits = smb2_get_credits,
 	.get_next_mid = smb2_get_next_mid,
+	.read_data_offset = smb2_read_data_offset,
+	.read_data_length = smb2_read_data_length,
+	.map_error = map_smb2_to_linux_error,
 	.find_mid = smb2_find_mid,
 	.check_message = smb2_check_message,
 	.dump_detail = smb2_dump_detail,
@@ -407,12 +424,14 @@ struct smb_version_operations smb21_operations = {
 	.set_fid = smb2_set_fid,
 	.close = smb2_close_file,
 	.flush = smb2_flush_file,
+	.async_readv = smb2_async_readv,
 };
 
 struct smb_version_values smb21_values = {
 	.version_string = SMB21_VERSION_STRING,
 	.header_size = sizeof(struct smb2_hdr),
 	.max_header_size = MAX_SMB2_HDR_SIZE,
+	.read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
 	.lock_cmd = SMB2_LOCK,
 	.cap_unix = 0,
 	.cap_nt_find = SMB2_NT_FIND,
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index ff37406..69646ac 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -31,6 +31,7 @@
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/vfs.h>
+#include <linux/task_io_accounting_ops.h>
 #include <linux/uaccess.h>
 #include <linux/xattr.h>
 #include "smb2pdu.h"
@@ -42,6 +43,7 @@
 #include "cifs_debug.h"
 #include "ntlmssp.h"
 #include "smb2status.h"
+#include "smb2glob.h"
 
 /*
  *  The following table defines the expected "StructureSize" of SMB2 requests
@@ -1190,3 +1192,137 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
 	free_rsp_buf(resp_buftype, iov[0].iov_base);
 	return rc;
 }
+
+/*
+ * To form a chain of read requests, any read requests after the first should
+ * have the end_of_chain boolean set to true.
+ */
+static int
+smb2_new_read_req(struct kvec *iov, struct cifs_io_parms *io_parms,
+		  unsigned int remaining_bytes, int request_type)
+{
+	int rc = -EACCES;
+	struct smb2_read_req *req = NULL;
+
+	rc = small_smb2_init(SMB2_READ, io_parms->tcon, (void **) &req);
+	if (rc)
+		return rc;
+	if (io_parms->tcon->ses->server == NULL)
+		return -ECONNABORTED;
+
+	req->hdr.ProcessId = cpu_to_le32(io_parms->pid);
+
+	req->PersistentFileId = io_parms->persistent_fid;
+	req->VolatileFileId = io_parms->volatile_fid;
+	req->ReadChannelInfoOffset = 0; /* reserved */
+	req->ReadChannelInfoLength = 0; /* reserved */
+	req->Channel = 0; /* reserved */
+	req->MinimumCount = 0;
+	req->Length = cpu_to_le32(io_parms->length);
+	req->Offset = cpu_to_le64(io_parms->offset);
+
+	if (request_type & CHAINED_REQUEST) {
+		if (!(request_type & END_OF_CHAIN)) {
+			/* 4 for rfc1002 length field */
+			req->hdr.NextCommand =
+				cpu_to_le32(get_rfc1002_length(req) + 4);
+		} else /* END_OF_CHAIN */
+			req->hdr.NextCommand = 0;
+		if (request_type & RELATED_REQUEST) {
+			req->hdr.Flags |= SMB2_FLAGS_RELATED_OPERATIONS;
+			/*
+			 * Related requests use info from previous read request
+			 * in chain.
+			 */
+			req->hdr.SessionId = 0xFFFFFFFF;
+			req->hdr.TreeId = 0xFFFFFFFF;
+			req->PersistentFileId = 0xFFFFFFFF;
+			req->VolatileFileId = 0xFFFFFFFF;
+		}
+	}
+	if (remaining_bytes > io_parms->length)
+		req->RemainingBytes = cpu_to_le32(remaining_bytes);
+	else
+		req->RemainingBytes = 0;
+
+	iov[0].iov_base = (char *)req;
+	/* 4 for rfc1002 length field */
+	iov[0].iov_len = get_rfc1002_length(req) + 4;
+	return rc;
+}
+
+static void
+smb2_readv_callback(struct mid_q_entry *mid)
+{
+	struct cifs_readdata *rdata = mid->callback_data;
+	struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
+	struct TCP_Server_Info *server = tcon->ses->server;
+	struct smb2_hdr *buf = (struct smb2_hdr *)rdata->iov[0].iov_base;
+	unsigned int credits_received = 1;
+
+	cFYI(1, "%s: mid=%llu state=%d result=%d bytes=%u", __func__,
+		mid->mid, mid->mid_state, rdata->result, rdata->bytes);
+
+	switch (mid->mid_state) {
+	case MID_RESPONSE_RECEIVED:
+		credits_received = le16_to_cpu(buf->CreditRequest);
+		/* result already set, check signature */
+		/* if (server->sec_mode &
+		    (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+			if (smb2_verify_signature(mid->resp_buf, server))
+				cERROR(1, "Unexpected SMB signature"); */
+		/* FIXME: should this be counted toward the initiating task? */
+		task_io_account_read(rdata->bytes);
+		cifs_stats_bytes_read(tcon, rdata->bytes);
+		break;
+	case MID_REQUEST_SUBMITTED:
+	case MID_RETRY_NEEDED:
+		rdata->result = -EAGAIN;
+		break;
+	default:
+		rdata->result = -EIO;
+	}
+
+	if (rdata->result)
+		cifs_stats_fail_inc(tcon, SMB2_READ_HE);
+
+	queue_work(cifsiod_wq, &rdata->work);
+	DeleteMidQEntry(mid);
+	add_credits(server, credits_received, 0);
+}
+
+/* smb2_async_readv - send an async write, and set up mid to handle result */
+int
+smb2_async_readv(struct cifs_readdata *rdata)
+{
+	int rc;
+	struct smb2_hdr *buf;
+	struct cifs_io_parms io_parms;
+
+	cFYI(1, "%s: offset=%llu bytes=%u", __func__,
+		rdata->offset, rdata->bytes);
+
+	io_parms.tcon = tlink_tcon(rdata->cfile->tlink);
+	io_parms.offset = rdata->offset;
+	io_parms.length = rdata->bytes;
+	io_parms.persistent_fid = rdata->cfile->fid.persistent_fid;
+	io_parms.volatile_fid = rdata->cfile->fid.volatile_fid;
+	io_parms.pid = rdata->pid;
+	rc = smb2_new_read_req(&rdata->iov[0], &io_parms, 0, 0);
+	if (rc)
+		return rc;
+
+	buf = (struct smb2_hdr *)rdata->iov[0].iov_base;
+	/* 4 for rfc1002 length field */
+	rdata->iov[0].iov_len = get_rfc1002_length(rdata->iov[0].iov_base) + 4;
+
+	kref_get(&rdata->refcount);
+	rc = cifs_call_async(io_parms.tcon->ses->server, rdata->iov, 1,
+			     cifs_readv_receive, smb2_readv_callback,
+			     rdata, 0);
+	if (rc)
+		kref_put(&rdata->refcount, cifs_readdata_release);
+
+	cifs_small_buf_release(buf);
+	return rc;
+}
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index af2c996..d73367c 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -466,6 +466,34 @@ struct smb2_flush_rsp {
 	__le16 Reserved;
 } __packed;
 
+struct smb2_read_req {
+	struct smb2_hdr hdr;
+	__le16 StructureSize; /* Must be 49 */
+	__u8   Padding; /* offset from start of SMB2 header to place read */
+	__u8   Reserved;
+	__le32 Length;
+	__le64 Offset;
+	__u64  PersistentFileId; /* opaque endianness */
+	__u64  VolatileFileId; /* opaque endianness */
+	__le32 MinimumCount;
+	__le32 Channel; /* Reserved MBZ */
+	__le32 RemainingBytes;
+	__le16 ReadChannelInfoOffset; /* Reserved MBZ */
+	__le16 ReadChannelInfoLength; /* Reserved MBZ */
+	__u8   Buffer[1];
+} __packed;
+
+struct smb2_read_rsp {
+	struct smb2_hdr hdr;
+	__le16 StructureSize; /* Must be 17 */
+	__u8   DataOffset;
+	__u8   Reserved;
+	__le32 DataLength;
+	__le32 DataRemaining;
+	__u32  Reserved2;
+	__u8   Buffer[1];
+} __packed;
+
 struct smb2_echo_req {
 	struct smb2_hdr hdr;
 	__le16 StructureSize;	/* Must be 4 */
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 51e6cd1..f442e46 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -97,6 +97,7 @@ extern int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
 extern int SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon,
 			    u64 persistent_fid, u64 volatile_fid,
 			    __le64 *uniqueid);
+extern int smb2_async_readv(struct cifs_readdata *rdata);
 extern int SMB2_echo(struct TCP_Server_Info *server);
 
 #endif			/* _SMB2PROTO_H */
-- 
1.7.1

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

* [PATCH 24/45] CIFS: Move async write to ops struct
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (22 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 23/45] CIFS: Add SMB2 support for cifs_iovec_read Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
  2012-07-18 15:48   ` [PATCH 25/45] CIFS: Add SMB2 support for cifs_iovec_write Pavel Shilovsky
                     ` (21 subsequent siblings)
  45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/cifsglob.h |    3 +++
 fs/cifs/cifssmb.c  |    4 +++-
 fs/cifs/file.c     |   13 +++++++++++--
 fs/cifs/smb1ops.c  |    1 +
 4 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 9ce1353..61a013e 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -173,6 +173,7 @@ struct cifs_fattr;
 struct smb_vol;
 struct cifs_fid;
 struct cifs_readdata;
+struct cifs_writedata;
 
 struct smb_version_operations {
 	int (*send_cancel)(struct TCP_Server_Info *, void *,
@@ -283,6 +284,8 @@ struct smb_version_operations {
 	int (*flush)(const unsigned int, struct cifs_tcon *, struct cifs_fid *);
 	/* async read from the server */
 	int (*async_readv)(struct cifs_readdata *);
+	/* async write to the server */
+	int (*async_writev)(struct cifs_writedata *);
 };
 
 struct smb_version_values {
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index e37801c..715781a 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -1921,6 +1921,7 @@ cifs_writev_requeue(struct cifs_writedata *wdata)
 {
 	int i, rc;
 	struct inode *inode = wdata->cfile->dentry->d_inode;
+	struct TCP_Server_Info *server;
 
 	for (i = 0; i < wdata->nr_pages; i++) {
 		lock_page(wdata->pages[i]);
@@ -1928,7 +1929,8 @@ cifs_writev_requeue(struct cifs_writedata *wdata)
 	}
 
 	do {
-		rc = cifs_async_writev(wdata);
+		server = tlink_tcon(wdata->cfile->tlink)->ses->server;
+		rc = server->ops->async_writev(wdata);
 	} while (rc == -EAGAIN);
 
 	for (i = 0; i < wdata->nr_pages; i++) {
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 81403ad..fd2c8bb 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1747,6 +1747,7 @@ static int cifs_writepages(struct address_space *mapping,
 	bool done = false, scanned = false, range_whole = false;
 	pgoff_t end, index;
 	struct cifs_writedata *wdata;
+	struct TCP_Server_Info *server;
 	struct page *page;
 	int rc = 0;
 
@@ -1897,7 +1898,8 @@ retry:
 				break;
 			}
 			wdata->pid = wdata->cfile->pid;
-			rc = cifs_async_writev(wdata);
+			server = tlink_tcon(wdata->cfile->tlink)->ses->server;
+			rc = server->ops->async_writev(wdata);
 		} while (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN);
 
 		for (i = 0; i < nr_pages; ++i)
@@ -2228,6 +2230,9 @@ static int
 cifs_uncached_retry_writev(struct cifs_writedata *wdata)
 {
 	int rc;
+	struct TCP_Server_Info *server;
+
+	server = tlink_tcon(wdata->cfile->tlink)->ses->server;
 
 	do {
 		if (wdata->cfile->invalidHandle) {
@@ -2235,7 +2240,7 @@ cifs_uncached_retry_writev(struct cifs_writedata *wdata)
 			if (rc != 0)
 				continue;
 		}
-		rc = cifs_async_writev(wdata);
+		rc = server->ops->async_writev(wdata);
 	} while (rc == -EAGAIN);
 
 	return rc;
@@ -2270,6 +2275,10 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
 	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
 	open_file = file->private_data;
 	tcon = tlink_tcon(open_file->tlink);
+
+	if (!tcon->ses->server->ops->async_writev)
+		return -ENOSYS;
+
 	offset = *poffset;
 
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index e2dbd22..50c3697 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -786,6 +786,7 @@ struct smb_version_operations smb1_operations = {
 	.close = cifs_close_file,
 	.flush = cifs_flush_file,
 	.async_readv = cifs_async_readv,
+	.async_writev = cifs_async_writev,
 };
 
 struct smb_version_values smb1_values = {
-- 
1.7.1

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

* [PATCH 25/45] CIFS: Add SMB2 support for cifs_iovec_write
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (23 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 24/45] CIFS: Move async write to ops struct Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
  2012-07-18 15:48   ` [PATCH 26/45] CIFS: Move readpage code to ops struct Pavel Shilovsky
                     ` (20 subsequent siblings)
  45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/cifsfs.c    |    2 +
 fs/cifs/cifsglob.h  |   47 +++++++++++++++++++
 fs/cifs/cifsproto.h |   18 -------
 fs/cifs/cifssmb.c   |   26 -----------
 fs/cifs/smb2ops.c   |    1 +
 fs/cifs/smb2pdu.c   |  123 +++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/cifs/smb2pdu.h   |   30 ++++++++++++
 fs/cifs/smb2proto.h |    1 +
 8 files changed, 204 insertions(+), 44 deletions(-)

diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 54d8b13..65f8b05 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -89,6 +89,8 @@ extern mempool_t *cifs_mid_poolp;
 
 struct workqueue_struct	*cifsiod_wq;
 
+DEFINE_MUTEX(cifs_kmap_mutex);
+
 static int
 cifs_read_super(struct super_block *sb)
 {
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 61a013e..68eda60 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -582,6 +582,33 @@ get_next_mid(struct TCP_Server_Info *server)
 #define CIFS_KMAP_SIZE_LIMIT   (1<<24)
 #endif /* CONFIG_HIGHMEM */
 
+#ifdef CONFIG_HIGHMEM
+/*
+ * On arches that have high memory, kmap address space is limited. By
+ * serializing the kmap operations on those arches, we ensure that we don't
+ * end up with a bunch of threads in writeback with partially mapped page
+ * arrays, stuck waiting for kmap to come back. That situation prevents
+ * progress and can deadlock.
+ */
+
+extern struct mutex cifs_kmap_mutex;
+
+static inline void
+cifs_kmap_lock(void)
+{
+	mutex_lock(&cifs_kmap_mutex);
+}
+
+static inline void
+cifs_kmap_unlock(void)
+{
+	mutex_unlock(&cifs_kmap_mutex);
+}
+#else /* !CONFIG_HIGHMEM */
+#define cifs_kmap_lock() do { ; } while (0)
+#define cifs_kmap_unlock() do { ; } while (0)
+#endif /* CONFIG_HIGHMEM */
+
 /*
  * Macros to allow the TCP_Server_Info->net field and related code to drop out
  * when CONFIG_NET_NS isn't set.
@@ -891,6 +918,26 @@ struct cifs_readdata {
 	struct kvec			iov[1];
 };
 
+struct cifs_writedata;
+
+/* asynchronous write support */
+struct cifs_writedata {
+	struct kref			refcount;
+	struct list_head		list;
+	struct completion		done;
+	enum writeback_sync_modes	sync_mode;
+	struct work_struct		work;
+	struct cifsFileInfo		*cfile;
+	__u64				offset;
+	pid_t				pid;
+	unsigned int			bytes;
+	int				result;
+	void (*marshal_iov) (struct kvec *iov,
+			     struct cifs_writedata *wdata);
+	unsigned int			nr_pages;
+	struct page			*pages[1];
+};
+
 /*
  * Take a reference on the file private data. Must be called with
  * cifs_file_list_lock held.
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 949be72..01d5514 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -467,24 +467,6 @@ void cifs_readdata_release(struct kref *refcount);
 int cifs_async_readv(struct cifs_readdata *rdata);
 int cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid);
 
-/* asynchronous write support */
-struct cifs_writedata {
-	struct kref			refcount;
-	struct list_head		list;
-	struct completion		done;
-	enum writeback_sync_modes	sync_mode;
-	struct work_struct		work;
-	struct cifsFileInfo		*cfile;
-	__u64				offset;
-	pid_t				pid;
-	unsigned int			bytes;
-	int				result;
-	void (*marshal_iov) (struct kvec *iov,
-			     struct cifs_writedata *wdata);
-	unsigned int			nr_pages;
-	struct page			*pages[1];
-};
-
 int cifs_async_writev(struct cifs_writedata *wdata);
 void cifs_writev_complete(struct work_struct *work);
 struct cifs_writedata *cifs_writedata_alloc(unsigned int nr_pages,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 715781a..d27c8be 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -86,32 +86,6 @@ static struct {
 #endif /* CONFIG_CIFS_WEAK_PW_HASH */
 #endif /* CIFS_POSIX */
 
-#ifdef CONFIG_HIGHMEM
-/*
- * On arches that have high memory, kmap address space is limited. By
- * serializing the kmap operations on those arches, we ensure that we don't
- * end up with a bunch of threads in writeback with partially mapped page
- * arrays, stuck waiting for kmap to come back. That situation prevents
- * progress and can deadlock.
- */
-static DEFINE_MUTEX(cifs_kmap_mutex);
-
-static inline void
-cifs_kmap_lock(void)
-{
-	mutex_lock(&cifs_kmap_mutex);
-}
-
-static inline void
-cifs_kmap_unlock(void)
-{
-	mutex_unlock(&cifs_kmap_mutex);
-}
-#else /* !CONFIG_HIGHMEM */
-#define cifs_kmap_lock() do { ; } while(0)
-#define cifs_kmap_unlock() do { ; } while(0)
-#endif /* CONFIG_HIGHMEM */
-
 /*
  * Mark as invalid, all open files on tree connections since they
  * were closed when session to server was lost.
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index ba4adf2..74e8bce 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -425,6 +425,7 @@ struct smb_version_operations smb21_operations = {
 	.close = smb2_close_file,
 	.flush = smb2_flush_file,
 	.async_readv = smb2_async_readv,
+	.async_writev = smb2_async_writev,
 };
 
 struct smb_version_values smb21_values = {
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 69646ac..c998fbe 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -33,6 +33,7 @@
 #include <linux/vfs.h>
 #include <linux/task_io_accounting_ops.h>
 #include <linux/uaccess.h>
+#include <linux/pagemap.h>
 #include <linux/xattr.h>
 #include "smb2pdu.h"
 #include "cifsglob.h"
@@ -1326,3 +1327,125 @@ smb2_async_readv(struct cifs_readdata *rdata)
 	cifs_small_buf_release(buf);
 	return rc;
 }
+
+/*
+ * Check the mid_state and signature on received buffer (if any), and queue the
+ * workqueue completion task.
+ */
+static void
+smb2_writev_callback(struct mid_q_entry *mid)
+{
+	struct cifs_writedata *wdata = mid->callback_data;
+	struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
+	unsigned int written;
+	struct smb2_write_rsp *rsp = (struct smb2_write_rsp *)mid->resp_buf;
+	unsigned int credits_received = 1;
+
+	switch (mid->mid_state) {
+	case MID_RESPONSE_RECEIVED:
+		credits_received = le16_to_cpu(rsp->hdr.CreditRequest);
+		wdata->result = smb2_check_receive(mid, tcon->ses->server, 0);
+		if (wdata->result != 0)
+			break;
+
+		written = le32_to_cpu(rsp->DataLength);
+		/*
+		 * Mask off high 16 bits when bytes written as returned
+		 * by the server is greater than bytes requested by the
+		 * client. OS/2 servers are known to set incorrect
+		 * CountHigh values.
+		 */
+		if (written > wdata->bytes)
+			written &= 0xFFFF;
+
+		if (written < wdata->bytes)
+			wdata->result = -ENOSPC;
+		else
+			wdata->bytes = written;
+		break;
+	case MID_REQUEST_SUBMITTED:
+	case MID_RETRY_NEEDED:
+		wdata->result = -EAGAIN;
+		break;
+	default:
+		wdata->result = -EIO;
+		break;
+	}
+
+	if (wdata->result)
+		cifs_stats_fail_inc(tcon, SMB2_WRITE_HE);
+
+	queue_work(cifsiod_wq, &wdata->work);
+	DeleteMidQEntry(mid);
+	add_credits(tcon->ses->server, credits_received, 0);
+}
+
+/* smb2_async_writev - send an async write, and set up mid to handle result */
+int
+smb2_async_writev(struct cifs_writedata *wdata)
+{
+	int i, rc = -EACCES;
+	struct smb2_write_req *req = NULL;
+	struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
+	struct kvec *iov = NULL;
+
+	rc = small_smb2_init(SMB2_WRITE, tcon, (void **) &req);
+	if (rc)
+		goto async_writev_out;
+
+	/* 1 iov per page + 1 for header */
+	iov = kzalloc((wdata->nr_pages + 1) * sizeof(*iov), GFP_NOFS);
+	if (iov == NULL) {
+		rc = -ENOMEM;
+		goto async_writev_out;
+	}
+
+	req->hdr.ProcessId = cpu_to_le32(wdata->cfile->pid);
+
+	req->PersistentFileId = wdata->cfile->fid.persistent_fid;
+	req->VolatileFileId = wdata->cfile->fid.volatile_fid;
+	req->WriteChannelInfoOffset = 0;
+	req->WriteChannelInfoLength = 0;
+	req->Channel = 0;
+	req->Offset = cpu_to_le64(wdata->offset);
+	/* 4 for rfc1002 length field */
+	req->DataOffset = cpu_to_le16(
+				offsetof(struct smb2_write_req, Buffer) - 4);
+	req->RemainingBytes = 0;
+
+	/* 4 for rfc1002 length field and 1 for Buffer */
+	iov[0].iov_len = get_rfc1002_length(req) + 4 - 1;
+	iov[0].iov_base = (char *)req;
+
+	/*
+	 * This function should marshal up the page array into the kvec
+	 * array, reserving [0] for the header. It should kmap the pages
+	 * and set the iov_len properly for each one. It may also set
+	 * wdata->bytes too.
+	 */
+	cifs_kmap_lock();
+	wdata->marshal_iov(iov, wdata);
+	cifs_kmap_unlock();
+
+	cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
+
+	req->Length = cpu_to_le32(wdata->bytes);
+
+	inc_rfc1001_len(&req->hdr, wdata->bytes - 1 /* Buffer */);
+
+	kref_get(&wdata->refcount);
+	rc = cifs_call_async(tcon->ses->server, iov, wdata->nr_pages + 1,
+			     NULL, smb2_writev_callback, wdata, 0);
+
+	if (rc)
+		kref_put(&wdata->refcount, cifs_writedata_release);
+
+	/* send is done, unmap pages */
+	for (i = 0; i < wdata->nr_pages; i++)
+		kunmap(wdata->pages[i]);
+
+async_writev_out:
+	cifs_small_buf_release(req);
+	kfree(iov);
+	return rc;
+}
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index d73367c..4712273 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -494,6 +494,36 @@ struct smb2_read_rsp {
 	__u8   Buffer[1];
 } __packed;
 
+/* For write request Flags field below the following flag is defined: */
+#define SMB2_WRITEFLAG_WRITE_THROUGH 0x00000001
+
+struct smb2_write_req {
+	struct smb2_hdr hdr;
+	__le16 StructureSize; /* Must be 49 */
+	__le16 DataOffset; /* offset from start of SMB2 header to write data */
+	__le32 Length;
+	__le64 Offset;
+	__u64  PersistentFileId; /* opaque endianness */
+	__u64  VolatileFileId; /* opaque endianness */
+	__le32 Channel; /* Reserved MBZ */
+	__le32 RemainingBytes;
+	__le16 WriteChannelInfoOffset; /* Reserved MBZ */
+	__le16 WriteChannelInfoLength; /* Reserved MBZ */
+	__le32 Flags;
+	__u8   Buffer[1];
+} __packed;
+
+struct smb2_write_rsp {
+	struct smb2_hdr hdr;
+	__le16 StructureSize; /* Must be 17 */
+	__u8   DataOffset;
+	__u8   Reserved;
+	__le32 DataLength;
+	__le32 DataRemaining;
+	__u32  Reserved2;
+	__u8   Buffer[1];
+} __packed;
+
 struct smb2_echo_req {
 	struct smb2_hdr hdr;
 	__le16 StructureSize;	/* Must be 4 */
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index f442e46..ec983be 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -98,6 +98,7 @@ extern int SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon,
 			    u64 persistent_fid, u64 volatile_fid,
 			    __le64 *uniqueid);
 extern int smb2_async_readv(struct cifs_readdata *rdata);
+extern int smb2_async_writev(struct cifs_writedata *wdata);
 extern int SMB2_echo(struct TCP_Server_Info *server);
 
 #endif			/* _SMB2PROTO_H */
-- 
1.7.1

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

* [PATCH 26/45] CIFS: Move readpage code to ops struct
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (24 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 25/45] CIFS: Add SMB2 support for cifs_iovec_write Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
  2012-07-18 15:48   ` [PATCH 27/45] CIFS: Add readpage support for SMB2 Pavel Shilovsky
                     ` (19 subsequent siblings)
  45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/cifsglob.h |    5 +++++
 fs/cifs/file.c     |   28 +++++++++++++++++-----------
 fs/cifs/smb1ops.c  |   10 ++++++++++
 3 files changed, 32 insertions(+), 11 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 68eda60..222d865 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -174,6 +174,7 @@ struct smb_vol;
 struct cifs_fid;
 struct cifs_readdata;
 struct cifs_writedata;
+struct cifs_io_parms;
 
 struct smb_version_operations {
 	int (*send_cancel)(struct TCP_Server_Info *, void *,
@@ -286,6 +287,10 @@ struct smb_version_operations {
 	int (*async_readv)(struct cifs_readdata *);
 	/* async write to the server */
 	int (*async_writev)(struct cifs_writedata *);
+	/* sync read from the server */
+	int (*sync_read)(const unsigned int, struct cifsFileInfo *,
+			 struct cifs_io_parms *, unsigned int *, char **,
+			 int *);
 };
 
 struct smb_version_values {
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index fd2c8bb..6b92bbe 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -2771,8 +2771,8 @@ ssize_t cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov,
 	return cifs_user_readv(iocb, iov, nr_segs, pos);
 }
 
-static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
-			 loff_t *poffset)
+static ssize_t
+cifs_read(struct file *file, char *read_data, size_t read_size, loff_t *offset)
 {
 	int rc = -EACCES;
 	unsigned int bytes_read = 0;
@@ -2781,8 +2781,9 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
 	unsigned int rsize;
 	struct cifs_sb_info *cifs_sb;
 	struct cifs_tcon *tcon;
+	struct TCP_Server_Info *server;
 	unsigned int xid;
-	char *current_offset;
+	char *cur_offset;
 	struct cifsFileInfo *open_file;
 	struct cifs_io_parms io_parms;
 	int buf_type = CIFS_NO_BUFFER;
@@ -2801,6 +2802,12 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
 	}
 	open_file = file->private_data;
 	tcon = tlink_tcon(open_file->tlink);
+	server = tcon->ses->server;
+
+	if (!server->ops->sync_read) {
+		free_xid(xid);
+		return -ENOSYS;
+	}
 
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
 		pid = open_file->pid;
@@ -2810,9 +2817,8 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
 	if ((file->f_flags & O_ACCMODE) == O_WRONLY)
 		cFYI(1, "attempting read on write only file instance");
 
-	for (total_read = 0, current_offset = read_data;
-	     read_size > total_read;
-	     total_read += bytes_read, current_offset += bytes_read) {
+	for (total_read = 0, cur_offset = read_data; read_size > total_read;
+	     total_read += bytes_read, cur_offset += bytes_read) {
 		current_read_size = min_t(uint, read_size - total_read, rsize);
 		/*
 		 * For windows me and 9x we do not want to request more than it
@@ -2830,13 +2836,13 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
 				if (rc != 0)
 					break;
 			}
-			io_parms.netfid = open_file->fid.netfid;
 			io_parms.pid = pid;
 			io_parms.tcon = tcon;
-			io_parms.offset = *poffset;
+			io_parms.offset = *offset;
 			io_parms.length = current_read_size;
-			rc = CIFSSMBRead(xid, &io_parms, &bytes_read,
-					 &current_offset, &buf_type);
+			rc = server->ops->sync_read(xid, open_file, &io_parms,
+						    &bytes_read, &cur_offset,
+						    &buf_type);
 		}
 		if (rc || (bytes_read == 0)) {
 			if (total_read) {
@@ -2847,7 +2853,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
 			}
 		} else {
 			cifs_stats_bytes_read(tcon, total_read);
-			*poffset += bytes_read;
+			*offset += bytes_read;
 		}
 	}
 	free_xid(xid);
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 50c3697..cea958e 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -739,6 +739,15 @@ cifs_flush_file(const unsigned int xid, struct cifs_tcon *tcon,
 	return CIFSSMBFlush(xid, tcon, fid->netfid);
 }
 
+static int
+cifs_sync_read(const unsigned int xid, struct cifsFileInfo *cfile,
+	       struct cifs_io_parms *parms, unsigned int *bytes_read,
+	       char **buf, int *buf_type)
+{
+	parms->netfid = cfile->fid.netfid;
+	return CIFSSMBRead(xid, parms, bytes_read, buf, buf_type);
+}
+
 struct smb_version_operations smb1_operations = {
 	.send_cancel = send_nt_cancel,
 	.compare_fids = cifs_compare_fids,
@@ -787,6 +796,7 @@ struct smb_version_operations smb1_operations = {
 	.flush = cifs_flush_file,
 	.async_readv = cifs_async_readv,
 	.async_writev = cifs_async_writev,
+	.sync_read = cifs_sync_read,
 };
 
 struct smb_version_values smb1_values = {
-- 
1.7.1

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

* [PATCH 27/45] CIFS: Add readpage support for SMB2
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (25 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 26/45] CIFS: Move readpage code to ops struct Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
  2012-07-18 15:48   ` [PATCH 28/45] CIFS: Move writepage to ops struct Pavel Shilovsky
                     ` (18 subsequent siblings)
  45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/smb2ops.c   |   12 ++++++++++++
 fs/cifs/smb2pdu.c   |   51 +++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/cifs/smb2proto.h |    2 ++
 3 files changed, 65 insertions(+), 0 deletions(-)

diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 74e8bce..4dca13d 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -384,6 +384,17 @@ smb2_read_data_length(char *buf)
 	return le32_to_cpu(rsp->DataLength);
 }
 
+
+static int
+smb2_sync_read(const unsigned int xid, struct cifsFileInfo *cfile,
+	       struct cifs_io_parms *parms, unsigned int *bytes_read,
+	       char **buf, int *buf_type)
+{
+	parms->persistent_fid = cfile->fid.persistent_fid;
+	parms->volatile_fid = cfile->fid.volatile_fid;
+	return SMB2_read(xid, parms, bytes_read, buf, buf_type);
+}
+
 struct smb_version_operations smb21_operations = {
 	.setup_request = smb2_setup_request,
 	.setup_async_request = smb2_setup_async_request,
@@ -426,6 +437,7 @@ struct smb_version_operations smb21_operations = {
 	.flush = smb2_flush_file,
 	.async_readv = smb2_async_readv,
 	.async_writev = smb2_async_writev,
+	.sync_read = smb2_sync_read,
 };
 
 struct smb_version_values smb21_values = {
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index c998fbe..15b9b08 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1328,6 +1328,57 @@ smb2_async_readv(struct cifs_readdata *rdata)
 	return rc;
 }
 
+int
+SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
+	  unsigned int *nbytes, char **buf, int *buf_type)
+{
+	int resp_buftype, rc = -EACCES;
+	struct smb2_read_rsp *rsp = NULL;
+	struct kvec iov[1];
+
+	*nbytes = 0;
+	rc = smb2_new_read_req(iov, io_parms, 0, 0);
+	if (rc)
+		return rc;
+
+	rc = SendReceive2(xid, io_parms->tcon->ses, iov, 1,
+			  &resp_buftype, CIFS_LOG_ERROR);
+
+	rsp = (struct smb2_read_rsp *)iov[0].iov_base;
+
+	if (rsp->hdr.Status == STATUS_END_OF_FILE) {
+		free_rsp_buf(resp_buftype, iov[0].iov_base);
+		return 0;
+	}
+
+	if (rc) {
+		cifs_stats_fail_inc(io_parms->tcon, SMB2_READ_HE);
+		cERROR(1, "Send error in read = %d", rc);
+	} else {
+		*nbytes = le32_to_cpu(rsp->DataLength);
+		if ((*nbytes > CIFS_MAX_MSGSIZE) ||
+		    (*nbytes > io_parms->length)) {
+			cFYI(1, "bad length %d for count %d", *nbytes,
+				io_parms->length);
+			rc = -EIO;
+			*nbytes = 0;
+		}
+	}
+
+	if (*buf) {
+		memcpy(*buf, (char *)rsp->hdr.ProtocolId + rsp->DataOffset,
+		       *nbytes);
+		free_rsp_buf(resp_buftype, iov[0].iov_base);
+	} else if (resp_buftype != CIFS_NO_BUFFER) {
+		*buf = iov[0].iov_base;
+		if (resp_buftype == CIFS_SMALL_BUFFER)
+			*buf_type = CIFS_SMALL_BUFFER;
+		else if (resp_buftype == CIFS_LARGE_BUFFER)
+			*buf_type = CIFS_LARGE_BUFFER;
+	}
+	return rc;
+}
+
 /*
  * Check the mid_state and signature on received buffer (if any), and queue the
  * workqueue completion task.
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index ec983be..97e62f3 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -98,6 +98,8 @@ extern int SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon,
 			    u64 persistent_fid, u64 volatile_fid,
 			    __le64 *uniqueid);
 extern int smb2_async_readv(struct cifs_readdata *rdata);
+extern int SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
+		     unsigned int *nbytes, char **buf, int *buf_type);
 extern int smb2_async_writev(struct cifs_writedata *wdata);
 extern int SMB2_echo(struct TCP_Server_Info *server);
 
-- 
1.7.1

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

* [PATCH 28/45] CIFS: Move writepage to ops struct
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (26 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 27/45] CIFS: Add readpage support for SMB2 Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
  2012-07-18 15:48   ` [PATCH 29/45] CIFS: Add writepage support for SMB2 Pavel Shilovsky
                     ` (17 subsequent siblings)
  45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/cifsglob.h  |    4 ++++
 fs/cifs/cifsproto.h |    3 +--
 fs/cifs/cifssmb.c   |    6 ++----
 fs/cifs/file.c      |   36 ++++++++++++++++++++----------------
 fs/cifs/smb1ops.c   |   11 +++++++++++
 5 files changed, 38 insertions(+), 22 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 222d865..3e54b19 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -291,6 +291,10 @@ struct smb_version_operations {
 	int (*sync_read)(const unsigned int, struct cifsFileInfo *,
 			 struct cifs_io_parms *, unsigned int *, char **,
 			 int *);
+	/* sync write to the server */
+	int (*sync_write)(const unsigned int, struct cifsFileInfo *,
+			  struct cifs_io_parms *, unsigned int *, struct kvec *,
+			  unsigned long);
 };
 
 struct smb_version_values {
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 01d5514..bdf8948 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -369,8 +369,7 @@ extern int CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
 			unsigned int *nbytes, const char *buf,
 			const char __user *ubuf, const int long_op);
 extern int CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
-			unsigned int *nbytes, struct kvec *iov, const int nvec,
-			const int long_op);
+			unsigned int *nbytes, struct kvec *iov, const int nvec);
 extern int CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
 				 const char *search_name, __u64 *inode_number,
 				 const struct nls_table *nls_codepage,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index d27c8be..666535c 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -2118,8 +2118,7 @@ async_writev_out:
 
 int
 CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
-	      unsigned int *nbytes, struct kvec *iov, int n_vec,
-	      const int long_op)
+	      unsigned int *nbytes, struct kvec *iov, int n_vec)
 {
 	int rc = -EACCES;
 	WRITE_REQ *pSMB = NULL;
@@ -2190,8 +2189,7 @@ CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
 		iov[0].iov_len = smb_hdr_len + 8;
 
 
-	rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
-			  long_op);
+	rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0);
 	cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
 	if (rc) {
 		cFYI(1, "Send error Write2 = %d", rc);
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 6b92bbe..2ffee05 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1470,15 +1470,16 @@ cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
 		cifsi->server_eof = end_of_write;
 }
 
-static ssize_t cifs_write(struct cifsFileInfo *open_file, __u32 pid,
-			  const char *write_data, size_t write_size,
-			  loff_t *poffset)
+static ssize_t
+cifs_write(struct cifsFileInfo *open_file, __u32 pid, const char *write_data,
+	   size_t write_size, loff_t *offset)
 {
 	int rc = 0;
 	unsigned int bytes_written = 0;
 	unsigned int total_written;
 	struct cifs_sb_info *cifs_sb;
-	struct cifs_tcon *pTcon;
+	struct cifs_tcon *tcon;
+	struct TCP_Server_Info *server;
 	unsigned int xid;
 	struct dentry *dentry = open_file->dentry;
 	struct cifsInodeInfo *cifsi = CIFS_I(dentry->d_inode);
@@ -1487,9 +1488,13 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, __u32 pid,
 	cifs_sb = CIFS_SB(dentry->d_sb);
 
 	cFYI(1, "write %zd bytes to offset %lld of %s", write_size,
-	   *poffset, dentry->d_name.name);
+	     *offset, dentry->d_name.name);
+
+	tcon = tlink_tcon(open_file->tlink);
+	server = tcon->ses->server;
 
-	pTcon = tlink_tcon(open_file->tlink);
+	if (!server->ops->sync_write)
+		return -ENOSYS;
 
 	xid = get_xid();
 
@@ -1515,13 +1520,12 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, __u32 pid,
 			/* iov[0] is reserved for smb header */
 			iov[1].iov_base = (char *)write_data + total_written;
 			iov[1].iov_len = len;
-			io_parms.netfid = open_file->fid.netfid;
 			io_parms.pid = pid;
-			io_parms.tcon = pTcon;
-			io_parms.offset = *poffset;
+			io_parms.tcon = tcon;
+			io_parms.offset = *offset;
 			io_parms.length = len;
-			rc = CIFSSMBWrite2(xid, &io_parms, &bytes_written, iov,
-					   1, 0);
+			rc = server->ops->sync_write(xid, open_file, &io_parms,
+						     &bytes_written, iov, 1);
 		}
 		if (rc || (bytes_written == 0)) {
 			if (total_written)
@@ -1532,18 +1536,18 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, __u32 pid,
 			}
 		} else {
 			spin_lock(&dentry->d_inode->i_lock);
-			cifs_update_eof(cifsi, *poffset, bytes_written);
+			cifs_update_eof(cifsi, *offset, bytes_written);
 			spin_unlock(&dentry->d_inode->i_lock);
-			*poffset += bytes_written;
+			*offset += bytes_written;
 		}
 	}
 
-	cifs_stats_bytes_written(pTcon, total_written);
+	cifs_stats_bytes_written(tcon, total_written);
 
 	if (total_written > 0) {
 		spin_lock(&dentry->d_inode->i_lock);
-		if (*poffset > dentry->d_inode->i_size)
-			i_size_write(dentry->d_inode, *poffset);
+		if (*offset > dentry->d_inode->i_size)
+			i_size_write(dentry->d_inode, *offset);
 		spin_unlock(&dentry->d_inode->i_lock);
 	}
 	mark_inode_dirty_sync(dentry->d_inode);
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index cea958e..aa55c2f 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -748,6 +748,16 @@ cifs_sync_read(const unsigned int xid, struct cifsFileInfo *cfile,
 	return CIFSSMBRead(xid, parms, bytes_read, buf, buf_type);
 }
 
+static int
+cifs_sync_write(const unsigned int xid, struct cifsFileInfo *cfile,
+		struct cifs_io_parms *parms, unsigned int *written,
+		struct kvec *iov, unsigned long nr_segs)
+{
+
+	parms->netfid = cfile->fid.netfid;
+	return CIFSSMBWrite2(xid, parms, written, iov, nr_segs);
+}
+
 struct smb_version_operations smb1_operations = {
 	.send_cancel = send_nt_cancel,
 	.compare_fids = cifs_compare_fids,
@@ -797,6 +807,7 @@ struct smb_version_operations smb1_operations = {
 	.async_readv = cifs_async_readv,
 	.async_writev = cifs_async_writev,
 	.sync_read = cifs_sync_read,
+	.sync_write = cifs_sync_write,
 };
 
 struct smb_version_values smb1_values = {
-- 
1.7.1

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

* [PATCH 29/45] CIFS: Add writepage support for SMB2
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (27 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 28/45] CIFS: Move writepage to ops struct Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
  2012-07-18 15:48   ` [PATCH 30/45] CIFS: Enable signing in SMB2 Pavel Shilovsky
                     ` (16 subsequent siblings)
  45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/smb2ops.c   |   12 ++++++++++
 fs/cifs/smb2pdu.c   |   61 +++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/cifs/smb2proto.h |    2 +
 3 files changed, 75 insertions(+), 0 deletions(-)

diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 4dca13d..82852fc 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -395,6 +395,17 @@ smb2_sync_read(const unsigned int xid, struct cifsFileInfo *cfile,
 	return SMB2_read(xid, parms, bytes_read, buf, buf_type);
 }
 
+static int
+smb2_sync_write(const unsigned int xid, struct cifsFileInfo *cfile,
+		struct cifs_io_parms *parms, unsigned int *written,
+		struct kvec *iov, unsigned long nr_segs)
+{
+
+	parms->persistent_fid = cfile->fid.persistent_fid;
+	parms->volatile_fid = cfile->fid.volatile_fid;
+	return SMB2_write(xid, parms, written, iov, nr_segs);
+}
+
 struct smb_version_operations smb21_operations = {
 	.setup_request = smb2_setup_request,
 	.setup_async_request = smb2_setup_async_request,
@@ -438,6 +449,7 @@ struct smb_version_operations smb21_operations = {
 	.async_readv = smb2_async_readv,
 	.async_writev = smb2_async_writev,
 	.sync_read = smb2_sync_read,
+	.sync_write = smb2_sync_write,
 };
 
 struct smb_version_values smb21_values = {
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 15b9b08..cb7d672 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1500,3 +1500,64 @@ async_writev_out:
 	kfree(iov);
 	return rc;
 }
+
+/*
+ * SMB2_write function gets iov pointer to kvec array with n_vec as a length.
+ * The length field from io_parms must be at least 1 and indicates a number of
+ * elements with data to write that begins with position 1 in iov array. All
+ * data length is specified by count.
+ */
+int
+SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
+	   unsigned int *nbytes, struct kvec *iov, int n_vec)
+{
+	int rc = 0;
+	struct smb2_write_req *req = NULL;
+	struct smb2_write_rsp *rsp = NULL;
+	int resp_buftype;
+	*nbytes = 0;
+
+	if (n_vec < 1)
+		return rc;
+
+	rc = small_smb2_init(SMB2_WRITE, io_parms->tcon, (void **) &req);
+	if (rc)
+		return rc;
+
+	if (io_parms->tcon->ses->server == NULL)
+		return -ECONNABORTED;
+
+	req->hdr.ProcessId = cpu_to_le32(io_parms->pid);
+
+	req->PersistentFileId = io_parms->persistent_fid;
+	req->VolatileFileId = io_parms->volatile_fid;
+	req->WriteChannelInfoOffset = 0;
+	req->WriteChannelInfoLength = 0;
+	req->Channel = 0;
+	req->Length = cpu_to_le32(io_parms->length);
+	req->Offset = cpu_to_le64(io_parms->offset);
+	/* 4 for rfc1002 length field */
+	req->DataOffset = cpu_to_le16(
+				offsetof(struct smb2_write_req, Buffer) - 4);
+	req->RemainingBytes = 0;
+
+	iov[0].iov_base = (char *)req;
+	/* 4 for rfc1002 length field and 1 for Buffer */
+	iov[0].iov_len = get_rfc1002_length(req) + 4 - 1;
+
+	/* length of entire message including data to be written */
+	inc_rfc1001_len(req, io_parms->length - 1 /* Buffer */);
+
+	rc = SendReceive2(xid, io_parms->tcon->ses, iov, n_vec + 1,
+			  &resp_buftype, 0);
+
+	if (rc) {
+		cifs_stats_fail_inc(io_parms->tcon, SMB2_WRITE_HE);
+		cERROR(1, "Send error in write = %d", rc);
+	} else {
+		rsp = (struct smb2_write_rsp *)iov[0].iov_base;
+		*nbytes = le32_to_cpu(rsp->DataLength);
+		free_rsp_buf(resp_buftype, rsp);
+	}
+	return rc;
+}
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 97e62f3..192d0c7 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -101,6 +101,8 @@ extern int smb2_async_readv(struct cifs_readdata *rdata);
 extern int SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
 		     unsigned int *nbytes, char **buf, int *buf_type);
 extern int smb2_async_writev(struct cifs_writedata *wdata);
+extern int SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
+		      unsigned int *nbytes, struct kvec *iov, int n_vec);
 extern int SMB2_echo(struct TCP_Server_Info *server);
 
 #endif			/* _SMB2PROTO_H */
-- 
1.7.1

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

* [PATCH 30/45] CIFS: Enable signing in SMB2
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (28 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 29/45] CIFS: Add writepage support for SMB2 Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
       [not found]     ` <1342626541-29872-31-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
  2012-07-18 15:48   ` [PATCH 31/45] CIFS: Move rename to ops struct Pavel Shilovsky
                     ` (15 subsequent siblings)
  45 siblings, 1 reply; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Use hmac-sha256 and rather than hmac-md5 that is used for CIFS/SMB.

Signature field in SMB2 header is 16 bytes instead of 8 bytes.

Automatically enable signing by client when requested by the server
when signing ability is available to the client.

Signed-off-by: Shirish Pargaonkar <shirishpargaonkar-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Sachin Prabhu <sprabhu-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Signed-off-by: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 fs/cifs/Kconfig         |    1 +
 fs/cifs/cifsencrypt.c   |   30 +++++++++-
 fs/cifs/cifsglob.h      |    2 +
 fs/cifs/cifsproto.h     |    1 +
 fs/cifs/smb2glob.h      |    4 +
 fs/cifs/smb2pdu.c       |   48 +++++++++++++--
 fs/cifs/smb2proto.h     |    2 +
 fs/cifs/smb2transport.c |  157 ++++++++++++++++++++++++++++++++++++++++++++--
 fs/cifs/transport.c     |   24 ++++----
 9 files changed, 243 insertions(+), 26 deletions(-)

diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig
index a08306a..8029301 100644
--- a/fs/cifs/Kconfig
+++ b/fs/cifs/Kconfig
@@ -9,6 +9,7 @@ config CIFS
 	select CRYPTO_ARC4
 	select CRYPTO_ECB
 	select CRYPTO_DES
+	select CRYPTO_SHA256
 	help
 	  This is the client VFS module for the Common Internet File System
 	  (CIFS) protocol which is the successor to the Server Message Block
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index 63c460e..e572d55 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -686,12 +686,17 @@ calc_seckey(struct cifs_ses *ses)
 void
 cifs_crypto_shash_release(struct TCP_Server_Info *server)
 {
+	if (server->secmech.hmacsha256)
+		crypto_free_shash(server->secmech.hmacsha256);
+
 	if (server->secmech.md5)
 		crypto_free_shash(server->secmech.md5);
 
 	if (server->secmech.hmacmd5)
 		crypto_free_shash(server->secmech.hmacmd5);
 
+	kfree(server->secmech.sdeschmacsha256);
+
 	kfree(server->secmech.sdeschmacmd5);
 
 	kfree(server->secmech.sdescmd5);
@@ -716,6 +721,13 @@ cifs_crypto_shash_allocate(struct TCP_Server_Info *server)
 		goto crypto_allocate_md5_fail;
 	}
 
+	server->secmech.hmacsha256 = crypto_alloc_shash("hmac(sha256)", 0, 0);
+	if (IS_ERR(server->secmech.hmacsha256)) {
+		cERROR(1, "could not allocate crypto hmacsha256\n");
+		rc = PTR_ERR(server->secmech.hmacsha256);
+		goto crypto_allocate_hmacsha256_fail;
+	}
+
 	size = sizeof(struct shash_desc) +
 			crypto_shash_descsize(server->secmech.hmacmd5);
 	server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL);
@@ -727,7 +739,6 @@ cifs_crypto_shash_allocate(struct TCP_Server_Info *server)
 	server->secmech.sdeschmacmd5->shash.tfm = server->secmech.hmacmd5;
 	server->secmech.sdeschmacmd5->shash.flags = 0x0;
 
-
 	size = sizeof(struct shash_desc) +
 			crypto_shash_descsize(server->secmech.md5);
 	server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL);
@@ -739,12 +750,29 @@ cifs_crypto_shash_allocate(struct TCP_Server_Info *server)
 	server->secmech.sdescmd5->shash.tfm = server->secmech.md5;
 	server->secmech.sdescmd5->shash.flags = 0x0;
 
+	size = sizeof(struct shash_desc) +
+			crypto_shash_descsize(server->secmech.hmacsha256);
+	server->secmech.sdeschmacsha256 = kmalloc(size, GFP_KERNEL);
+	if (!server->secmech.sdeschmacsha256) {
+		cERROR(1, "%s: Can't alloc hmacsha256\n", __func__);
+		rc = -ENOMEM;
+		goto crypto_allocate_hmacsha256_sdesc_fail;
+	}
+	server->secmech.sdeschmacsha256->shash.tfm = server->secmech.hmacsha256;
+	server->secmech.sdeschmacsha256->shash.flags = 0x0;
+
 	return 0;
 
+crypto_allocate_hmacsha256_sdesc_fail:
+	kfree(server->secmech.sdescmd5);
+
 crypto_allocate_md5_sdesc_fail:
 	kfree(server->secmech.sdeschmacmd5);
 
 crypto_allocate_hmacmd5_sdesc_fail:
+	crypto_free_shash(server->secmech.hmacsha256);
+
+crypto_allocate_hmacsha256_fail:
 	crypto_free_shash(server->secmech.md5);
 
 crypto_allocate_md5_fail:
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 3e54b19..78ce424 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -128,8 +128,10 @@ struct sdesc {
 struct cifs_secmech {
 	struct crypto_shash *hmacmd5; /* hmac-md5 hash function */
 	struct crypto_shash *md5; /* md5 hash function */
+	struct crypto_shash *hmacsha256; /* hmac-sha256 hash function */
 	struct sdesc *sdeschmacmd5;  /* ctxt to generate ntlmv2 hash, CR1 */
 	struct sdesc *sdescmd5; /* ctxt to generate cifs/smb signature */
+	struct sdesc *sdeschmacsha256;  /* ctxt to generate smb2 signature */
 };
 
 /* per smb session structure/fields */
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index bdf8948..722dba8 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -65,6 +65,7 @@ extern char *cifs_compose_mount_options(const char *sb_mountdata,
 extern struct mid_q_entry *AllocMidQEntry(const struct smb_hdr *smb_buffer,
 					struct TCP_Server_Info *server);
 extern void DeleteMidQEntry(struct mid_q_entry *midEntry);
+extern void cifs_delete_mid(struct mid_q_entry *mid);
 extern void cifs_wake_up_task(struct mid_q_entry *mid);
 extern int cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
 			   unsigned int nvec, mid_receive_t *receive,
diff --git a/fs/cifs/smb2glob.h b/fs/cifs/smb2glob.h
index 11505d7..8635574 100644
--- a/fs/cifs/smb2glob.h
+++ b/fs/cifs/smb2glob.h
@@ -47,4 +47,8 @@
 #define END_OF_CHAIN 4
 #define RELATED_REQUEST 8
 
+#define SMB2_SIGNATURE_SIZE (16)
+#define SMB2_NTLMV2_SESSKEY_SIZE (16)
+#define SMB2_HMACSHA256_SIZE (32)
+
 #endif	/* _SMB2_GLOB_H */
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index cb7d672..46829c6 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -118,9 +118,9 @@ smb2_hdr_assemble(struct smb2_hdr *hdr, __le16 smb2_cmd /* command */ ,
 	/* BB how does SMB2 do case sensitive? */
 	/* if (tcon->nocase)
 		hdr->Flags |= SMBFLG_CASELESS; */
-	/* if (tcon->ses && tcon->ses->server &&
+	if (tcon->ses && tcon->ses->server &&
 	    (tcon->ses->server->sec_mode & SECMODE_SIGN_REQUIRED))
-		hdr->Flags |= SMB2_FLAGS_SIGNED; */
+		hdr->Flags |= SMB2_FLAGS_SIGNED;
 out:
 	pdu->StructureSize2 = cpu_to_le16(parmsize);
 	return;
@@ -441,6 +441,38 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
 		rc = -EIO;
 		goto neg_exit;
 	}
+
+	cFYI(1, "sec_flags 0x%x", sec_flags);
+	if (sec_flags & CIFSSEC_MUST_SIGN) {
+		cFYI(1, "Signing required");
+		if (!(server->sec_mode & (SMB2_NEGOTIATE_SIGNING_REQUIRED |
+		      SMB2_NEGOTIATE_SIGNING_ENABLED))) {
+			cERROR(1, "signing required but server lacks support");
+			rc = -EOPNOTSUPP;
+			goto neg_exit;
+		}
+		server->sec_mode |= SECMODE_SIGN_REQUIRED;
+	} else if (sec_flags & CIFSSEC_MAY_SIGN) {
+		cFYI(1, "Signing optional");
+		if (server->sec_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) {
+			cFYI(1, "Server requires signing");
+			server->sec_mode |= SECMODE_SIGN_REQUIRED;
+		} else {
+			server->sec_mode &=
+				~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
+		}
+	} else {
+		cFYI(1, "Signing disabled");
+		if (server->sec_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) {
+			cERROR(1, "Server requires packet signing to be enabled"
+				  " in /proc/fs/cifs/SecurityFlags.");
+			rc = -EOPNOTSUPP;
+			goto neg_exit;
+		}
+		server->sec_mode &=
+			~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
+	}
+
 #ifdef CONFIG_SMB2_ASN1  /* BB REMOVEME when updated asn1.c ready */
 	rc = decode_neg_token_init(security_blob, blob_length,
 				   &server->sec_type);
@@ -669,6 +701,8 @@ SMB2_logoff(const unsigned int xid, struct cifs_ses *ses)
 
 	 /* since no tcon, smb2_init can not do this, so do here */
 	req->hdr.SessionId = ses->Suid;
+	if (server->sec_mode & SECMODE_SIGN_REQUIRED)
+		req->hdr.Flags |= SMB2_FLAGS_SIGNED;
 
 	rc = SendReceiveNoRsp(xid, ses, (char *) &req->hdr, 0);
 	/*
@@ -1268,10 +1302,12 @@ smb2_readv_callback(struct mid_q_entry *mid)
 	case MID_RESPONSE_RECEIVED:
 		credits_received = le16_to_cpu(buf->CreditRequest);
 		/* result already set, check signature */
-		/* if (server->sec_mode &
-		    (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
-			if (smb2_verify_signature(mid->resp_buf, server))
-				cERROR(1, "Unexpected SMB signature"); */
+		if (server->sec_mode &
+		    (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
+			if (smb2_verify_signature2(rdata->iov, rdata->nr_iov,
+						   server))
+				cERROR(1, "Unexpected SMB signature");
+		}
 		/* FIXME: should this be counted toward the initiating task? */
 		task_io_account_read(rdata->bytes);
 		cifs_stats_bytes_read(tcon, rdata->bytes);
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 192d0c7..dbbdc39 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -39,6 +39,8 @@ extern char *smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr);
 extern __le16 *cifs_convert_path_to_utf16(const char *from,
 					  struct cifs_sb_info *cifs_sb);
 
+extern int smb2_verify_signature2(struct kvec *, unsigned int,
+				  struct TCP_Server_Info *);
 extern int smb2_check_receive(struct mid_q_entry *mid,
 			      struct TCP_Server_Info *server, bool log_error);
 extern int smb2_setup_request(struct cifs_ses *ses, struct kvec *iov,
diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c
index 31f5d42..7276f6f 100644
--- a/fs/cifs/smb2transport.c
+++ b/fs/cifs/smb2transport.c
@@ -36,6 +36,149 @@
 #include "smb2proto.h"
 #include "cifs_debug.h"
 #include "smb2status.h"
+#include "smb2glob.h"
+
+static int
+smb2_calc_signature2(const struct kvec *iov, int n_vec,
+		     struct TCP_Server_Info *server)
+{
+	int i, rc;
+	unsigned char smb2_signature[SMB2_HMACSHA256_SIZE];
+	unsigned char *sigptr = smb2_signature;
+	struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base;
+
+	memset(smb2_signature, 0x0, SMB2_HMACSHA256_SIZE);
+	memset(smb2_pdu->Signature, 0x0, SMB2_SIGNATURE_SIZE);
+
+	rc = crypto_shash_setkey(server->secmech.hmacsha256,
+		server->session_key.response, SMB2_NTLMV2_SESSKEY_SIZE);
+	if (rc) {
+		cERROR(1, "%s: Could not update with response\n", __func__);
+		return rc;
+	}
+
+	rc = crypto_shash_init(&server->secmech.sdeschmacsha256->shash);
+	if (rc) {
+		cERROR(1, "%s: Could not init md5\n", __func__);
+		return rc;
+	}
+
+	for (i = 0; i < n_vec; i++) {
+		if (iov[i].iov_len == 0)
+			continue;
+		if (iov[i].iov_base == NULL) {
+			cERROR(1, "null iovec entry");
+			return -EIO;
+		}
+		/*
+		 * The first entry includes a length field (which does not get
+		 * signed that occupies the first 4 bytes before the header).
+		 */
+		if (i == 0) {
+			if (iov[0].iov_len <= 8) /* cmd field at offset 9 */
+				break; /* nothing to sign or corrupt header */
+			rc =
+			crypto_shash_update(
+				&server->secmech.sdeschmacsha256->shash,
+				iov[i].iov_base + 4, iov[i].iov_len - 4);
+		} else {
+			rc =
+			crypto_shash_update(
+				&server->secmech.sdeschmacsha256->shash,
+				iov[i].iov_base, iov[i].iov_len);
+		}
+		if (rc) {
+			cERROR(1, "%s: Could not update with payload\n",
+							__func__);
+			return rc;
+		}
+	}
+
+	rc = crypto_shash_final(&server->secmech.sdeschmacsha256->shash,
+				sigptr);
+	if (rc)
+		cERROR(1, "%s: Could not generate sha256 hash\n", __func__);
+
+	memcpy(smb2_pdu->Signature, sigptr, SMB2_SIGNATURE_SIZE);
+
+	return rc;
+}
+
+/* must be called with server->srv_mutex held */
+static int
+smb2_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server)
+{
+	int rc = 0;
+	struct smb2_hdr *smb2_pdu = iov[0].iov_base;
+
+	if (!(smb2_pdu->Flags & SMB2_FLAGS_SIGNED) ||
+	    server->tcpStatus == CifsNeedNegotiate)
+		return rc;
+
+	if (!server->session_estab) {
+		strncpy(smb2_pdu->Signature, "BSRSPYL", 8);
+		return rc;
+	}
+
+	rc = smb2_calc_signature2(iov, n_vec, server);
+
+	return rc;
+}
+
+int
+smb2_verify_signature2(struct kvec *iov, unsigned int n_vec,
+		       struct TCP_Server_Info *server)
+{
+	unsigned int rc;
+	char server_response_sig[16];
+	struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base;
+
+	if ((smb2_pdu->Command == SMB2_NEGOTIATE) ||
+	    (smb2_pdu->Command == SMB2_OPLOCK_BREAK) ||
+	    (!server->session_estab))
+		return 0;
+
+	/*
+	 * BB what if signatures are supposed to be on for session but
+	 * server does not send one? BB
+	 */
+
+	/* Do not need to verify session setups with signature "BSRSPYL " */
+	if (memcmp(smb2_pdu->Signature, "BSRSPYL ", 8) == 0)
+		cFYI(1, "dummy signature received for smb command 0x%x",
+			smb2_pdu->Command);
+
+	/*
+	 * Save off the origiginal signature so we can modify the smb and check
+	 * our calculated signature against what the server sent.
+	 */
+	memcpy(server_response_sig, smb2_pdu->Signature, SMB2_SIGNATURE_SIZE);
+
+	memset(smb2_pdu->Signature, 0, SMB2_SIGNATURE_SIZE);
+
+	mutex_lock(&server->srv_mutex);
+	rc = smb2_calc_signature2(iov, n_vec, server);
+	mutex_unlock(&server->srv_mutex);
+
+	if (rc)
+		return rc;
+
+	if (memcmp(server_response_sig, smb2_pdu->Signature,
+		   SMB2_SIGNATURE_SIZE))
+		return -EACCES;
+	else
+		return 0;
+}
+
+static int
+smb2_verify_signature(struct smb2_hdr *smb2_pdu, struct TCP_Server_Info *server)
+{
+	struct kvec iov;
+
+	iov.iov_base = (char *)smb2_pdu;
+	iov.iov_len = get_rfc1002_length(smb2_pdu) + 4;
+	return smb2_verify_signature2(&iov, 1, server);
+}
 
 /*
  * Set message id for the request. Should be called after wait_for_free_request
@@ -118,12 +261,11 @@ smb2_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
 
 	dump_smb(mid->resp_buf, min_t(u32, 80, len));
 	/* convert the length into a more usable form */
-	/* BB - uncomment with SMB2 signing implementation */
-	/* if ((len > 24) &&
+	if ((len > 24) &&
 	    (server->sec_mode & (SECMODE_SIGN_REQUIRED|SECMODE_SIGN_ENABLED))) {
 		if (smb2_verify_signature(mid->resp_buf, server))
 			cERROR(1, "Unexpected SMB signature");
-	} */
+	}
 
 	return map_smb2_to_linux_error(mid->resp_buf, log_error);
 }
@@ -141,9 +283,9 @@ smb2_setup_request(struct cifs_ses *ses, struct kvec *iov,
 	rc = smb2_get_mid_entry(ses, hdr, &mid);
 	if (rc)
 		return rc;
-	/* rc = smb2_sign_smb2(iov, nvec, ses->server);
+	rc = smb2_sign_smb2(iov, nvec, ses->server);
 	if (rc)
-		delete_mid(mid); */
+		cifs_delete_mid(mid);
 	*ret_mid = mid;
 	return rc;
 }
@@ -162,11 +304,12 @@ smb2_setup_async_request(struct TCP_Server_Info *server, struct kvec *iov,
 	if (mid == NULL)
 		return -ENOMEM;
 
-	/* rc = smb2_sign_smb2(iov, nvec, server);
+	rc = smb2_sign_smb2(iov, nvec, server);
 	if (rc) {
 		DeleteMidQEntry(mid);
 		return rc;
-	}*/
+	}
+
 	*ret_mid = mid;
 	return rc;
 }
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 4d37902..cb18dbf 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -109,8 +109,8 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
 	mempool_free(midEntry, cifs_mid_poolp);
 }
 
-static void
-delete_mid(struct mid_q_entry *mid)
+void
+cifs_delete_mid(struct mid_q_entry *mid)
 {
 	spin_lock(&GlobalMid_Lock);
 	list_del(&mid->qhead);
@@ -423,7 +423,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
 	if (rc == 0)
 		return 0;
 
-	delete_mid(mid);
+	cifs_delete_mid(mid);
 	add_credits(server, 1, optype);
 	wake_up(&server->request_q);
 	return rc;
@@ -533,7 +533,7 @@ cifs_setup_request(struct cifs_ses *ses, struct kvec *iov,
 		return rc;
 	rc = cifs_sign_smb2(iov, nvec, ses->server, &mid->sequence_number);
 	if (rc)
-		delete_mid(mid);
+		cifs_delete_mid(mid);
 	*ret_mid = mid;
 	return rc;
 }
@@ -653,11 +653,11 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 	rc = ses->server->ops->check_receive(midQ, ses->server,
 					     flags & CIFS_LOG_ERROR);
 
-	/* mark it so buf will not be freed by delete_mid */
+	/* mark it so buf will not be freed by cifs_delete_mid */
 	if ((flags & CIFS_NO_RESP) == 0)
 		midQ->resp_buf = NULL;
 out:
-	delete_mid(midQ);
+	cifs_delete_mid(midQ);
 	add_credits(ses->server, credits, optype);
 
 	return rc;
@@ -763,7 +763,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 	memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
 	rc = cifs_check_receive(midQ, ses->server, 0);
 out:
-	delete_mid(midQ);
+	cifs_delete_mid(midQ);
 	add_credits(ses->server, 1, 0);
 
 	return rc;
@@ -847,7 +847,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 
 	rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
 	if (rc) {
-		delete_mid(midQ);
+		cifs_delete_mid(midQ);
 		mutex_unlock(&ses->server->srv_mutex);
 		return rc;
 	}
@@ -860,7 +860,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 	mutex_unlock(&ses->server->srv_mutex);
 
 	if (rc < 0) {
-		delete_mid(midQ);
+		cifs_delete_mid(midQ);
 		return rc;
 	}
 
@@ -881,7 +881,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 			   blocking lock to return. */
 			rc = send_cancel(ses->server, in_buf, midQ);
 			if (rc) {
-				delete_mid(midQ);
+				cifs_delete_mid(midQ);
 				return rc;
 			}
 		} else {
@@ -893,7 +893,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 			/* If we get -ENOLCK back the lock may have
 			   already been removed. Don't exit in this case. */
 			if (rc && rc != -ENOLCK) {
-				delete_mid(midQ);
+				cifs_delete_mid(midQ);
 				return rc;
 			}
 		}
@@ -930,7 +930,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 	memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
 	rc = cifs_check_receive(midQ, ses->server, 0);
 out:
-	delete_mid(midQ);
+	cifs_delete_mid(midQ);
 	if (rstart && rc == -EACCES)
 		return -ERESTARTSYS;
 	return rc;
-- 
1.7.1

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

* [PATCH 31/45] CIFS: Move rename to ops struct
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (29 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 30/45] CIFS: Enable signing in SMB2 Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
  2012-07-18 15:48   ` [PATCH 32/45] CIFS: Add SMB2 support for rename operation Pavel Shilovsky
                     ` (14 subsequent siblings)
  45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/cifsglob.h  |    3 ++
 fs/cifs/cifsproto.h |    5 +--
 fs/cifs/cifssmb.c   |   22 +++++++-----
 fs/cifs/inode.c     |   92 ++++++++++++++++++++++++++------------------------
 fs/cifs/smb1ops.c   |    1 +
 5 files changed, 66 insertions(+), 57 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 78ce424..0f8a466 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -275,6 +275,9 @@ struct smb_version_operations {
 	/* open, rename and delete file */
 	int (*rename_pending_delete)(const char *, struct dentry *,
 				     const unsigned int);
+	/* send rename request */
+	int (*rename)(const unsigned int, struct cifs_tcon *, const char *,
+		      const char *, struct cifs_sb_info *);
 	/* open a file for non-posix mounts */
 	int (*open)(const unsigned int, struct cifs_tcon *, const char *, int,
 		    int, int, struct cifs_fid *, __u32 *, FILE_ALL_INFO *,
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 722dba8..ef94f36 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -310,9 +310,8 @@ extern int CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
 extern int CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon,
 			  const char *name, struct cifs_sb_info *cifs_sb);
 extern int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
-			const char *fromName, const char *toName,
-			const struct nls_table *nls_codepage,
-			int remap_special_chars);
+			 const char *from_name, const char *to_name,
+			 struct cifs_sb_info *cifs_sb);
 extern int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *tcon,
 				 int netfid, const char *target_name,
 				 const struct nls_table *nls_codepage,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 666535c..c1a18a6 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -2528,8 +2528,8 @@ CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
 
 int
 CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
-	      const char *fromName, const char *toName,
-	      const struct nls_table *nls_codepage, int remap)
+	      const char *from_name, const char *to_name,
+	      struct cifs_sb_info *cifs_sb)
 {
 	int rc = 0;
 	RENAME_REQ *pSMB = NULL;
@@ -2537,6 +2537,7 @@ CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
 	int bytes_returned;
 	int name_len, name_len2;
 	__u16 count;
+	int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
 
 	cFYI(1, "In CIFSSMBRename");
 renameRetry:
@@ -2551,9 +2552,9 @@ renameRetry:
 			ATTR_DIRECTORY);
 
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
-		name_len =
-		    cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName,
-				       PATH_MAX, nls_codepage, remap);
+		name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
+					      from_name, PATH_MAX,
+					      cifs_sb->local_nls, remap);
 		name_len++;	/* trailing null */
 		name_len *= 2;
 		pSMB->OldFileName[name_len] = 0x04;	/* pad */
@@ -2561,17 +2562,18 @@ renameRetry:
 		pSMB->OldFileName[name_len + 1] = 0x00;
 		name_len2 =
 		    cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
-				       toName, PATH_MAX, nls_codepage, remap);
+				       to_name, PATH_MAX, cifs_sb->local_nls,
+				       remap);
 		name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
 		name_len2 *= 2;	/* convert to bytes */
 	} else {	/* BB improve the check for buffer overruns BB */
-		name_len = strnlen(fromName, PATH_MAX);
+		name_len = strnlen(from_name, PATH_MAX);
 		name_len++;	/* trailing null */
-		strncpy(pSMB->OldFileName, fromName, name_len);
-		name_len2 = strnlen(toName, PATH_MAX);
+		strncpy(pSMB->OldFileName, from_name, name_len);
+		name_len2 = strnlen(to_name, PATH_MAX);
 		name_len2++;	/* trailing null */
 		pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
-		strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
+		strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
 		name_len2++;	/* trailing null */
 		name_len2++;	/* signature byte */
 	}
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 39ef1a6..f1448d9 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1512,29 +1512,32 @@ rmdir_exit:
 }
 
 static int
-cifs_do_rename(unsigned int xid, struct dentry *from_dentry,
-	       const char *fromPath, struct dentry *to_dentry,
-	       const char *toPath)
+cifs_do_rename(const unsigned int xid, struct dentry *from_dentry,
+	       const char *from_path, struct dentry *to_dentry,
+	       const char *to_path)
 {
 	struct cifs_sb_info *cifs_sb = CIFS_SB(from_dentry->d_sb);
 	struct tcon_link *tlink;
-	struct cifs_tcon *pTcon;
+	struct cifs_tcon *tcon;
+	struct TCP_Server_Info *server;
 	__u16 srcfid;
 	int oplock, rc;
 
 	tlink = cifs_sb_tlink(cifs_sb);
 	if (IS_ERR(tlink))
 		return PTR_ERR(tlink);
-	pTcon = tlink_tcon(tlink);
+	tcon = tlink_tcon(tlink);
+	server = tcon->ses->server;
+
+	if (!server->ops->rename)
+		return -ENOSYS;
 
 	/* try path-based rename first */
-	rc = CIFSSMBRename(xid, pTcon, fromPath, toPath, cifs_sb->local_nls,
-			   cifs_sb->mnt_cifs_flags &
-				CIFS_MOUNT_MAP_SPECIAL_CHR);
+	rc = server->ops->rename(xid, tcon, from_path, to_path, cifs_sb);
 
 	/*
-	 * don't bother with rename by filehandle unless file is busy and
-	 * source Note that cross directory moves do not work with
+	 * Don't bother with rename by filehandle unless file is busy and
+	 * source. Note that cross directory moves do not work with
 	 * rename by filehandle to various Windows servers.
 	 */
 	if (rc == 0 || rc != -ETXTBSY)
@@ -1545,29 +1548,28 @@ cifs_do_rename(unsigned int xid, struct dentry *from_dentry,
 		goto do_rename_exit;
 
 	/* open the file to be renamed -- we need DELETE perms */
-	rc = CIFSSMBOpen(xid, pTcon, fromPath, FILE_OPEN, DELETE,
+	rc = CIFSSMBOpen(xid, tcon, from_path, FILE_OPEN, DELETE,
 			 CREATE_NOT_DIR, &srcfid, &oplock, NULL,
 			 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
 				CIFS_MOUNT_MAP_SPECIAL_CHR);
-
 	if (rc == 0) {
-		rc = CIFSSMBRenameOpenFile(xid, pTcon, srcfid,
+		rc = CIFSSMBRenameOpenFile(xid, tcon, srcfid,
 				(const char *) to_dentry->d_name.name,
 				cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
 					CIFS_MOUNT_MAP_SPECIAL_CHR);
-
-		CIFSSMBClose(xid, pTcon, srcfid);
+		CIFSSMBClose(xid, tcon, srcfid);
 	}
 do_rename_exit:
 	cifs_put_tlink(tlink);
 	return rc;
 }
 
-int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
-	struct inode *target_dir, struct dentry *target_dentry)
+int
+cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
+	    struct inode *target_dir, struct dentry *target_dentry)
 {
-	char *fromName = NULL;
-	char *toName = NULL;
+	char *from_name = NULL;
+	char *to_name = NULL;
 	struct cifs_sb_info *cifs_sb;
 	struct tcon_link *tlink;
 	struct cifs_tcon *tcon;
@@ -1588,25 +1590,25 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
 	 * we already have the rename sem so we do not need to
 	 * grab it again here to protect the path integrity
 	 */
-	fromName = build_path_from_dentry(source_dentry);
-	if (fromName == NULL) {
+	from_name = build_path_from_dentry(source_dentry);
+	if (from_name == NULL) {
 		rc = -ENOMEM;
 		goto cifs_rename_exit;
 	}
 
-	toName = build_path_from_dentry(target_dentry);
-	if (toName == NULL) {
+	to_name = build_path_from_dentry(target_dentry);
+	if (to_name == NULL) {
 		rc = -ENOMEM;
 		goto cifs_rename_exit;
 	}
 
-	rc = cifs_do_rename(xid, source_dentry, fromName,
-			    target_dentry, toName);
+	rc = cifs_do_rename(xid, source_dentry, from_name, target_dentry,
+			    to_name);
 
 	if (rc == -EEXIST && tcon->unix_ext) {
 		/*
-		 * Are src and dst hardlinks of same inode? We can
-		 * only tell with unix extensions enabled
+		 * Are src and dst hardlinks of same inode? We can only tell
+		 * with unix extensions enabled.
 		 */
 		info_buf_source =
 			kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO),
@@ -1617,19 +1619,19 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
 		}
 
 		info_buf_target = info_buf_source + 1;
-		tmprc = CIFSSMBUnixQPathInfo(xid, tcon, fromName,
-					info_buf_source,
-					cifs_sb->local_nls,
-					cifs_sb->mnt_cifs_flags &
-					CIFS_MOUNT_MAP_SPECIAL_CHR);
+		tmprc = CIFSSMBUnixQPathInfo(xid, tcon, from_name,
+					     info_buf_source,
+					     cifs_sb->local_nls,
+					     cifs_sb->mnt_cifs_flags &
+						CIFS_MOUNT_MAP_SPECIAL_CHR);
 		if (tmprc != 0)
 			goto unlink_target;
 
-		tmprc = CIFSSMBUnixQPathInfo(xid, tcon, toName,
-					info_buf_target,
-					cifs_sb->local_nls,
-					cifs_sb->mnt_cifs_flags &
-					CIFS_MOUNT_MAP_SPECIAL_CHR);
+		tmprc = CIFSSMBUnixQPathInfo(xid, tcon, to_name,
+					     info_buf_target,
+					     cifs_sb->local_nls,
+					     cifs_sb->mnt_cifs_flags &
+						CIFS_MOUNT_MAP_SPECIAL_CHR);
 
 		if (tmprc == 0 && (info_buf_source->UniqueId ==
 				   info_buf_target->UniqueId)) {
@@ -1637,8 +1639,11 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
 			rc = 0;
 			goto cifs_rename_exit;
 		}
-	} /* else ... BB we could add the same check for Windows by
-		     checking the UniqueId via FILE_INTERNAL_INFO */
+	}
+	/*
+	 * else ... BB we could add the same check for Windows by
+	 * checking the UniqueId via FILE_INTERNAL_INFO
+	 */
 
 unlink_target:
 	/* Try unlinking the target dentry if it's not negative */
@@ -1646,15 +1651,14 @@ unlink_target:
 		tmprc = cifs_unlink(target_dir, target_dentry);
 		if (tmprc)
 			goto cifs_rename_exit;
-
-		rc = cifs_do_rename(xid, source_dentry, fromName,
-				    target_dentry, toName);
+		rc = cifs_do_rename(xid, source_dentry, from_name,
+				    target_dentry, to_name);
 	}
 
 cifs_rename_exit:
 	kfree(info_buf_source);
-	kfree(fromName);
-	kfree(toName);
+	kfree(from_name);
+	kfree(to_name);
 	free_xid(xid);
 	cifs_put_tlink(tlink);
 	return rc;
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index aa55c2f..3773920 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -800,6 +800,7 @@ struct smb_version_operations smb1_operations = {
 	.rmdir = CIFSSMBRmDir,
 	.unlink = CIFSSMBDelFile,
 	.rename_pending_delete = cifs_rename_pending_delete,
+	.rename = CIFSSMBRename,
 	.open = cifs_open_file,
 	.set_fid = cifs_set_fid,
 	.close = cifs_close_file,
-- 
1.7.1

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

* [PATCH 32/45] CIFS: Add SMB2 support for rename operation
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (30 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 31/45] CIFS: Move rename to ops struct Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
  2012-07-18 15:48   ` [PATCH 33/45] CIFS: Move hardlink to ops struct Pavel Shilovsky
                     ` (13 subsequent siblings)
  45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 fs/cifs/smb2inode.c |   25 ++++++++++++
 fs/cifs/smb2ops.c   |    1 +
 fs/cifs/smb2pdu.c   |  107 +++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/cifs/smb2pdu.h   |   28 +++++++++++++
 fs/cifs/smb2proto.h |    6 +++
 5 files changed, 167 insertions(+), 0 deletions(-)

diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index ee3a1ef..a6952ba 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -74,6 +74,10 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
 		 * SMB2_open() call.
 		 */
 		break;
+	case SMB2_OP_RENAME:
+		tmprc = SMB2_rename(xid, tcon, persistent_fid, volatile_fid,
+				    (__le16 *)data);
+		break;
 	default:
 		cERROR(1, "Invalid command");
 		break;
@@ -170,3 +174,24 @@ smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
 				  0, CREATE_DELETE_ON_CLOSE, NULL,
 				  SMB2_OP_DELETE);
 }
+
+int
+smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
+		 const char *from_name, const char *to_name,
+		 struct cifs_sb_info *cifs_sb)
+{
+	__le16 *smb2_to_name = NULL;
+	int rc;
+
+	smb2_to_name = cifs_convert_path_to_utf16(to_name, cifs_sb);
+	if (smb2_to_name == NULL) {
+		rc = -ENOMEM;
+		goto smb2_rename_path;
+	}
+
+	rc = smb2_open_op_close(xid, tcon, cifs_sb, from_name, DELETE,
+				FILE_OPEN, 0, 0, smb2_to_name, SMB2_OP_RENAME);
+smb2_rename_path:
+	kfree(smb2_to_name);
+	return rc;
+}
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 82852fc..da13a60 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -442,6 +442,7 @@ struct smb_version_operations smb21_operations = {
 	.mkdir_setinfo = smb2_mkdir_setinfo,
 	.rmdir = smb2_rmdir,
 	.unlink = smb2_unlink,
+	.rename = smb2_rename_path,
 	.open = smb2_open_file,
 	.set_fid = smb2_set_fid,
 	.close = smb2_close_file,
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 46829c6..515c141 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1597,3 +1597,110 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
 	}
 	return rc;
 }
+
+static int
+send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
+	       u64 persistent_fid, u64 volatile_fid, int info_class,
+	       unsigned int num, void **data, unsigned int *size)
+{
+	struct smb2_set_info_req *req;
+	struct smb2_set_info_rsp *rsp = NULL;
+	struct kvec *iov;
+	int rc = 0;
+	int resp_buftype;
+	unsigned int i;
+	struct TCP_Server_Info *server;
+	struct cifs_ses *ses = tcon->ses;
+
+	if (ses && (ses->server))
+		server = ses->server;
+	else
+		return -EIO;
+
+	if (!num)
+		return -EINVAL;
+
+	iov = kmalloc(sizeof(struct kvec) * num, GFP_KERNEL);
+	if (!iov)
+		return -ENOMEM;
+
+	rc = small_smb2_init(SMB2_SET_INFO, tcon, (void **) &req);
+	if (rc) {
+		kfree(iov);
+		return rc;
+	}
+
+	req->InfoType = SMB2_O_INFO_FILE;
+	req->FileInfoClass = info_class;
+	req->PersistentFileId = persistent_fid;
+	req->VolatileFileId = volatile_fid;
+
+	/* 4 for RFC1001 length and 1 for Buffer */
+	req->BufferOffset =
+			cpu_to_le16(sizeof(struct smb2_set_info_req) - 1 - 4);
+	req->BufferLength = cpu_to_le32(*size);
+
+	inc_rfc1001_len(req, *size - 1 /* Buffer */);
+
+	memcpy(req->Buffer, *data, *size);
+
+	iov[0].iov_base = (char *)req;
+	/* 4 for RFC1001 length */
+	iov[0].iov_len = get_rfc1002_length(req) + 4;
+
+	for (i = 1; i < num; i++) {
+		inc_rfc1001_len(req, size[i]);
+		le32_add_cpu(&req->BufferLength, size[i]);
+		iov[i].iov_base = (char *)data[i];
+		iov[i].iov_len = size[i];
+	}
+
+	rc = SendReceive2(xid, ses, iov, num, &resp_buftype, 0);
+	rsp = (struct smb2_set_info_rsp *)iov[0].iov_base;
+
+	if (rc != 0) {
+		cifs_stats_fail_inc(tcon, SMB2_SET_INFO_HE);
+		goto out;
+	}
+
+	if (rsp == NULL) {
+		rc = -EIO;
+		goto out;
+	}
+
+out:
+	free_rsp_buf(resp_buftype, rsp);
+	kfree(iov);
+	return rc;
+}
+
+int
+SMB2_rename(const unsigned int xid, struct cifs_tcon *tcon,
+	    u64 persistent_fid, u64 volatile_fid, __le16 *target_file)
+{
+	struct smb2_file_rename_info info;
+	void **data;
+	unsigned int size[2];
+	int rc;
+	int len = (2 * UniStrnlen((wchar_t *)target_file, PATH_MAX));
+
+	data = kmalloc(sizeof(void *) * 2, GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	info.ReplaceIfExists = 1; /* 1 = replace existing target with new */
+			      /* 0 = fail if target already exists */
+	info.RootDirectory = 0;  /* MBZ for network ops (why does spec say?) */
+	info.FileNameLength = cpu_to_le32(len);
+
+	data[0] = &info;
+	size[0] = sizeof(struct smb2_file_rename_info);
+
+	data[1] = target_file;
+	size[1] = len + 2 /* null */;
+
+	rc = send_set_info(xid, tcon, persistent_fid, volatile_fid,
+			   FILE_RENAME_INFORMATION, 2, data, size);
+	kfree(data);
+	return rc;
+}
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 4712273..e2c7887 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -566,6 +566,25 @@ struct smb2_query_info_rsp {
 	__u8   Buffer[1];
 } __packed;
 
+struct smb2_set_info_req {
+	struct smb2_hdr hdr;
+	__le16 StructureSize; /* Must be 33 */
+	__u8   InfoType;
+	__u8   FileInfoClass;
+	__le32 BufferLength;
+	__le16 BufferOffset;
+	__u16  Reserved;
+	__le32 AdditionalInformation;
+	__u64  PersistentFileId; /* opaque endianness */
+	__u64  VolatileFileId; /* opaque endianness */
+	__u8   Buffer[1];
+} __packed;
+
+struct smb2_set_info_rsp {
+	struct smb2_hdr hdr;
+	__le16 StructureSize; /* Must be 2 */
+} __packed;
+
 /*
  *	PDU infolevel structure definitions
  *	BB consider moving to a different header
@@ -623,6 +642,15 @@ struct smb2_file_internal_info {
 	__le64 IndexNumber;
 } __packed; /* level 6 Query */
 
+struct smb2_file_rename_info { /* encoding of request for level 10 */
+	__u8   ReplaceIfExists; /* 1 = replace existing target with new */
+				/* 0 = fail if target already exists */
+	__u8   Reserved[7];
+	__u64  RootDirectory;  /* MBZ for network operations (why says spec?) */
+	__le32 FileNameLength;
+	char   FileName[0];     /* New name to be assigned */
+} __packed; /* level 10 Set */
+
 /*
  * This level 18, although with struct with same name is different from cifs
  * level 0x107. Level 0x107 has an extra u64 between AccessFlags and
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index dbbdc39..b43036e 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -65,6 +65,9 @@ extern int smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon,
 		      const char *name, struct cifs_sb_info *cifs_sb);
 extern int smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon,
 		       const char *name, struct cifs_sb_info *cifs_sb);
+extern int smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
+			    const char *from_name, const char *to_name,
+			    struct cifs_sb_info *cifs_sb);
 
 extern int smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon,
 			  const char *full_path, int disposition,
@@ -106,5 +109,8 @@ extern int smb2_async_writev(struct cifs_writedata *wdata);
 extern int SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
 		      unsigned int *nbytes, struct kvec *iov, int n_vec);
 extern int SMB2_echo(struct TCP_Server_Info *server);
+extern int SMB2_rename(const unsigned int xid, struct cifs_tcon *tcon,
+		       u64 persistent_fid, u64 volatile_fid,
+		       __le16 *target_file);
 
 #endif			/* _SMB2PROTO_H */
-- 
1.7.1

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

* [PATCH 33/45] CIFS: Move hardlink to ops struct
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (31 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 32/45] CIFS: Add SMB2 support for rename operation Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
  2012-07-18 15:48   ` [PATCH 34/45] CIFS: Add SMB2 support for hardlink operation Pavel Shilovsky
                     ` (12 subsequent siblings)
  45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/cifsglob.h  |    4 +++
 fs/cifs/cifsproto.h |    8 ++---
 fs/cifs/cifssmb.c   |   20 +++++++------
 fs/cifs/link.c      |   74 ++++++++++++++++++++++++++++++--------------------
 fs/cifs/smb1ops.c   |    1 +
 5 files changed, 63 insertions(+), 44 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 0f8a466..de11b1f 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -278,6 +278,10 @@ struct smb_version_operations {
 	/* send rename request */
 	int (*rename)(const unsigned int, struct cifs_tcon *, const char *,
 		      const char *, struct cifs_sb_info *);
+	/* send create hardlink request */
+	int (*create_hardlink)(const unsigned int, struct cifs_tcon *,
+			       const char *, const char *,
+			       struct cifs_sb_info *);
 	/* open a file for non-posix mounts */
 	int (*open)(const unsigned int, struct cifs_tcon *, const char *, int,
 		    int, int, struct cifs_fid *, __u32 *, FILE_ALL_INFO *,
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index ef94f36..06b90bb 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -316,11 +316,9 @@ extern int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *tcon,
 				 int netfid, const char *target_name,
 				 const struct nls_table *nls_codepage,
 				 int remap_special_chars);
-extern int CIFSCreateHardLink(const unsigned int xid,
-			struct cifs_tcon *tcon,
-			const char *fromName, const char *toName,
-			const struct nls_table *nls_codepage,
-			int remap_special_chars);
+extern int CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
+			      const char *from_name, const char *to_name,
+			      struct cifs_sb_info *cifs_sb);
 extern int CIFSUnixCreateHardLink(const unsigned int xid,
 			struct cifs_tcon *tcon,
 			const char *fromName, const char *toName,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index c1a18a6..3029bf8 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -2921,8 +2921,8 @@ createHardLinkRetry:
 
 int
 CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
-		   const char *fromName, const char *toName,
-		   const struct nls_table *nls_codepage, int remap)
+		   const char *from_name, const char *to_name,
+		   struct cifs_sb_info *cifs_sb)
 {
 	int rc = 0;
 	NT_RENAME_REQ *pSMB = NULL;
@@ -2930,6 +2930,7 @@ CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
 	int bytes_returned;
 	int name_len, name_len2;
 	__u16 count;
+	int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
 
 	cFYI(1, "In CIFSCreateHardLink");
 winCreateHardLinkRetry:
@@ -2949,8 +2950,8 @@ winCreateHardLinkRetry:
 
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
 		name_len =
-		    cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName,
-				       PATH_MAX, nls_codepage, remap);
+		    cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
+				       PATH_MAX, cifs_sb->local_nls, remap);
 		name_len++;	/* trailing null */
 		name_len *= 2;
 
@@ -2959,17 +2960,18 @@ winCreateHardLinkRetry:
 		pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
 		name_len2 =
 		    cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
-				       toName, PATH_MAX, nls_codepage, remap);
+				       to_name, PATH_MAX, cifs_sb->local_nls,
+				       remap);
 		name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
 		name_len2 *= 2;	/* convert to bytes */
 	} else {	/* BB improve the check for buffer overruns BB */
-		name_len = strnlen(fromName, PATH_MAX);
+		name_len = strnlen(from_name, PATH_MAX);
 		name_len++;	/* trailing null */
-		strncpy(pSMB->OldFileName, fromName, name_len);
-		name_len2 = strnlen(toName, PATH_MAX);
+		strncpy(pSMB->OldFileName, from_name, name_len);
+		name_len2 = strnlen(to_name, PATH_MAX);
 		name_len2++;	/* trailing null */
 		pSMB->OldFileName[name_len] = 0x04;	/* 2nd buffer format */
-		strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
+		strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
 		name_len2++;	/* trailing null */
 		name_len2++;	/* signature byte */
 	}
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index d08b76c..169fa74 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -391,70 +391,84 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
 {
 	int rc = -EACCES;
 	unsigned int xid;
-	char *fromName = NULL;
-	char *toName = NULL;
+	char *from_name = NULL;
+	char *to_name = NULL;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 	struct tcon_link *tlink;
-	struct cifs_tcon *pTcon;
+	struct cifs_tcon *tcon;
+	struct TCP_Server_Info *server;
 	struct cifsInodeInfo *cifsInode;
 
 	tlink = cifs_sb_tlink(cifs_sb);
 	if (IS_ERR(tlink))
 		return PTR_ERR(tlink);
-	pTcon = tlink_tcon(tlink);
+	tcon = tlink_tcon(tlink);
 
 	xid = get_xid();
 
-	fromName = build_path_from_dentry(old_file);
-	toName = build_path_from_dentry(direntry);
-	if ((fromName == NULL) || (toName == NULL)) {
+	from_name = build_path_from_dentry(old_file);
+	to_name = build_path_from_dentry(direntry);
+	if ((from_name == NULL) || (to_name == NULL)) {
 		rc = -ENOMEM;
 		goto cifs_hl_exit;
 	}
 
-	if (pTcon->unix_ext)
-		rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName,
+	if (tcon->unix_ext)
+		rc = CIFSUnixCreateHardLink(xid, tcon, from_name, to_name,
 					    cifs_sb->local_nls,
 					    cifs_sb->mnt_cifs_flags &
 						CIFS_MOUNT_MAP_SPECIAL_CHR);
 	else {
-		rc = CIFSCreateHardLink(xid, pTcon, fromName, toName,
-					cifs_sb->local_nls,
-					cifs_sb->mnt_cifs_flags &
-						CIFS_MOUNT_MAP_SPECIAL_CHR);
+		server = tcon->ses->server;
+		if (!server->ops->create_hardlink)
+			return -ENOSYS;
+		rc = server->ops->create_hardlink(xid, tcon, from_name, to_name,
+						  cifs_sb);
 		if ((rc == -EIO) || (rc == -EINVAL))
 			rc = -EOPNOTSUPP;
 	}
 
 	d_drop(direntry);	/* force new lookup from server of target */
 
-	/* if source file is cached (oplocked) revalidate will not go to server
-	   until the file is closed or oplock broken so update nlinks locally */
+	/*
+	 * if source file is cached (oplocked) revalidate will not go to server
+	 * until the file is closed or oplock broken so update nlinks locally
+	 */
 	if (old_file->d_inode) {
 		cifsInode = CIFS_I(old_file->d_inode);
 		if (rc == 0) {
 			inc_nlink(old_file->d_inode);
-/* BB should we make this contingent on superblock flag NOATIME? */
-/*			old_file->d_inode->i_ctime = CURRENT_TIME;*/
-			/* parent dir timestamps will update from srv
-			within a second, would it really be worth it
-			to set the parent dir cifs inode time to zero
-			to force revalidate (faster) for it too? */
+			/*
+			 * BB should we make this contingent on superblock flag
+			 * NOATIME?
+			 */
+			/* old_file->d_inode->i_ctime = CURRENT_TIME; */
+			/*
+			 * parent dir timestamps will update from srv within a
+			 * second, would it really be worth it to set the parent
+			 * dir cifs inode time to zero to force revalidate
+			 * (faster) for it too?
+			 */
 		}
-		/* if not oplocked will force revalidate to get info
-		   on source file from srv */
+		/*
+		 * if not oplocked will force revalidate to get info on source
+		 * file from srv
+		 */
 		cifsInode->time = 0;
 
-		/* Will update parent dir timestamps from srv within a second.
-		   Would it really be worth it to set the parent dir (cifs
-		   inode) time field to zero to force revalidate on parent
-		   directory faster ie
-			CIFS_I(inode)->time = 0;  */
+		/*
+		 * Will update parent dir timestamps from srv within a second.
+		 * Would it really be worth it to set the parent dir (cifs
+		 * inode) time field to zero to force revalidate on parent
+		 * directory faster ie
+		 *
+		 * CIFS_I(inode)->time = 0;
+		 */
 	}
 
 cifs_hl_exit:
-	kfree(fromName);
-	kfree(toName);
+	kfree(from_name);
+	kfree(to_name);
 	free_xid(xid);
 	cifs_put_tlink(tlink);
 	return rc;
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 3773920..e5d6344 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -801,6 +801,7 @@ struct smb_version_operations smb1_operations = {
 	.unlink = CIFSSMBDelFile,
 	.rename_pending_delete = cifs_rename_pending_delete,
 	.rename = CIFSSMBRename,
+	.create_hardlink = CIFSCreateHardLink,
 	.open = cifs_open_file,
 	.set_fid = cifs_set_fid,
 	.close = cifs_close_file,
-- 
1.7.1

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

* [PATCH 34/45] CIFS: Add SMB2 support for hardlink operation
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (32 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 33/45] CIFS: Move hardlink to ops struct Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
  2012-07-18 15:48   ` [PATCH 35/45] CIFS: Move set_file_size to ops struct Pavel Shilovsky
                     ` (11 subsequent siblings)
  45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/smb2glob.h  |    1 +
 fs/cifs/smb2inode.c |   34 ++++++++++++++++++++++++++++------
 fs/cifs/smb2ops.c   |    1 +
 fs/cifs/smb2pdu.c   |   31 +++++++++++++++++++++++++++++++
 fs/cifs/smb2pdu.h   |    9 +++++++++
 fs/cifs/smb2proto.h |    6 ++++++
 6 files changed, 76 insertions(+), 6 deletions(-)

diff --git a/fs/cifs/smb2glob.h b/fs/cifs/smb2glob.h
index 8635574..21555d8 100644
--- a/fs/cifs/smb2glob.h
+++ b/fs/cifs/smb2glob.h
@@ -40,6 +40,7 @@
 #define SMB2_OP_MKDIR 5
 #define SMB2_OP_RENAME 6
 #define SMB2_OP_DELETE 7
+#define SMB2_OP_HARDLINK 8
 
 /* Used when constructing chained read requests. */
 #define CHAINED_REQUEST 1
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index a6952ba..1921c9c 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -78,6 +78,10 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
 		tmprc = SMB2_rename(xid, tcon, persistent_fid, volatile_fid,
 				    (__le16 *)data);
 		break;
+	case SMB2_OP_HARDLINK:
+		tmprc = SMB2_set_hardlink(xid, tcon, persistent_fid,
+					  volatile_fid, (__le16 *)data);
+		break;
 	default:
 		cERROR(1, "Invalid command");
 		break;
@@ -175,10 +179,10 @@ smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
 				  SMB2_OP_DELETE);
 }
 
-int
-smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
-		 const char *from_name, const char *to_name,
-		 struct cifs_sb_info *cifs_sb)
+static int
+smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
+		   const char *from_name, const char *to_name,
+		   struct cifs_sb_info *cifs_sb, __u32 access, int command)
 {
 	__le16 *smb2_to_name = NULL;
 	int rc;
@@ -189,9 +193,27 @@ smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
 		goto smb2_rename_path;
 	}
 
-	rc = smb2_open_op_close(xid, tcon, cifs_sb, from_name, DELETE,
-				FILE_OPEN, 0, 0, smb2_to_name, SMB2_OP_RENAME);
+	rc = smb2_open_op_close(xid, tcon, cifs_sb, from_name, access,
+				FILE_OPEN, 0, 0, smb2_to_name, command);
 smb2_rename_path:
 	kfree(smb2_to_name);
 	return rc;
 }
+
+int
+smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
+		 const char *from_name, const char *to_name,
+		 struct cifs_sb_info *cifs_sb)
+{
+	return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
+				  DELETE, SMB2_OP_RENAME);
+}
+
+int
+smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
+		     const char *from_name, const char *to_name,
+		     struct cifs_sb_info *cifs_sb)
+{
+	return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
+				  FILE_READ_ATTRIBUTES, SMB2_OP_HARDLINK);
+}
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index da13a60..f9e3a13 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -443,6 +443,7 @@ struct smb_version_operations smb21_operations = {
 	.rmdir = smb2_rmdir,
 	.unlink = smb2_unlink,
 	.rename = smb2_rename_path,
+	.create_hardlink = smb2_create_hardlink,
 	.open = smb2_open_file,
 	.set_fid = smb2_set_fid,
 	.close = smb2_close_file,
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 515c141..4d9ef2c 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1704,3 +1704,34 @@ SMB2_rename(const unsigned int xid, struct cifs_tcon *tcon,
 	kfree(data);
 	return rc;
 }
+
+int
+SMB2_set_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
+		  u64 persistent_fid, u64 volatile_fid, __le16 *target_file)
+{
+	struct smb2_file_link_info info;
+	void **data;
+	unsigned int size[2];
+	int rc;
+	int len = (2 * UniStrnlen((wchar_t *)target_file, PATH_MAX));
+
+	data = kmalloc(sizeof(void *) * 2, GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	info.ReplaceIfExists = 0; /* 1 = replace existing link with new */
+			      /* 0 = fail if link already exists */
+	info.RootDirectory = 0;  /* MBZ for network ops (why does spec say?) */
+	info.FileNameLength = cpu_to_le32(len);
+
+	data[0] = &info;
+	size[0] = sizeof(struct smb2_file_link_info);
+
+	data[1] = target_file;
+	size[1] = len + 2 /* null */;
+
+	rc = send_set_info(xid, tcon, persistent_fid, volatile_fid,
+			   FILE_LINK_INFORMATION, 2, data, size);
+	kfree(data);
+	return rc;
+}
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index e2c7887..34a9329 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -651,6 +651,15 @@ struct smb2_file_rename_info { /* encoding of request for level 10 */
 	char   FileName[0];     /* New name to be assigned */
 } __packed; /* level 10 Set */
 
+struct smb2_file_link_info { /* encoding of request for level 11 */
+	__u8   ReplaceIfExists; /* 1 = replace existing link with new */
+				/* 0 = fail if link already exists */
+	__u8   Reserved[7];
+	__u64  RootDirectory;  /* MBZ for network operations (why says spec?) */
+	__le32 FileNameLength;
+	char   FileName[0];     /* Name to be assigned to new link */
+} __packed; /* level 11 Set */
+
 /*
  * This level 18, although with struct with same name is different from cifs
  * level 0x107. Level 0x107 has an extra u64 between AccessFlags and
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index b43036e..99f6945 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -68,6 +68,9 @@ extern int smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon,
 extern int smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
 			    const char *from_name, const char *to_name,
 			    struct cifs_sb_info *cifs_sb);
+extern int smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
+				const char *from_name, const char *to_name,
+				struct cifs_sb_info *cifs_sb);
 
 extern int smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon,
 			  const char *full_path, int disposition,
@@ -112,5 +115,8 @@ extern int SMB2_echo(struct TCP_Server_Info *server);
 extern int SMB2_rename(const unsigned int xid, struct cifs_tcon *tcon,
 		       u64 persistent_fid, u64 volatile_fid,
 		       __le16 *target_file);
+extern int SMB2_set_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
+			     u64 persistent_fid, u64 volatile_fid,
+			     __le16 *target_file);
 
 #endif			/* _SMB2PROTO_H */
-- 
1.7.1

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

* [PATCH 35/45] CIFS: Move set_file_size to ops struct
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (33 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 34/45] CIFS: Add SMB2 support for hardlink operation Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
  2012-07-18 15:48   ` [PATCH 36/45] CIFS: Add SMB2 support for set_file_size Pavel Shilovsky
                     ` (10 subsequent siblings)
  45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/cifsglob.h  |    6 +++
 fs/cifs/cifsproto.h |   10 ++---
 fs/cifs/cifssmb.c   |   40 ++++++++++---------
 fs/cifs/inode.c     |  106 +++++++++++++++++++++++++++------------------------
 fs/cifs/smb1ops.c   |    2 +
 5 files changed, 89 insertions(+), 75 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index de11b1f..3f7a53d 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -252,6 +252,12 @@ struct smb_version_operations {
 	int (*get_srv_inum)(const unsigned int, struct cifs_tcon *,
 			    struct cifs_sb_info *, const char *,
 			    u64 *uniqueid, FILE_ALL_INFO *);
+	/* set size by path */
+	int (*set_path_size)(const unsigned int, struct cifs_tcon *,
+			     const char *, __u64, struct cifs_sb_info *, bool);
+	/* set size by file handle */
+	int (*set_file_size)(const unsigned int, struct cifs_tcon *,
+			     struct cifsFileInfo *, __u64, bool);
 	/* build a full path to the root of the mount */
 	char * (*build_path_to_root)(struct smb_vol *, struct cifs_sb_info *,
 				     struct cifs_tcon *);
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 06b90bb..6e04941 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -270,13 +270,11 @@ extern int CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon,
 			const struct nls_table *nls_codepage);
 #endif /* possibly unneeded function */
 extern int CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
-			const char *fileName, __u64 size,
-			bool setAllocationSizeFlag,
-			const struct nls_table *nls_codepage,
-			int remap_special_chars);
+			 const char *file_name, __u64 size,
+			 struct cifs_sb_info *cifs_sb, bool set_allocation);
 extern int CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
-			 __u64 size, __u16 fileHandle, __u32 opener_pid,
-			bool AllocSizeFlag);
+			      struct cifsFileInfo *cfile, __u64 size,
+			      bool set_allocation);
 
 struct cifs_unix_set_info_args {
 	__u64	ctime;
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 3029bf8..875a8c2 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -5392,16 +5392,16 @@ QFSPosixRetry:
 }
 
 
-/* We can not use write of zero bytes trick to
-   set file size due to need for large file support.  Also note that
-   this SetPathInfo is preferred to SetFileInfo based method in next
-   routine which is only needed to work around a sharing violation bug
-   in Samba which this routine can run into */
-
+/*
+ * We can not use write of zero bytes trick to set file size due to need for
+ * large file support. Also note that this SetPathInfo is preferred to
+ * SetFileInfo based method in next routine which is only needed to work around
+ * a sharing violation bugin Samba which this routine can run into.
+ */
 int
 CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
-	      const char *fileName, __u64 size, bool SetAllocation,
-	      const struct nls_table *nls_codepage, int remap)
+	      const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
+	      bool set_allocation)
 {
 	struct smb_com_transaction2_spi_req *pSMB = NULL;
 	struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
@@ -5409,6 +5409,8 @@ CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
 	int name_len;
 	int rc = 0;
 	int bytes_returned = 0;
+	int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
+
 	__u16 params, byte_count, data_count, param_offset, offset;
 
 	cFYI(1, "In SetEOF");
@@ -5420,14 +5422,14 @@ SetEOFRetry:
 
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
 		name_len =
-		    cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
-				       PATH_MAX, nls_codepage, remap);
+		    cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
+				       PATH_MAX, cifs_sb->local_nls, remap);
 		name_len++;	/* trailing null */
 		name_len *= 2;
 	} else {	/* BB improve the check for buffer overruns BB */
-		name_len = strnlen(fileName, PATH_MAX);
+		name_len = strnlen(file_name, PATH_MAX);
 		name_len++;	/* trailing null */
-		strncpy(pSMB->FileName, fileName, name_len);
+		strncpy(pSMB->FileName, file_name, name_len);
 	}
 	params = 6 + name_len;
 	data_count = sizeof(struct file_end_of_file_info);
@@ -5441,7 +5443,7 @@ SetEOFRetry:
 	param_offset = offsetof(struct smb_com_transaction2_spi_req,
 				InformationLevel) - 4;
 	offset = param_offset + params;
-	if (SetAllocation) {
+	if (set_allocation) {
 		if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
 			pSMB->InformationLevel =
 				cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
@@ -5488,8 +5490,8 @@ SetEOFRetry:
 }
 
 int
-CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon, __u64 size,
-		   __u16 fid, __u32 pid_of_opener, bool SetAllocation)
+CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
+		   struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
 {
 	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
 	struct file_end_of_file_info *parm_data;
@@ -5503,8 +5505,8 @@ CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon, __u64 size,
 	if (rc)
 		return rc;
 
-	pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
-	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
+	pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
+	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
 
 	params = 6;
 	pSMB->MaxSetupCount = 0;
@@ -5533,8 +5535,8 @@ CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon, __u64 size,
 				+ offset);
 	pSMB->DataOffset = cpu_to_le16(offset);
 	parm_data->FileSize = cpu_to_le64(size);
-	pSMB->Fid = fid;
-	if (SetAllocation) {
+	pSMB->Fid = cfile->fid.netfid;
+	if (set_allocation) {
 		if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
 			pSMB->InformationLevel =
 				cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index f1448d9..16101a0 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1883,7 +1883,8 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
 	struct cifsInodeInfo *cifsInode = CIFS_I(inode);
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 	struct tcon_link *tlink = NULL;
-	struct cifs_tcon *pTcon = NULL;
+	struct cifs_tcon *tcon = NULL;
+	struct TCP_Server_Info *server;
 	struct cifs_io_parms io_parms;
 
 	/*
@@ -1897,19 +1898,21 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
 	 */
 	open_file = find_writable_file(cifsInode, true);
 	if (open_file) {
-		__u16 nfid = open_file->fid.netfid;
-		__u32 npid = open_file->pid;
-		pTcon = tlink_tcon(open_file->tlink);
-		rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, nfid,
-					npid, false);
+		tcon = tlink_tcon(open_file->tlink);
+		server = tcon->ses->server;
+		if (server->ops->set_file_size)
+			rc = server->ops->set_file_size(xid, tcon, open_file,
+							attrs->ia_size, false);
+		else
+			rc = -ENOSYS;
 		cifsFileInfo_put(open_file);
 		cFYI(1, "SetFSize for attrs rc = %d", rc);
 		if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
 			unsigned int bytes_written;
 
-			io_parms.netfid = nfid;
-			io_parms.pid = npid;
-			io_parms.tcon = pTcon;
+			io_parms.netfid = open_file->fid.netfid;
+			io_parms.pid = open_file->pid;
+			io_parms.tcon = tcon;
 			io_parms.offset = 0;
 			io_parms.length = attrs->ia_size;
 			rc = CIFSSMBWrite(xid, &io_parms, &bytes_written,
@@ -1919,52 +1922,55 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
 	} else
 		rc = -EINVAL;
 
-	if (rc != 0) {
-		if (pTcon == NULL) {
-			tlink = cifs_sb_tlink(cifs_sb);
-			if (IS_ERR(tlink))
-				return PTR_ERR(tlink);
-			pTcon = tlink_tcon(tlink);
-		}
+	if (!rc)
+		goto set_size_out;
 
-		/* 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
-		   it by handle */
-		rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size,
-				   false, cifs_sb->local_nls,
+	if (tcon == NULL) {
+		tlink = cifs_sb_tlink(cifs_sb);
+		if (IS_ERR(tlink))
+			return PTR_ERR(tlink);
+		tcon = tlink_tcon(tlink);
+		server = tcon->ses->server;
+	}
+
+	/*
+	 * 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 it by handle.
+	 */
+	if (server->ops->set_path_size)
+		rc = server->ops->set_path_size(xid, tcon, full_path,
+						attrs->ia_size, cifs_sb, false);
+	else
+		rc = -ENOSYS;
+	cFYI(1, "SetEOF by path (setattrs) rc = %d", rc);
+	if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
+		__u16 netfid;
+		int oplock = 0;
+
+		rc = SMBLegacyOpen(xid, tcon, full_path, FILE_OPEN,
+				   GENERIC_WRITE, CREATE_NOT_DIR, &netfid,
+				   &oplock, NULL, cifs_sb->local_nls,
 				   cifs_sb->mnt_cifs_flags &
-					CIFS_MOUNT_MAP_SPECIAL_CHR);
-		cFYI(1, "SetEOF by path (setattrs) rc = %d", rc);
-		if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
-			__u16 netfid;
-			int oplock = 0;
-
-			rc = SMBLegacyOpen(xid, pTcon, full_path,
-				FILE_OPEN, GENERIC_WRITE,
-				CREATE_NOT_DIR, &netfid, &oplock, NULL,
-				cifs_sb->local_nls,
-				cifs_sb->mnt_cifs_flags &
-					CIFS_MOUNT_MAP_SPECIAL_CHR);
-			if (rc == 0) {
-				unsigned int bytes_written;
-
-				io_parms.netfid = netfid;
-				io_parms.pid = current->tgid;
-				io_parms.tcon = pTcon;
-				io_parms.offset = 0;
-				io_parms.length = attrs->ia_size;
-				rc = CIFSSMBWrite(xid, &io_parms,
-						  &bytes_written,
-						  NULL, NULL,  1);
-				cFYI(1, "wrt seteof rc %d", rc);
-				CIFSSMBClose(xid, pTcon, netfid);
-			}
+						CIFS_MOUNT_MAP_SPECIAL_CHR);
+		if (rc == 0) {
+			unsigned int bytes_written;
+
+			io_parms.netfid = netfid;
+			io_parms.pid = current->tgid;
+			io_parms.tcon = tcon;
+			io_parms.offset = 0;
+			io_parms.length = attrs->ia_size;
+			rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, NULL,
+					  NULL,  1);
+			cFYI(1, "wrt seteof rc %d", rc);
+			CIFSSMBClose(xid, tcon, netfid);
 		}
-		if (tlink)
-			cifs_put_tlink(tlink);
 	}
+	if (tlink)
+		cifs_put_tlink(tlink);
 
+set_size_out:
 	if (rc == 0) {
 		cifsInode->server_eof = attrs->ia_size;
 		cifs_setsize(inode, attrs->ia_size);
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index e5d6344..b73d275 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -793,6 +793,8 @@ struct smb_version_operations smb1_operations = {
 	.query_path_info = cifs_query_path_info,
 	.query_file_info = cifs_query_file_info,
 	.get_srv_inum = cifs_get_srv_inum,
+	.set_path_size = CIFSSMBSetEOF,
+	.set_file_size = CIFSSMBSetFileSize,
 	.build_path_to_root = cifs_build_path_to_root,
 	.echo = CIFSSMBEcho,
 	.mkdir = CIFSSMBMkDir,
-- 
1.7.1

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

* [PATCH 36/45] CIFS: Add SMB2 support for set_file_size
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (34 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 35/45] CIFS: Move set_file_size to ops struct Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
  2012-07-18 15:48   ` [PATCH 37/45] CIFS: Move set_file_info to ops struct Pavel Shilovsky
                     ` (9 subsequent siblings)
  45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/smb2glob.h  |    1 +
 fs/cifs/smb2inode.c |   15 +++++++++++++++
 fs/cifs/smb2ops.c   |   11 +++++++++++
 fs/cifs/smb2pdu.c   |   26 +++++++++++++++++++++++---
 fs/cifs/smb2pdu.h   |    4 ++++
 fs/cifs/smb2proto.h |    6 ++++++
 6 files changed, 60 insertions(+), 3 deletions(-)

diff --git a/fs/cifs/smb2glob.h b/fs/cifs/smb2glob.h
index 21555d8..05d429b 100644
--- a/fs/cifs/smb2glob.h
+++ b/fs/cifs/smb2glob.h
@@ -41,6 +41,7 @@
 #define SMB2_OP_RENAME 6
 #define SMB2_OP_DELETE 7
 #define SMB2_OP_HARDLINK 8
+#define SMB2_OP_SET_EOF 9
 
 /* Used when constructing chained read requests. */
 #define CHAINED_REQUEST 1
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index 1921c9c..2905830 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -82,6 +82,10 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
 		tmprc = SMB2_set_hardlink(xid, tcon, persistent_fid,
 					  volatile_fid, (__le16 *)data);
 		break;
+	case SMB2_OP_SET_EOF:
+		tmprc = SMB2_set_eof(xid, tcon, persistent_fid, volatile_fid,
+				     current->tgid, (__le64 *)data);
+		break;
 	default:
 		cERROR(1, "Invalid command");
 		break;
@@ -217,3 +221,14 @@ smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
 	return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
 				  FILE_READ_ATTRIBUTES, SMB2_OP_HARDLINK);
 }
+
+int
+smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
+		   const char *full_path, __u64 size,
+		   struct cifs_sb_info *cifs_sb, bool set_alloc)
+{
+	__le64 eof = cpu_to_le64(size);
+	return smb2_open_op_close(xid, tcon, cifs_sb, full_path,
+				  FILE_WRITE_DATA, FILE_OPEN, 0, 0, &eof,
+				  SMB2_OP_SET_EOF);
+}
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index f9e3a13..3aad536 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -406,6 +406,15 @@ smb2_sync_write(const unsigned int xid, struct cifsFileInfo *cfile,
 	return SMB2_write(xid, parms, written, iov, nr_segs);
 }
 
+static int
+smb2_set_file_size(const unsigned int xid, struct cifs_tcon *tcon,
+		   struct cifsFileInfo *cfile, __u64 size, bool set_alloc)
+{
+	__le64 eof = cpu_to_le64(size);
+	return SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid,
+			    cfile->fid.volatile_fid, cfile->pid, &eof);
+}
+
 struct smb_version_operations smb21_operations = {
 	.setup_request = smb2_setup_request,
 	.setup_async_request = smb2_setup_async_request,
@@ -437,6 +446,8 @@ struct smb_version_operations smb21_operations = {
 	.query_path_info = smb2_query_path_info,
 	.get_srv_inum = smb2_get_srv_inum,
 	.query_file_info = smb2_query_file_info,
+	.set_path_size = smb2_set_path_size,
+	.set_file_size = smb2_set_file_size,
 	.build_path_to_root = smb2_build_path_to_root,
 	.mkdir = smb2_mkdir,
 	.mkdir_setinfo = smb2_mkdir_setinfo,
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 4d9ef2c..f1edc5e 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1600,7 +1600,7 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
 
 static int
 send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
-	       u64 persistent_fid, u64 volatile_fid, int info_class,
+	       u64 persistent_fid, u64 volatile_fid, u32 pid, int info_class,
 	       unsigned int num, void **data, unsigned int *size)
 {
 	struct smb2_set_info_req *req;
@@ -1630,6 +1630,8 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
 		return rc;
 	}
 
+	req->hdr.ProcessId = cpu_to_le32(pid);
+
 	req->InfoType = SMB2_O_INFO_FILE;
 	req->FileInfoClass = info_class;
 	req->PersistentFileId = persistent_fid;
@@ -1700,7 +1702,8 @@ SMB2_rename(const unsigned int xid, struct cifs_tcon *tcon,
 	size[1] = len + 2 /* null */;
 
 	rc = send_set_info(xid, tcon, persistent_fid, volatile_fid,
-			   FILE_RENAME_INFORMATION, 2, data, size);
+			   current->tgid, FILE_RENAME_INFORMATION, 2, data,
+			   size);
 	kfree(data);
 	return rc;
 }
@@ -1731,7 +1734,24 @@ SMB2_set_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
 	size[1] = len + 2 /* null */;
 
 	rc = send_set_info(xid, tcon, persistent_fid, volatile_fid,
-			   FILE_LINK_INFORMATION, 2, data, size);
+			   current->tgid, FILE_LINK_INFORMATION, 2, data, size);
 	kfree(data);
 	return rc;
 }
+
+int
+SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
+	     u64 volatile_fid, u32 pid, __le64 *eof)
+{
+	struct smb2_file_eof_info info;
+	void *data;
+	unsigned int size;
+
+	info.EndOfFile = *eof;
+
+	data = &info;
+	size = sizeof(struct smb2_file_eof_info);
+
+	return send_set_info(xid, tcon, persistent_fid, volatile_fid, pid,
+			     FILE_END_OF_FILE_INFORMATION, 1, &data, &size);
+}
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 34a9329..45ecae9 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -688,4 +688,8 @@ struct smb2_file_all_info { /* data block encoding of response to level 18 */
 	char   FileName[1];
 } __packed; /* level 18 Query */
 
+struct smb2_file_eof_info { /* encoding of request for level 10 */
+	__le64 EndOfFile; /* new end of file value */
+} __packed; /* level 20 Set */
+
 #endif				/* _SMB2PDU_H */
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 99f6945..3d48662 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -56,6 +56,9 @@ extern int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
 				struct cifs_sb_info *cifs_sb,
 				const char *full_path, FILE_ALL_INFO *data,
 				bool *adjust_tz);
+extern int smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
+			      const char *full_path, __u64 size,
+			      struct cifs_sb_info *cifs_sb, bool set_alloc);
 extern int smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon,
 		      const char *name, struct cifs_sb_info *cifs_sb);
 extern void smb2_mkdir_setinfo(struct inode *inode, const char *full_path,
@@ -118,5 +121,8 @@ extern int SMB2_rename(const unsigned int xid, struct cifs_tcon *tcon,
 extern int SMB2_set_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
 			     u64 persistent_fid, u64 volatile_fid,
 			     __le16 *target_file);
+extern int SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon,
+			u64 persistent_fid, u64 volatile_fid, u32 pid,
+			__le64 *eof);
 
 #endif			/* _SMB2PROTO_H */
-- 
1.7.1

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

* [PATCH 37/45] CIFS: Move set_file_info to ops struct
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (35 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 36/45] CIFS: Add SMB2 support for set_file_size Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
  2012-07-18 15:48   ` [PATCH 38/45] CIFS: Add set_file_info support for SMB2 Pavel Shilovsky
                     ` (8 subsequent siblings)
  45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/cifsglob.h |    3 ++
 fs/cifs/inode.c    |   79 ++++------------------------------------------------
 fs/cifs/smb1ops.c  |   79 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 88 insertions(+), 73 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 3f7a53d..7c20d5a 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -258,6 +258,9 @@ struct smb_version_operations {
 	/* set size by file handle */
 	int (*set_file_size)(const unsigned int, struct cifs_tcon *,
 			     struct cifsFileInfo *, __u64, bool);
+	/* set attributes */
+	int (*set_file_info)(struct inode *, const char *, FILE_BASIC_INFO *,
+			     const unsigned int);
 	/* build a full path to the root of the mount */
 	char * (*build_path_to_root)(struct smb_vol *, struct cifs_sb_info *,
 				     struct cifs_tcon *);
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 16101a0..92c6c27 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -888,21 +888,18 @@ int
 cifs_set_file_info(struct inode *inode, struct iattr *attrs, unsigned int xid,
 		   char *full_path, __u32 dosattr)
 {
-	int rc;
-	int oplock = 0;
-	__u16 netfid;
-	__u32 netpid;
 	bool set_time = false;
-	struct cifsFileInfo *open_file;
-	struct cifsInodeInfo *cifsInode = CIFS_I(inode);
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
-	struct tcon_link *tlink = NULL;
-	struct cifs_tcon *pTcon;
+	struct TCP_Server_Info *server;
 	FILE_BASIC_INFO	info_buf;
 
 	if (attrs == NULL)
 		return -EINVAL;
 
+	server = cifs_sb_master_tcon(cifs_sb)->ses->server;
+	if (!server->ops->set_file_info)
+		return -ENOSYS;
+
 	if (attrs->ia_valid & ATTR_ATIME) {
 		set_time = true;
 		info_buf.LastAccessTime =
@@ -933,71 +930,7 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, unsigned int xid,
 	info_buf.CreationTime = 0;	/* don't change */
 	info_buf.Attributes = cpu_to_le32(dosattr);
 
-	/*
-	 * If the file is already open for write, just use that fileid
-	 */
-	open_file = find_writable_file(cifsInode, true);
-	if (open_file) {
-		netfid = open_file->fid.netfid;
-		netpid = open_file->pid;
-		pTcon = tlink_tcon(open_file->tlink);
-		goto set_via_filehandle;
-	}
-
-	tlink = cifs_sb_tlink(cifs_sb);
-	if (IS_ERR(tlink)) {
-		rc = PTR_ERR(tlink);
-		tlink = NULL;
-		goto out;
-	}
-	pTcon = tlink_tcon(tlink);
-
-	/*
-	 * NT4 apparently returns success on this call, but it doesn't
-	 * really work.
-	 */
-	if (!(pTcon->ses->flags & CIFS_SES_NT4)) {
-		rc = CIFSSMBSetPathInfo(xid, pTcon, full_path,
-				     &info_buf, cifs_sb->local_nls,
-				     cifs_sb->mnt_cifs_flags &
-					CIFS_MOUNT_MAP_SPECIAL_CHR);
-		if (rc == 0) {
-			cifsInode->cifsAttrs = dosattr;
-			goto out;
-		} else if (rc != -EOPNOTSUPP && rc != -EINVAL)
-			goto out;
-	}
-
-	cFYI(1, "calling SetFileInfo since SetPathInfo for "
-		 "times not supported by this server");
-	rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
-			 SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
-			 CREATE_NOT_DIR, &netfid, &oplock,
-			 NULL, cifs_sb->local_nls,
-			 cifs_sb->mnt_cifs_flags &
-				CIFS_MOUNT_MAP_SPECIAL_CHR);
-
-	if (rc != 0) {
-		if (rc == -EIO)
-			rc = -EINVAL;
-		goto out;
-	}
-
-	netpid = current->tgid;
-
-set_via_filehandle:
-	rc = CIFSSMBSetFileInfo(xid, pTcon, &info_buf, netfid, netpid);
-	if (!rc)
-		cifsInode->cifsAttrs = dosattr;
-
-	if (open_file == NULL)
-		CIFSSMBClose(xid, pTcon, netfid);
-	else
-		cifsFileInfo_put(open_file);
-out:
-	if (tlink != NULL)
-		cifs_put_tlink(tlink);
-	return rc;
+	return server->ops->set_file_info(inode, full_path, &info_buf, xid);
 }
 
 /*
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index b73d275..ed31196 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -758,6 +758,84 @@ cifs_sync_write(const unsigned int xid, struct cifsFileInfo *cfile,
 	return CIFSSMBWrite2(xid, parms, written, iov, nr_segs);
 }
 
+static int
+smb_set_file_info(struct inode *inode, const char *full_path,
+		  FILE_BASIC_INFO *buf, const unsigned int xid)
+{
+	int oplock = 0;
+	int rc;
+	__u16 netfid;
+	__u32 netpid;
+	struct cifsFileInfo *open_file;
+	struct cifsInodeInfo *cinode = CIFS_I(inode);
+	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+	struct tcon_link *tlink = NULL;
+	struct cifs_tcon *tcon;
+	FILE_BASIC_INFO info_buf;
+
+	/* if the file is already open for write, just use that fileid */
+	open_file = find_writable_file(cinode, true);
+	if (open_file) {
+		netfid = open_file->fid.netfid;
+		netpid = open_file->pid;
+		tcon = tlink_tcon(open_file->tlink);
+		goto set_via_filehandle;
+	}
+
+	tlink = cifs_sb_tlink(cifs_sb);
+	if (IS_ERR(tlink)) {
+		rc = PTR_ERR(tlink);
+		tlink = NULL;
+		goto out;
+	}
+	tcon = tlink_tcon(tlink);
+
+	/*
+	 * NT4 apparently returns success on this call, but it doesn't really
+	 * work.
+	 */
+	if (!(tcon->ses->flags & CIFS_SES_NT4)) {
+		rc = CIFSSMBSetPathInfo(xid, tcon, full_path, buf,
+					cifs_sb->local_nls,
+					cifs_sb->mnt_cifs_flags &
+						CIFS_MOUNT_MAP_SPECIAL_CHR);
+		if (rc == 0) {
+			cinode->cifsAttrs = le32_to_cpu(buf->Attributes);
+			goto out;
+		} else if (rc != -EOPNOTSUPP && rc != -EINVAL)
+			goto out;
+	}
+
+	cFYI(1, "calling SetFileInfo since SetPathInfo for times not supported "
+		"by this server");
+	rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN,
+			 SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, CREATE_NOT_DIR,
+			 &netfid, &oplock, NULL, cifs_sb->local_nls,
+			 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+
+	if (rc != 0) {
+		if (rc == -EIO)
+			rc = -EINVAL;
+		goto out;
+	}
+
+	netpid = current->tgid;
+
+set_via_filehandle:
+	rc = CIFSSMBSetFileInfo(xid, tcon, &info_buf, netfid, netpid);
+	if (!rc)
+		cinode->cifsAttrs = le32_to_cpu(buf->Attributes);
+
+	if (open_file == NULL)
+		CIFSSMBClose(xid, tcon, netfid);
+	else
+		cifsFileInfo_put(open_file);
+out:
+	if (tlink != NULL)
+		cifs_put_tlink(tlink);
+	return rc;
+}
+
 struct smb_version_operations smb1_operations = {
 	.send_cancel = send_nt_cancel,
 	.compare_fids = cifs_compare_fids,
@@ -795,6 +873,7 @@ struct smb_version_operations smb1_operations = {
 	.get_srv_inum = cifs_get_srv_inum,
 	.set_path_size = CIFSSMBSetEOF,
 	.set_file_size = CIFSSMBSetFileSize,
+	.set_file_info = smb_set_file_info,
 	.build_path_to_root = cifs_build_path_to_root,
 	.echo = CIFSSMBEcho,
 	.mkdir = CIFSSMBMkDir,
-- 
1.7.1

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

* [PATCH 38/45] CIFS: Add set_file_info support for SMB2
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (36 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 37/45] CIFS: Move set_file_info to ops struct Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
  2012-07-18 15:48   ` [PATCH 39/45] CIFS: Move readdir code to ops struct Pavel Shilovsky
                     ` (7 subsequent siblings)
  45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/smb2inode.c |   22 ++++++++++++++++++++++
 fs/cifs/smb2ops.c   |    1 +
 fs/cifs/smb2pdu.c   |   11 +++++++++++
 fs/cifs/smb2proto.h |    5 +++++
 4 files changed, 39 insertions(+), 0 deletions(-)

diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index 2905830..1bd6b0f 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -86,6 +86,10 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
 		tmprc = SMB2_set_eof(xid, tcon, persistent_fid, volatile_fid,
 				     current->tgid, (__le64 *)data);
 		break;
+	case SMB2_OP_SET_INFO:
+		tmprc = SMB2_set_info(xid, tcon, persistent_fid, volatile_fid,
+				      (FILE_BASIC_INFO *)data);
+		break;
 	default:
 		cERROR(1, "Invalid command");
 		break;
@@ -232,3 +236,21 @@ smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
 				  FILE_WRITE_DATA, FILE_OPEN, 0, 0, &eof,
 				  SMB2_OP_SET_EOF);
 }
+
+int
+smb2_set_file_info(struct inode *inode, const char *full_path,
+		   FILE_BASIC_INFO *buf, const unsigned int xid)
+{
+	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+	struct tcon_link *tlink;
+	int rc;
+
+	tlink = cifs_sb_tlink(cifs_sb);
+	if (IS_ERR(tlink))
+		return PTR_ERR(tlink);
+	rc = smb2_open_op_close(xid, tlink_tcon(tlink), cifs_sb, full_path,
+				FILE_WRITE_ATTRIBUTES, FILE_OPEN, 0, 0, buf,
+				SMB2_OP_SET_INFO);
+	cifs_put_tlink(tlink);
+	return rc;
+}
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 3aad536..7ecb117 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -448,6 +448,7 @@ struct smb_version_operations smb21_operations = {
 	.query_file_info = smb2_query_file_info,
 	.set_path_size = smb2_set_path_size,
 	.set_file_size = smb2_set_file_size,
+	.set_file_info = smb2_set_file_info,
 	.build_path_to_root = smb2_build_path_to_root,
 	.mkdir = smb2_mkdir,
 	.mkdir_setinfo = smb2_mkdir_setinfo,
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index f1edc5e..1587761 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1755,3 +1755,14 @@ SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
 	return send_set_info(xid, tcon, persistent_fid, volatile_fid, pid,
 			     FILE_END_OF_FILE_INFORMATION, 1, &data, &size);
 }
+
+int
+SMB2_set_info(const unsigned int xid, struct cifs_tcon *tcon,
+	      u64 persistent_fid, u64 volatile_fid, FILE_BASIC_INFO *buf)
+{
+	unsigned int size;
+	size = sizeof(FILE_BASIC_INFO);
+	return send_set_info(xid, tcon, persistent_fid, volatile_fid,
+			     current->tgid, FILE_BASIC_INFORMATION, 1,
+			     (void **)&buf, &size);
+}
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 3d48662..2774724 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -59,6 +59,8 @@ extern int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
 extern int smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
 			      const char *full_path, __u64 size,
 			      struct cifs_sb_info *cifs_sb, bool set_alloc);
+extern int smb2_set_file_info(struct inode *inode, const char *full_path,
+			      FILE_BASIC_INFO *buf, const unsigned int xid);
 extern int smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon,
 		      const char *name, struct cifs_sb_info *cifs_sb);
 extern void smb2_mkdir_setinfo(struct inode *inode, const char *full_path,
@@ -124,5 +126,8 @@ extern int SMB2_set_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
 extern int SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon,
 			u64 persistent_fid, u64 volatile_fid, u32 pid,
 			__le64 *eof);
+extern int SMB2_set_info(const unsigned int xid, struct cifs_tcon *tcon,
+			 u64 persistent_fid, u64 volatile_fid,
+			 FILE_BASIC_INFO *buf);
 
 #endif			/* _SMB2PROTO_H */
-- 
1.7.1

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

* [PATCH 39/45] CIFS: Move readdir code to ops struct
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (37 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 38/45] CIFS: Add set_file_info support for SMB2 Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
  2012-07-18 15:48   ` [PATCH 40/45] CIFS: Add readdir support for SMB2 Pavel Shilovsky
                     ` (6 subsequent siblings)
  45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/cifsglob.h  |   15 +++++
 fs/cifs/cifsproto.h |    2 +-
 fs/cifs/file.c      |   62 +++++++++++--------
 fs/cifs/netmisc.c   |    3 +-
 fs/cifs/readdir.c   |  165 ++++++++++++++++++++++++++++-----------------------
 fs/cifs/smb1ops.c   |   31 ++++++++++
 6 files changed, 174 insertions(+), 104 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 7c20d5a..406ad6d 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -177,6 +177,7 @@ struct cifs_fid;
 struct cifs_readdata;
 struct cifs_writedata;
 struct cifs_io_parms;
+struct cifs_search_info;
 
 struct smb_version_operations {
 	int (*send_cancel)(struct TCP_Server_Info *, void *,
@@ -313,6 +314,20 @@ struct smb_version_operations {
 	int (*sync_write)(const unsigned int, struct cifsFileInfo *,
 			  struct cifs_io_parms *, unsigned int *, struct kvec *,
 			  unsigned long);
+	/* open dir, start readdir */
+	int (*query_dir_first)(const unsigned int, struct cifs_tcon *,
+			       const char *, struct cifs_sb_info *,
+			       struct cifs_fid *, __u16,
+			       struct cifs_search_info *);
+	/* continue readdir */
+	int (*query_dir_next)(const unsigned int, struct cifs_tcon *,
+			      struct cifs_fid *,
+			      __u16, struct cifs_search_info *srch_inf);
+	/* close dir */
+	int (*close_dir)(const unsigned int, struct cifs_tcon *,
+			 struct cifs_fid *);
+	/* calculate a size of SMB message */
+	unsigned int (*calc_smb_size)(void *);
 };
 
 struct smb_version_values {
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 6e04941..afc0797 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -100,7 +100,7 @@ extern void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
 			    unsigned int bytes_written);
 extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, bool);
 extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool);
-extern unsigned int smbCalcSize(struct smb_hdr *ptr);
+extern unsigned int smbCalcSize(void *buf);
 extern int decode_negTokenInit(unsigned char *security_blob, int length,
 			struct TCP_Server_Info *server);
 extern int cifs_convert_address(struct sockaddr *dst, const char *src, int len);
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 2ffee05..da9dc50 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -609,39 +609,47 @@ int cifs_closedir(struct inode *inode, struct file *file)
 	int rc = 0;
 	unsigned int xid;
 	struct cifsFileInfo *cfile = file->private_data;
-	char *tmp;
+	struct cifs_tcon *tcon;
+	struct TCP_Server_Info *server;
+	char *buf;
 
 	cFYI(1, "Closedir inode = 0x%p", inode);
 
+	if (cfile == NULL)
+		return rc;
+
 	xid = get_xid();
+	tcon = tlink_tcon(cfile->tlink);
+	server = tcon->ses->server;
 
-	if (cfile) {
-		struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
+	cFYI(1, "Freeing private data in close dir");
+	spin_lock(&cifs_file_list_lock);
+	if (!cfile->srch_inf.endOfSearch && !cfile->invalidHandle) {
+		cfile->invalidHandle = true;
+		spin_unlock(&cifs_file_list_lock);
+		if (server->ops->close_dir)
+			rc = server->ops->close_dir(xid, tcon, &cfile->fid);
+		else
+			rc = -ENOSYS;
+		cFYI(1, "Closing uncompleted readdir with rc %d", rc);
+		/* not much we can do if it fails anyway, ignore rc */
+		rc = 0;
+	} else
+		spin_unlock(&cifs_file_list_lock);
 
-		cFYI(1, "Freeing private data in close dir");
-		spin_lock(&cifs_file_list_lock);
-		if (!cfile->srch_inf.endOfSearch && !cfile->invalidHandle) {
-			cfile->invalidHandle = true;
-			spin_unlock(&cifs_file_list_lock);
-			rc = CIFSFindClose(xid, tcon, cfile->fid.netfid);
-			cFYI(1, "Closing uncompleted readdir with rc %d", rc);
-			/* not much we can do if it fails anyway, ignore rc */
-			rc = 0;
-		} else
-			spin_unlock(&cifs_file_list_lock);
-		tmp = cfile->srch_inf.ntwrk_buf_start;
-		if (tmp) {
-			cFYI(1, "closedir free smb buf in srch struct");
-			cfile->srch_inf.ntwrk_buf_start = NULL;
-			if (cfile->srch_inf.smallBuf)
-				cifs_small_buf_release(tmp);
-			else
-				cifs_buf_release(tmp);
-		}
-		cifs_put_tlink(cfile->tlink);
-		kfree(file->private_data);
-		file->private_data = NULL;
+	buf = cfile->srch_inf.ntwrk_buf_start;
+	if (buf) {
+		cFYI(1, "closedir free smb buf in srch struct");
+		cfile->srch_inf.ntwrk_buf_start = NULL;
+		if (cfile->srch_inf.smallBuf)
+			cifs_small_buf_release(buf);
+		else
+			cifs_buf_release(buf);
 	}
+
+	cifs_put_tlink(cfile->tlink);
+	kfree(file->private_data);
+	file->private_data = NULL;
 	/* BB can we lock the filestruct while this is going on? */
 	free_xid(xid);
 	return rc;
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c
index 581c225..e7bab3b 100644
--- a/fs/cifs/netmisc.c
+++ b/fs/cifs/netmisc.c
@@ -913,8 +913,9 @@ map_smb_to_linux_error(char *buf, bool logErr)
  * portion, the number of word parameters and the data portion of the message
  */
 unsigned int
-smbCalcSize(struct smb_hdr *ptr)
+smbCalcSize(void *buf)
 {
+	struct smb_hdr *ptr = (struct smb_hdr *)buf;
 	return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) +
 		2 /* size of the bcc field */ + get_bcc(ptr));
 }
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 9e76e3b..b0f4a42 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -220,7 +220,8 @@ int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb,
 }
  */
 
-static int initiate_cifs_search(const unsigned int xid, struct file *file)
+static int
+initiate_cifs_search(const unsigned int xid, struct file *file)
 {
 	__u16 search_flags;
 	int rc = 0;
@@ -229,6 +230,7 @@ static int initiate_cifs_search(const unsigned int xid, struct file *file)
 	struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
 	struct tcon_link *tlink = NULL;
 	struct cifs_tcon *tcon;
+	struct TCP_Server_Info *server;
 
 	if (file->private_data == NULL) {
 		tlink = cifs_sb_tlink(cifs_sb);
@@ -248,6 +250,13 @@ static int initiate_cifs_search(const unsigned int xid, struct file *file)
 		tcon = tlink_tcon(cifsFile->tlink);
 	}
 
+	server = tcon->ses->server;
+
+	if (!server->ops->query_dir_first) {
+		rc = -ENOSYS;
+		goto error_exit;
+	}
+
 	cifsFile->invalidHandle = true;
 	cifsFile->srch_inf.endOfSearch = false;
 
@@ -278,10 +287,10 @@ ffirst_retry:
 	if (backup_cred(cifs_sb))
 		search_flags |= CIFS_SEARCH_BACKUP_SEARCH;
 
-	rc = CIFSFindFirst(xid, tcon, full_path, cifs_sb->local_nls,
-		&cifsFile->fid.netfid, search_flags, &cifsFile->srch_inf,
-		cifs_sb->mnt_cifs_flags &
-			CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
+	rc = server->ops->query_dir_first(xid, tcon, full_path, cifs_sb,
+					  &cifsFile->fid, search_flags,
+					  &cifsFile->srch_inf);
+
 	if (rc == 0)
 		cifsFile->invalidHandle = false;
 	/* BB add following call to handle readdir on new NTFS symlink errors
@@ -501,62 +510,67 @@ static int cifs_save_resume_key(const char *current_entry,
 	return rc;
 }
 
-/* find the corresponding entry in the search */
-/* Note that the SMB server returns search entries for . and .. which
-   complicates logic here if we choose to parse for them and we do not
-   assume that they are located in the findfirst return buffer.*/
-/* We start counting in the buffer with entry 2 and increment for every
-   entry (do not increment for . or .. entry) */
-static int find_cifs_entry(const unsigned int xid, struct cifs_tcon *pTcon,
-	struct file *file, char **ppCurrentEntry, int *num_to_ret)
+/*
+ * Find the corresponding entry in the search. Note that the SMB server returns
+ * search entries for . and .. which complicates logic here if we choose to
+ * parse for them and we do not assume that they are located in the findfirst
+ * return buffer. We start counting in the buffer with entry 2 and increment for
+ * every entry (do not increment for . or .. entry).
+ */
+static int
+find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon,
+		struct file *file, char **current_entry, int *num_to_ret)
 {
 	__u16 search_flags;
 	int rc = 0;
 	int pos_in_buf = 0;
 	loff_t first_entry_in_buffer;
 	loff_t index_to_find = file->f_pos;
-	struct cifsFileInfo *cifsFile = file->private_data;
+	struct cifsFileInfo *cfile = file->private_data;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
+	struct TCP_Server_Info *server = tcon->ses->server;
 	/* check if index in the buffer */
 
-	if ((cifsFile == NULL) || (ppCurrentEntry == NULL) ||
-	   (num_to_ret == NULL))
+	if (!server->ops->query_dir_first || !server->ops->query_dir_next)
+		return -ENOSYS;
+
+	if ((cfile == NULL) || (current_entry == NULL) || (num_to_ret == NULL))
 		return -ENOENT;
 
-	*ppCurrentEntry = NULL;
-	first_entry_in_buffer =
-		cifsFile->srch_inf.index_of_last_entry -
-			cifsFile->srch_inf.entries_in_buffer;
+	*current_entry = NULL;
+	first_entry_in_buffer = cfile->srch_inf.index_of_last_entry -
+					cfile->srch_inf.entries_in_buffer;
 
-	/* if first entry in buf is zero then is first buffer
-	in search response data which means it is likely . and ..
-	will be in this buffer, although some servers do not return
-	. and .. for the root of a drive and for those we need
-	to start two entries earlier */
+	/*
+	 * If first entry in buf is zero then is first buffer
+	 * in search response data which means it is likely . and ..
+	 * will be in this buffer, although some servers do not return
+	 * . and .. for the root of a drive and for those we need
+	 * to start two entries earlier.
+	 */
 
 	dump_cifs_file_struct(file, "In fce ");
-	if (((index_to_find < cifsFile->srch_inf.index_of_last_entry) &&
-	     is_dir_changed(file)) ||
-	   (index_to_find < first_entry_in_buffer)) {
+	if (((index_to_find < cfile->srch_inf.index_of_last_entry) &&
+	     is_dir_changed(file)) || (index_to_find < first_entry_in_buffer)) {
 		/* close and restart search */
 		cFYI(1, "search backing up - close and restart search");
 		spin_lock(&cifs_file_list_lock);
-		if (!cifsFile->srch_inf.endOfSearch &&
-		    !cifsFile->invalidHandle) {
-			cifsFile->invalidHandle = true;
+		if (!cfile->srch_inf.endOfSearch && !cfile->invalidHandle) {
+			cfile->invalidHandle = true;
 			spin_unlock(&cifs_file_list_lock);
-			CIFSFindClose(xid, pTcon, cifsFile->fid.netfid);
+			if (server->ops->close)
+				server->ops->close(xid, tcon, &cfile->fid);
 		} else
 			spin_unlock(&cifs_file_list_lock);
-		if (cifsFile->srch_inf.ntwrk_buf_start) {
+		if (cfile->srch_inf.ntwrk_buf_start) {
 			cFYI(1, "freeing SMB ff cache buf on search rewind");
-			if (cifsFile->srch_inf.smallBuf)
-				cifs_small_buf_release(cifsFile->srch_inf.
+			if (cfile->srch_inf.smallBuf)
+				cifs_small_buf_release(cfile->srch_inf.
 						ntwrk_buf_start);
 			else
-				cifs_buf_release(cifsFile->srch_inf.
+				cifs_buf_release(cfile->srch_inf.
 						ntwrk_buf_start);
-			cifsFile->srch_inf.ntwrk_buf_start = NULL;
+			cfile->srch_inf.ntwrk_buf_start = NULL;
 		}
 		rc = initiate_cifs_search(xid, file);
 		if (rc) {
@@ -565,65 +579,64 @@ static int find_cifs_entry(const unsigned int xid, struct cifs_tcon *pTcon,
 			return rc;
 		}
 		/* FindFirst/Next set last_entry to NULL on malformed reply */
-		if (cifsFile->srch_inf.last_entry)
-			cifs_save_resume_key(cifsFile->srch_inf.last_entry,
-						cifsFile);
+		if (cfile->srch_inf.last_entry)
+			cifs_save_resume_key(cfile->srch_inf.last_entry, cfile);
 	}
 
 	search_flags = CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME;
 	if (backup_cred(cifs_sb))
 		search_flags |= CIFS_SEARCH_BACKUP_SEARCH;
 
-	while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) &&
-	      (rc == 0) && !cifsFile->srch_inf.endOfSearch) {
+	while ((index_to_find >= cfile->srch_inf.index_of_last_entry) &&
+	       (rc == 0) && !cfile->srch_inf.endOfSearch) {
 		cFYI(1, "calling findnext2");
-		rc = CIFSFindNext(xid, pTcon, cifsFile->fid.netfid,
-				  search_flags, &cifsFile->srch_inf);
+		rc = server->ops->query_dir_next(xid, tcon, &cfile->fid,
+						 search_flags,
+						 &cfile->srch_inf);
 		/* FindFirst/Next set last_entry to NULL on malformed reply */
-		if (cifsFile->srch_inf.last_entry)
-			cifs_save_resume_key(cifsFile->srch_inf.last_entry,
-						cifsFile);
+		if (cfile->srch_inf.last_entry)
+			cifs_save_resume_key(cfile->srch_inf.last_entry, cfile);
 		if (rc)
 			return -ENOENT;
 	}
-	if (index_to_find < cifsFile->srch_inf.index_of_last_entry) {
+	if (index_to_find < cfile->srch_inf.index_of_last_entry) {
 		/* we found the buffer that contains the entry */
 		/* scan and find it */
 		int i;
-		char *current_entry;
-		char *end_of_smb = cifsFile->srch_inf.ntwrk_buf_start +
-			smbCalcSize((struct smb_hdr *)
-				cifsFile->srch_inf.ntwrk_buf_start);
-
-		current_entry = cifsFile->srch_inf.srch_entries_start;
-		first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry
-					- cifsFile->srch_inf.entries_in_buffer;
+		char *cur_ent;
+		char *end_of_smb = cfile->srch_inf.ntwrk_buf_start +
+			server->ops->calc_smb_size(
+					cfile->srch_inf.ntwrk_buf_start);
+
+		cur_ent = cfile->srch_inf.srch_entries_start;
+		first_entry_in_buffer = cfile->srch_inf.index_of_last_entry
+					- cfile->srch_inf.entries_in_buffer;
 		pos_in_buf = index_to_find - first_entry_in_buffer;
 		cFYI(1, "found entry - pos_in_buf %d", pos_in_buf);
 
-		for (i = 0; (i < (pos_in_buf)) && (current_entry != NULL); i++) {
+		for (i = 0; (i < (pos_in_buf)) && (cur_ent != NULL); i++) {
 			/* go entry by entry figuring out which is first */
-			current_entry = nxt_dir_entry(current_entry, end_of_smb,
-						cifsFile->srch_inf.info_level);
+			cur_ent = nxt_dir_entry(cur_ent, end_of_smb,
+						cfile->srch_inf.info_level);
 		}
-		if ((current_entry == NULL) && (i < pos_in_buf)) {
+		if ((cur_ent == NULL) && (i < pos_in_buf)) {
 			/* BB fixme - check if we should flag this error */
 			cERROR(1, "reached end of buf searching for pos in buf"
-			  " %d index to find %lld rc %d",
-			  pos_in_buf, index_to_find, rc);
+				  " %d index to find %lld rc %d", pos_in_buf,
+				  index_to_find, rc);
 		}
 		rc = 0;
-		*ppCurrentEntry = current_entry;
+		*current_entry = cur_ent;
 	} else {
 		cFYI(1, "index not in buffer - could not findnext into it");
 		return 0;
 	}
 
-	if (pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) {
+	if (pos_in_buf >= cfile->srch_inf.entries_in_buffer) {
 		cFYI(1, "can not return entries pos_in_buf beyond last");
 		*num_to_ret = 0;
 	} else
-		*num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf;
+		*num_to_ret = cfile->srch_inf.entries_in_buffer - pos_in_buf;
 
 	return rc;
 }
@@ -723,7 +736,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
 	int rc = 0;
 	unsigned int xid;
 	int i;
-	struct cifs_tcon *pTcon;
+	struct cifs_tcon *tcon;
 	struct cifsFileInfo *cifsFile = NULL;
 	char *current_entry;
 	int num_to_fill = 0;
@@ -781,12 +794,12 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
 			}
 		} /* else {
 			cifsFile->invalidHandle = true;
-			CIFSFindClose(xid, pTcon, cifsFile->fid.netfid);
+			tcon->ses->server->close(xid, tcon, &cifsFile->fid);
 		} */
 
-		pTcon = tlink_tcon(cifsFile->tlink);
-		rc = find_cifs_entry(xid, pTcon, file,
-				&current_entry, &num_to_fill);
+		tcon = tlink_tcon(cifsFile->tlink);
+		rc = find_cifs_entry(xid, tcon, file, &current_entry,
+				     &num_to_fill);
 		if (rc) {
 			cFYI(1, "fce error %d", rc);
 			goto rddir2_exit;
@@ -798,7 +811,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
 		}
 		cFYI(1, "loop through %d times filling dir for net buf %p",
 			num_to_fill, cifsFile->srch_inf.ntwrk_buf_start);
-		max_len = smbCalcSize((struct smb_hdr *)
+		max_len = tcon->ses->server->ops->calc_smb_size(
 				cifsFile->srch_inf.ntwrk_buf_start);
 		end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len;
 
@@ -815,10 +828,12 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
 					  num_to_fill, i);
 				break;
 			}
-			/* if buggy server returns . and .. late do
-			we want to check for that here? */
-			rc = cifs_filldir(current_entry, file,
-					filldir, direntry, tmp_buf, max_len);
+			/*
+			 * if buggy server returns . and .. late do we want to
+			 * check for that here?
+			 */
+			rc = cifs_filldir(current_entry, file, filldir,
+					  direntry, tmp_buf, max_len);
 			if (rc == -EOVERFLOW) {
 				rc = 0;
 				break;
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index ed31196..068d609 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -836,6 +836,33 @@ out:
 	return rc;
 }
 
+static int
+cifs_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
+		     const char *path, struct cifs_sb_info *cifs_sb,
+		     struct cifs_fid *fid, __u16 search_flags,
+		     struct cifs_search_info *srch_inf)
+{
+	return CIFSFindFirst(xid, tcon, path, cifs_sb->local_nls,
+			     &fid->netfid, search_flags, srch_inf,
+			     cifs_sb->mnt_cifs_flags &
+			     CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
+}
+
+static int
+cifs_query_dir_next(const unsigned int xid, struct cifs_tcon *tcon,
+		    struct cifs_fid *fid, __u16 search_flags,
+		    struct cifs_search_info *srch_inf)
+{
+	return CIFSFindNext(xid, tcon, fid->netfid, search_flags, srch_inf);
+}
+
+static int
+cifs_close_dir(const unsigned int xid, struct cifs_tcon *tcon,
+	       struct cifs_fid *fid)
+{
+	return CIFSFindClose(xid, tcon, fid->netfid);
+}
+
 struct smb_version_operations smb1_operations = {
 	.send_cancel = send_nt_cancel,
 	.compare_fids = cifs_compare_fids,
@@ -891,6 +918,10 @@ struct smb_version_operations smb1_operations = {
 	.async_writev = cifs_async_writev,
 	.sync_read = cifs_sync_read,
 	.sync_write = cifs_sync_write,
+	.query_dir_first = cifs_query_dir_first,
+	.query_dir_next = cifs_query_dir_next,
+	.close_dir = cifs_close_dir,
+	.calc_smb_size = smbCalcSize,
 };
 
 struct smb_version_values smb1_values = {
-- 
1.7.1

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

* [PATCH 40/45] CIFS: Add readdir support for SMB2
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (38 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 39/45] CIFS: Move readdir code to ops struct Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
  2012-07-18 15:48   ` [PATCH 41/45] CIFS: Process oplocks " Pavel Shilovsky
                     ` (5 subsequent siblings)
  45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/smb2misc.c  |    8 ++-
 fs/cifs/smb2ops.c   |   57 +++++++++++++++++
 fs/cifs/smb2pdu.c   |  168 +++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/cifs/smb2pdu.h   |   28 +++++++++
 fs/cifs/smb2proto.h |    5 +-
 5 files changed, 264 insertions(+), 2 deletions(-)

diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c
index cbb69e2..81fb162 100644
--- a/fs/cifs/smb2misc.c
+++ b/fs/cifs/smb2misc.c
@@ -246,6 +246,11 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr)
 		*len = le32_to_cpu(((struct smb2_read_rsp *)hdr)->DataLength);
 		break;
 	case SMB2_QUERY_DIRECTORY:
+		*off = le16_to_cpu(
+		  ((struct smb2_query_directory_rsp *)hdr)->OutputBufferOffset);
+		*len = le32_to_cpu(
+		  ((struct smb2_query_directory_rsp *)hdr)->OutputBufferLength);
+		break;
 	case SMB2_IOCTL:
 	case SMB2_CHANGE_NOTIFY:
 	default:
@@ -288,8 +293,9 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr)
  * portion, the number of word parameters and the data portion of the message.
  */
 unsigned int
-smb2_calc_size(struct smb2_hdr *hdr)
+smb2_calc_size(void *buf)
 {
+	struct smb2_hdr *hdr = (struct smb2_hdr *)buf;
 	struct smb2_pdu *pdu = (struct smb2_pdu *)hdr;
 	int offset; /* the offset from the beginning of SMB to data area */
 	int data_length; /* the length of the variable length data area */
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 7ecb117..0ea6cfe 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -415,6 +415,59 @@ smb2_set_file_size(const unsigned int xid, struct cifs_tcon *tcon,
 			    cfile->fid.volatile_fid, cfile->pid, &eof);
 }
 
+static int
+smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
+		     const char *path, struct cifs_sb_info *cifs_sb,
+		     struct cifs_fid *fid, __u16 search_flags,
+		     struct cifs_search_info *srch_inf)
+{
+	__le16 *utf16_path;
+	int rc;
+	__u64 persistent_fid, volatile_fid;
+
+	utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
+	if (!utf16_path)
+		return -ENOMEM;
+
+	rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid,
+		       FILE_READ_ATTRIBUTES | FILE_READ_DATA, FILE_OPEN, 0, 0,
+		       NULL);
+	kfree(utf16_path);
+	if (rc) {
+		cERROR(1, "open dir failed");
+		return rc;
+	}
+
+	srch_inf->entries_in_buffer = 0;
+	srch_inf->index_of_last_entry = 0;
+	fid->persistent_fid = persistent_fid;
+	fid->volatile_fid = volatile_fid;
+
+	rc = SMB2_query_directory(xid, tcon, persistent_fid, volatile_fid, 0,
+				  srch_inf);
+	if (rc) {
+		cERROR(1, "query directory failed");
+		SMB2_close(xid, tcon, persistent_fid, volatile_fid);
+	}
+	return rc;
+}
+
+static int
+smb2_query_dir_next(const unsigned int xid, struct cifs_tcon *tcon,
+		    struct cifs_fid *fid, __u16 search_flags,
+		    struct cifs_search_info *srch_inf)
+{
+	return SMB2_query_directory(xid, tcon, fid->persistent_fid,
+				    fid->volatile_fid, 0, srch_inf);
+}
+
+static int
+smb2_close_dir(const unsigned int xid, struct cifs_tcon *tcon,
+	       struct cifs_fid *fid)
+{
+	return SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid);
+}
+
 struct smb_version_operations smb21_operations = {
 	.setup_request = smb2_setup_request,
 	.setup_async_request = smb2_setup_async_request,
@@ -464,6 +517,10 @@ struct smb_version_operations smb21_operations = {
 	.async_writev = smb2_async_writev,
 	.sync_read = smb2_sync_read,
 	.sync_write = smb2_sync_write,
+	.query_dir_first = smb2_query_dir_first,
+	.query_dir_next = smb2_query_dir_next,
+	.close_dir = smb2_close_dir,
+	.calc_smb_size = smb2_calc_size,
 };
 
 struct smb_version_values smb21_values = {
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 1587761..181b4db 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -45,6 +45,7 @@
 #include "ntlmssp.h"
 #include "smb2status.h"
 #include "smb2glob.h"
+#include "cifspdu.h"
 
 /*
  *  The following table defines the expected "StructureSize" of SMB2 requests
@@ -1598,6 +1599,173 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
 	return rc;
 }
 
+static unsigned int
+num_entries(char *bufstart, char *end_of_buf, char **lastentry, size_t size)
+{
+	int len;
+	unsigned int entrycount = 0;
+	unsigned int next_offset = 0;
+	FILE_DIRECTORY_INFO *entryptr;
+
+	if (bufstart == NULL)
+		return 0;
+
+	entryptr = (FILE_DIRECTORY_INFO *)bufstart;
+
+	while (1) {
+		entryptr = (FILE_DIRECTORY_INFO *)
+					((char *)entryptr + next_offset);
+
+		if ((char *)entryptr + size > end_of_buf) {
+			cERROR(1, "malformed search entry would overflow");
+			break;
+		}
+
+		len = le32_to_cpu(entryptr->FileNameLength);
+		if ((char *)entryptr + len + size > end_of_buf) {
+			cERROR(1, "directory entry name would overflow frame "
+				  "end of buf %p", end_of_buf);
+			break;
+		}
+
+		*lastentry = (char *)entryptr;
+		entrycount++;
+
+		next_offset = le32_to_cpu(entryptr->NextEntryOffset);
+		if (!next_offset)
+			break;
+	}
+
+	return entrycount;
+}
+
+/*
+ * Readdir/FindFirst
+ */
+int
+SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
+		     u64 persistent_fid, u64 volatile_fid, int index,
+		     struct cifs_search_info *srch_inf)
+{
+	struct smb2_query_directory_req *req;
+	struct smb2_query_directory_rsp *rsp = NULL;
+	struct kvec iov[2];
+	int rc = 0;
+	int len;
+	int resp_buftype;
+	unsigned char *bufptr;
+	struct TCP_Server_Info *server;
+	struct cifs_ses *ses = tcon->ses;
+	__le16 asteriks = cpu_to_le16('*');
+	char *end_of_smb;
+	unsigned int output_size = CIFSMaxBufSize;
+	size_t info_buf_size;
+
+	if (ses && (ses->server))
+		server = ses->server;
+	else
+		return -EIO;
+
+	rc = small_smb2_init(SMB2_QUERY_DIRECTORY, tcon, (void **) &req);
+	if (rc)
+		return rc;
+
+	switch (srch_inf->info_level) {
+	case SMB_FIND_FILE_DIRECTORY_INFO:
+		req->FileInformationClass = FILE_DIRECTORY_INFORMATION;
+		info_buf_size = sizeof(FILE_DIRECTORY_INFO) - 1;
+		break;
+	case SMB_FIND_FILE_ID_FULL_DIR_INFO:
+		req->FileInformationClass = FILEID_FULL_DIRECTORY_INFORMATION;
+		info_buf_size = sizeof(SEARCH_ID_FULL_DIR_INFO) - 1;
+		break;
+	default:
+		cERROR(1, "info level %u isn't supported",
+		       srch_inf->info_level);
+		rc = -EINVAL;
+		goto qdir_exit;
+	}
+
+	req->FileIndex = cpu_to_le32(index);
+	req->PersistentFileId = persistent_fid;
+	req->VolatileFileId = volatile_fid;
+
+	len = 0x2;
+	bufptr = req->Buffer;
+	memcpy(bufptr, &asteriks, len);
+
+	req->FileNameOffset =
+		cpu_to_le16(sizeof(struct smb2_query_directory_req) - 1 - 4);
+	req->FileNameLength = cpu_to_le16(len);
+	/*
+	 * BB could be 30 bytes or so longer if we used SMB2 specific
+	 * buffer lengths, but this is safe and close enough.
+	 */
+	output_size = min_t(unsigned int, output_size, server->maxBuf);
+	output_size = min_t(unsigned int, output_size, 2 << 15);
+	req->OutputBufferLength = cpu_to_le32(output_size);
+
+	iov[0].iov_base = (char *)req;
+	/* 4 for RFC1001 length and 1 for Buffer */
+	iov[0].iov_len = get_rfc1002_length(req) + 4 - 1;
+
+	iov[1].iov_base = (char *)(req->Buffer);
+	iov[1].iov_len = len;
+
+	inc_rfc1001_len(req, len - 1 /* Buffer */);
+
+	rc = SendReceive2(xid, ses, iov, 2, &resp_buftype, 0);
+	if (rc) {
+		cifs_stats_fail_inc(tcon, SMB2_QUERY_DIRECTORY_HE);
+		goto qdir_exit;
+	}
+	rsp = (struct smb2_query_directory_rsp *)iov[0].iov_base;
+
+	rc = validate_buf(le16_to_cpu(rsp->OutputBufferOffset),
+			  le32_to_cpu(rsp->OutputBufferLength), &rsp->hdr,
+			  info_buf_size);
+	if (rc)
+		goto qdir_exit;
+
+	srch_inf->unicode = true;
+
+	if (srch_inf->ntwrk_buf_start) {
+		if (srch_inf->smallBuf)
+			cifs_small_buf_release(srch_inf->ntwrk_buf_start);
+		else
+			cifs_buf_release(srch_inf->ntwrk_buf_start);
+	}
+	srch_inf->ntwrk_buf_start = (char *)rsp;
+	srch_inf->srch_entries_start = srch_inf->last_entry = 4 /* rfclen */ +
+		(char *)&rsp->hdr + le16_to_cpu(rsp->OutputBufferOffset);
+	/* 4 for rfc1002 length field */
+	end_of_smb = get_rfc1002_length(rsp) + 4 + (char *)&rsp->hdr;
+	srch_inf->entries_in_buffer =
+			num_entries(srch_inf->srch_entries_start, end_of_smb,
+				    &srch_inf->last_entry, info_buf_size);
+	srch_inf->index_of_last_entry += srch_inf->entries_in_buffer;
+	cFYI(1, "num entries %d last_index %lld srch start %p srch end %p",
+		srch_inf->entries_in_buffer, srch_inf->index_of_last_entry,
+		srch_inf->srch_entries_start, srch_inf->last_entry);
+	if (resp_buftype == CIFS_LARGE_BUFFER)
+		srch_inf->smallBuf = false;
+	else if (resp_buftype == CIFS_SMALL_BUFFER)
+		srch_inf->smallBuf = true;
+	else
+		cERROR(1, "illegal search buffer type");
+
+	if (rsp->hdr.Status == STATUS_NO_MORE_FILES)
+		srch_inf->endOfSearch = 1;
+	else
+		srch_inf->endOfSearch = 0;
+
+	return rc;
+
+qdir_exit:
+	free_rsp_buf(resp_buftype, rsp);
+	return rc;
+}
+
 static int
 send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
 	       u64 persistent_fid, u64 volatile_fid, u32 pid, int info_class,
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 45ecae9..cd64385 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -536,6 +536,34 @@ struct smb2_echo_rsp {
 	__u16  Reserved;
 } __packed;
 
+/* search (query_directory) Flags field */
+#define SMB2_RESTART_SCANS		0x01
+#define SMB2_RETURN_SINGLE_ENTRY	0x02
+#define SMB2_INDEX_SPECIFIED		0x04
+#define SMB2_REOPEN			0x10
+
+struct smb2_query_directory_req {
+	struct smb2_hdr hdr;
+	__le16 StructureSize; /* Must be 33 */
+	__u8   FileInformationClass;
+	__u8   Flags;
+	__le32 FileIndex;
+	__u64  PersistentFileId; /* opaque endianness */
+	__u64  VolatileFileId; /* opaque endianness */
+	__le16 FileNameOffset;
+	__le16 FileNameLength;
+	__le32 OutputBufferLength;
+	__u8   Buffer[1];
+} __packed;
+
+struct smb2_query_directory_rsp {
+	struct smb2_hdr hdr;
+	__le16 StructureSize; /* Must be 9 */
+	__le16 OutputBufferOffset;
+	__le32 OutputBufferLength;
+	__u8   Buffer[1];
+} __packed;
+
 /* Possible InfoType values */
 #define SMB2_O_INFO_FILE	0x01
 #define SMB2_O_INFO_FILESYSTEM	0x02
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 2774724..0d29db2 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -34,7 +34,7 @@ struct statfs;
  */
 extern int map_smb2_to_linux_error(char *buf, bool log_err);
 extern int smb2_check_message(char *buf, unsigned int length);
-extern unsigned int smb2_calc_size(struct smb2_hdr *hdr);
+extern unsigned int smb2_calc_size(void *buf);
 extern char *smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr);
 extern __le16 *cifs_convert_path_to_utf16(const char *from,
 					  struct cifs_sb_info *cifs_sb);
@@ -117,6 +117,9 @@ extern int smb2_async_writev(struct cifs_writedata *wdata);
 extern int SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
 		      unsigned int *nbytes, struct kvec *iov, int n_vec);
 extern int SMB2_echo(struct TCP_Server_Info *server);
+extern int SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
+				u64 persistent_fid, u64 volatile_fid, int index,
+				struct cifs_search_info *srch_inf);
 extern int SMB2_rename(const unsigned int xid, struct cifs_tcon *tcon,
 		       u64 persistent_fid, u64 volatile_fid,
 		       __le16 *target_file);
-- 
1.7.1

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

* [PATCH 41/45] CIFS: Process oplocks for SMB2
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (39 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 40/45] CIFS: Add readdir support for SMB2 Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
  2012-07-18 15:48   ` [PATCH 42/45] CIFS: Move oplock break to ops struct Pavel Shilovsky
                     ` (4 subsequent siblings)
  45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 fs/cifs/cifsglob.h  |    1 +
 fs/cifs/connect.c   |    4 ++++
 fs/cifs/smb2file.c  |   24 ++++++++++++++++++++++--
 fs/cifs/smb2inode.c |    3 ++-
 fs/cifs/smb2ops.c   |   29 +++++++++++++++++++++++++----
 fs/cifs/smb2pdu.c   |    8 +++++---
 fs/cifs/smb2proto.h |    3 ++-
 7 files changed, 61 insertions(+), 11 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 406ad6d..133cd0c 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -328,6 +328,7 @@ struct smb_version_operations {
 			 struct cifs_fid *);
 	/* calculate a size of SMB message */
 	unsigned int (*calc_smb_size)(void *);
+	bool (*is_status_pending)(char *, struct TCP_Server_Info *, int);
 };
 
 struct smb_version_values {
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index bd4dcdd..34f46d0 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -818,6 +818,10 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 		cifs_dump_mem("Bad SMB: ", buf,
 			min_t(unsigned int, server->total_read, 48));
 
+	if (server->ops->is_status_pending &&
+	    server->ops->is_status_pending(buf, server, length))
+		return -1;
+
 	if (!mid)
 		return length;
 
diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c
index a7618df..5ff25e0 100644
--- a/fs/cifs/smb2file.c
+++ b/fs/cifs/smb2file.c
@@ -34,6 +34,26 @@
 #include "fscache.h"
 #include "smb2proto.h"
 
+void
+smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock)
+{
+	oplock &= 0xFF;
+	if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
+		cinode->clientCanCacheAll = true;
+		cinode->clientCanCacheRead = true;
+		cFYI(1, "Exclusive Oplock granted on inode %p",
+		     &cinode->vfs_inode);
+	} else if (oplock == SMB2_OPLOCK_LEVEL_II) {
+		cinode->clientCanCacheAll = false;
+		cinode->clientCanCacheRead = true;
+		cFYI(1, "Level II Oplock granted on inode %p",
+		    &cinode->vfs_inode);
+	} else {
+		cinode->clientCanCacheAll = false;
+		cinode->clientCanCacheRead = false;
+	}
+}
+
 int
 smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
 	       int disposition, int desired_access, int create_options,
@@ -58,10 +78,11 @@ smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
 	}
 
 	desired_access |= FILE_READ_ATTRIBUTES;
+	*oplock = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
 
 	rc = SMB2_open(xid, tcon, smb2_path, &fid->persistent_fid,
 		       &fid->volatile_fid, desired_access, disposition,
-		       0, 0, smb2_data);
+		       0, 0, (__u8 *)oplock, smb2_data);
 	if (rc)
 		goto out;
 
@@ -79,7 +100,6 @@ smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
 	}
 
 out:
-	*oplock = 0;
 	kfree(smb2_data);
 	kfree(smb2_path);
 	return rc;
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index 1bd6b0f..7064824 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -47,6 +47,7 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
 	int rc, tmprc = 0;
 	u64 persistent_fid, volatile_fid;
 	__le16 *utf16_path;
+	__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
 
 	utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
 	if (!utf16_path)
@@ -54,7 +55,7 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
 
 	rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid,
 		       desired_access, create_disposition, file_attributes,
-		       create_options, NULL);
+		       create_options, &oplock, NULL);
 	if (rc) {
 		kfree(utf16_path);
 		return rc;
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 0ea6cfe..25f4263 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -22,6 +22,7 @@
 #include "smb2proto.h"
 #include "cifsproto.h"
 #include "cifs_debug.h"
+#include "smb2status.h"
 
 static int
 change_conf(struct TCP_Server_Info *server)
@@ -198,13 +199,14 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
 	int rc;
 	__u64 persistent_fid, volatile_fid;
 	__le16 *utf16_path;
+	__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
 
 	utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
 	if (!utf16_path)
 		return -ENOMEM;
 
 	rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid,
-		       FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0, NULL);
+		       FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0, &oplock, NULL);
 	if (rc) {
 		kfree(utf16_path);
 		return rc;
@@ -349,10 +351,10 @@ smb2_print_stats(struct seq_file *m, struct cifs_tcon *tcon)
 static void
 smb2_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock)
 {
-	/* struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); */
+	struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
 	cfile->fid.persistent_fid = fid->persistent_fid;
 	cfile->fid.volatile_fid = fid->volatile_fid;
-	/* cifs_set_oplock_level(cinode, oplock); */
+	smb2_set_oplock_level(cinode, oplock);
 	/* cinode->can_cache_brlcks = cinode->clientCanCacheAll; */
 }
 
@@ -423,6 +425,7 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
 {
 	__le16 *utf16_path;
 	int rc;
+	__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
 	__u64 persistent_fid, volatile_fid;
 
 	utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
@@ -431,7 +434,7 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
 
 	rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid,
 		       FILE_READ_ATTRIBUTES | FILE_READ_DATA, FILE_OPEN, 0, 0,
-		       NULL);
+		       &oplock, NULL);
 	kfree(utf16_path);
 	if (rc) {
 		cERROR(1, "open dir failed");
@@ -468,6 +471,23 @@ smb2_close_dir(const unsigned int xid, struct cifs_tcon *tcon,
 	return SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid);
 }
 
+/*
+* If we negotiate SMB2 protocol and get STATUS_PENDING - update
+* the number of credits and return true. Otherwise - return false.
+*/
+static bool
+smb2_is_status_pending(char *buf, struct TCP_Server_Info *server, int length)
+{
+	struct smb2_hdr *hdr = (struct smb2_hdr *)buf;
+
+	if (le32_to_cpu(hdr->Status) != STATUS_PENDING)
+		return false;
+
+	if (!length)
+		add_credits(server, le16_to_cpu(hdr->CreditRequest), 0);
+	return true;
+}
+
 struct smb_version_operations smb21_operations = {
 	.setup_request = smb2_setup_request,
 	.setup_async_request = smb2_setup_async_request,
@@ -521,6 +541,7 @@ struct smb_version_operations smb21_operations = {
 	.query_dir_next = smb2_query_dir_next,
 	.close_dir = smb2_close_dir,
 	.calc_smb_size = smb2_calc_size,
+	.is_status_pending = smb2_is_status_pending,
 };
 
 struct smb_version_values smb21_values = {
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 181b4db..58c1e91 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -872,7 +872,7 @@ int
 SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
 	  u64 *persistent_fid, u64 *volatile_fid, __u32 desired_access,
 	  __u32 create_disposition, __u32 file_attributes, __u32 create_options,
-	  struct smb2_file_all_info *buf)
+	  __u8 *oplock, struct smb2_file_all_info *buf)
 {
 	struct smb2_create_req *req;
 	struct smb2_create_rsp *rsp;
@@ -895,9 +895,9 @@ SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
 	if (rc)
 		return rc;
 
-	/* if (server->oplocks)
+	if (server->oplocks)
 		req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_BATCH;
-	else */
+	else
 		req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_NONE;
 	req->ImpersonationLevel = IL_IMPERSONATION;
 	req->DesiredAccess = cpu_to_le32(desired_access);
@@ -954,6 +954,8 @@ SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
 		buf->NumberOfLinks = cpu_to_le32(1);
 		buf->DeletePending = 0;
 	}
+
+	*oplock = rsp->OplockLevel;
 creat_exit:
 	free_rsp_buf(resp_buftype, rsp);
 	return rc;
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 0d29db2..d18339f 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -82,6 +82,7 @@ extern int smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon,
 			  int desired_access, int create_options,
 			  struct cifs_fid *fid, __u32 *oplock,
 			  FILE_ALL_INFO *buf, struct cifs_sb_info *cifs_sb);
+extern void smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock);
 
 /*
  * SMB2 Worker functions - most of protocol specific implementation details
@@ -99,7 +100,7 @@ extern int SMB2_open(const unsigned int xid, struct cifs_tcon *tcon,
 		     __le16 *path, u64 *persistent_fid, u64 *volatile_fid,
 		     __u32 desired_access, __u32 create_disposition,
 		     __u32 file_attributes, __u32 create_options,
-		     struct smb2_file_all_info *buf);
+		     __u8 *oplock, struct smb2_file_all_info *buf);
 extern int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
 		      u64 persistent_file_id, u64 volatile_file_id);
 extern int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon,
-- 
1.7.1

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

* [PATCH 42/45] CIFS: Move oplock break to ops struct
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (40 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 41/45] CIFS: Process oplocks " Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
  2012-07-18 15:48   ` [PATCH 43/45] CIFS: Add oplock break support for SMB2 Pavel Shilovsky
                     ` (3 subsequent siblings)
  45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/cifsglob.h |    4 ++++
 fs/cifs/file.c     |    7 +++----
 fs/cifs/smb1ops.c  |   10 ++++++++++
 3 files changed, 17 insertions(+), 4 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 133cd0c..a8f424f 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -178,6 +178,7 @@ struct cifs_readdata;
 struct cifs_writedata;
 struct cifs_io_parms;
 struct cifs_search_info;
+struct cifsInodeInfo;
 
 struct smb_version_operations {
 	int (*send_cancel)(struct TCP_Server_Info *, void *,
@@ -329,6 +330,9 @@ struct smb_version_operations {
 	/* calculate a size of SMB message */
 	unsigned int (*calc_smb_size)(void *);
 	bool (*is_status_pending)(char *, struct TCP_Server_Info *, int);
+	/* send oplock break response */
+	int (*oplock_response)(struct cifs_tcon *, struct cifs_fid *,
+			       struct cifsInodeInfo *);
 };
 
 struct smb_version_values {
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index da9dc50..40230a7 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -3395,6 +3395,7 @@ void cifs_oplock_break(struct work_struct *work)
 						  oplock_break);
 	struct inode *inode = cfile->dentry->d_inode;
 	struct cifsInodeInfo *cinode = CIFS_I(inode);
+	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
 	int rc = 0;
 
 	if (inode && S_ISREG(inode->i_mode)) {
@@ -3422,10 +3423,8 @@ void cifs_oplock_break(struct work_struct *work)
 	 * disconnected since oplock already released by the server
 	 */
 	if (!cfile->oplock_break_cancelled) {
-		rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->fid.netfid,
-				 current->tgid, 0, 0, 0, 0,
-				 LOCKING_ANDX_OPLOCK_RELEASE, false,
-				 cinode->clientCanCacheRead ? 1 : 0);
+		rc = tcon->ses->server->ops->oplock_response(tcon, &cfile->fid,
+							     cinode);
 		cFYI(1, "Oplock release rc = %d", rc);
 	}
 }
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 068d609..f55b2e3 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -863,6 +863,15 @@ cifs_close_dir(const unsigned int xid, struct cifs_tcon *tcon,
 	return CIFSFindClose(xid, tcon, fid->netfid);
 }
 
+static int
+cifs_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid,
+		     struct cifsInodeInfo *cinode)
+{
+	return CIFSSMBLock(0, tcon, fid->netfid, current->tgid, 0, 0, 0, 0,
+			   LOCKING_ANDX_OPLOCK_RELEASE, false,
+			   cinode->clientCanCacheRead ? 1 : 0);
+}
+
 struct smb_version_operations smb1_operations = {
 	.send_cancel = send_nt_cancel,
 	.compare_fids = cifs_compare_fids,
@@ -922,6 +931,7 @@ struct smb_version_operations smb1_operations = {
 	.query_dir_next = cifs_query_dir_next,
 	.close_dir = cifs_close_dir,
 	.calc_smb_size = smbCalcSize,
+	.oplock_response = cifs_oplock_response,
 };
 
 struct smb_version_values smb1_values = {
-- 
1.7.1

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

* [PATCH 43/45] CIFS: Add oplock break support for SMB2
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (41 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 42/45] CIFS: Move oplock break to ops struct Pavel Shilovsky
@ 2012-07-18 15:48   ` Pavel Shilovsky
  2012-07-18 15:49   ` [PATCH 44/45] CIFS: Move statfs to ops struct Pavel Shilovsky
                     ` (2 subsequent siblings)
  45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/smb2misc.c  |   75 +++++++++++++++++++++++++++++++++++++++++++++++++-
 fs/cifs/smb2ops.c   |   19 +++++++++++-
 fs/cifs/smb2pdu.c   |   35 +++++++++++++++++++++++
 fs/cifs/smb2pdu.h   |   10 +++++++
 fs/cifs/smb2proto.h |    5 +++
 5 files changed, 140 insertions(+), 4 deletions(-)

diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c
index 81fb162..15e0d8d 100644
--- a/fs/cifs/smb2misc.c
+++ b/fs/cifs/smb2misc.c
@@ -141,8 +141,8 @@ smb2_check_message(char *buf, unsigned int length)
 	}
 
 	if (smb2_rsp_struct_sizes[command] != pdu->StructureSize2) {
-		if (hdr->Status == 0 ||
-		    pdu->StructureSize2 != SMB2_ERROR_STRUCTURE_SIZE2) {
+		if (command != SMB2_OPLOCK_BREAK_HE && (hdr->Status == 0 ||
+		    pdu->StructureSize2 != SMB2_ERROR_STRUCTURE_SIZE2)) {
 			/* error packets have 9 byte structure size */
 			cERROR(1, "Illegal response size %u for command %d",
 				   le16_to_cpu(pdu->StructureSize2), command);
@@ -161,6 +161,8 @@ smb2_check_message(char *buf, unsigned int length)
 	if (4 + len != clc_len) {
 		cFYI(1, "Calculated size %u length %u mismatch mid %llu",
 			clc_len, 4 + len, mid);
+		if (clc_len + 20 == len && command == SMB2_OPLOCK_BREAK_HE)
+			return 0; /* Windows 7 server returns 24 bytes more */
 		if (clc_len == 4 + len + 1) /* BB FIXME (fix samba) */
 			return 0; /* BB workaround Samba 3 bug SessSetup rsp */
 		return 1;
@@ -354,3 +356,72 @@ cifs_convert_path_to_utf16(const char *from, struct cifs_sb_info *cifs_sb)
 					CIFS_MOUNT_MAP_SPECIAL_CHR);
 	return to;
 }
+
+bool
+smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
+{
+	struct smb2_oplock_break *rsp = (struct smb2_oplock_break *)buffer;
+	struct list_head *tmp, *tmp1, *tmp2;
+	struct cifs_ses *ses;
+	struct cifs_tcon *tcon;
+	struct cifsInodeInfo *cinode;
+	struct cifsFileInfo *cfile;
+
+	cFYI(1, "Checking for oplock break");
+
+	if (rsp->hdr.Command != SMB2_OPLOCK_BREAK)
+		return false;
+
+	if (le16_to_cpu(rsp->StructureSize) !=
+				smb2_rsp_struct_sizes[SMB2_OPLOCK_BREAK_HE]) {
+		return false;
+	}
+
+	cFYI(1, "oplock level 0x%d", rsp->OplockLevel);
+
+	/* look up tcon based on tid & uid */
+	spin_lock(&cifs_tcp_ses_lock);
+	list_for_each(tmp, &server->smb_ses_list) {
+		ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
+		list_for_each(tmp1, &ses->tcon_list) {
+			tcon = list_entry(tmp1, struct cifs_tcon, tcon_list);
+
+			cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks);
+			spin_lock(&cifs_file_list_lock);
+			list_for_each(tmp2, &tcon->openFileList) {
+				cfile = list_entry(tmp2, struct cifsFileInfo,
+						     tlist);
+				if (rsp->PersistentFid !=
+				    cfile->fid.persistent_fid ||
+				    rsp->VolatileFid !=
+				    cfile->fid.volatile_fid)
+					continue;
+
+				cFYI(1, "file id match, oplock break");
+				cinode = CIFS_I(cfile->dentry->d_inode);
+
+				if (!cinode->clientCanCacheAll &&
+				    rsp->OplockLevel == SMB2_OPLOCK_LEVEL_NONE)
+					cfile->oplock_break_cancelled = true;
+				else
+					cfile->oplock_break_cancelled = false;
+
+				smb2_set_oplock_level(cinode,
+				  rsp->OplockLevel ? SMB2_OPLOCK_LEVEL_II : 0);
+
+				queue_work(cifsiod_wq, &cfile->oplock_break);
+
+				spin_unlock(&cifs_file_list_lock);
+				spin_unlock(&cifs_tcp_ses_lock);
+				return true;
+			}
+			spin_unlock(&cifs_file_list_lock);
+			spin_unlock(&cifs_tcp_ses_lock);
+			cFYI(1, "No matching file for oplock break");
+			return true;
+		}
+	}
+	spin_unlock(&cifs_tcp_ses_lock);
+	cFYI(1, "Can not process oplock break for non-existent connection");
+	return false;
+}
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 25f4263..99dbb8c 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -483,11 +483,24 @@ smb2_is_status_pending(char *buf, struct TCP_Server_Info *server, int length)
 	if (le32_to_cpu(hdr->Status) != STATUS_PENDING)
 		return false;
 
-	if (!length)
-		add_credits(server, le16_to_cpu(hdr->CreditRequest), 0);
+	if (!length) {
+		spin_lock(&server->req_lock);
+		server->credits += le16_to_cpu(hdr->CreditRequest);
+		spin_unlock(&server->req_lock);
+		wake_up(&server->request_q);
+	}
 	return true;
 }
 
+static int
+smb2_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid,
+		     struct cifsInodeInfo *cinode)
+{
+	return SMB2_oplock_break(0, tcon, fid->persistent_fid,
+				 fid->volatile_fid,
+				 cinode->clientCanCacheRead ? 1 : 0);
+}
+
 struct smb_version_operations smb21_operations = {
 	.setup_request = smb2_setup_request,
 	.setup_async_request = smb2_setup_async_request,
@@ -505,6 +518,7 @@ struct smb_version_operations smb21_operations = {
 	.dump_detail = smb2_dump_detail,
 	.clear_stats = smb2_clear_stats,
 	.print_stats = smb2_print_stats,
+	.is_oplock_break = smb2_is_valid_oplock_break,
 	.need_neg = smb2_need_neg,
 	.negotiate = smb2_negotiate,
 	.negotiate_wsize = smb2_negotiate_wsize,
@@ -542,6 +556,7 @@ struct smb_version_operations smb21_operations = {
 	.close_dir = smb2_close_dir,
 	.calc_smb_size = smb2_calc_size,
 	.is_status_pending = smb2_is_status_pending,
+	.oplock_response = smb2_oplock_response,
 };
 
 struct smb_version_values smb21_values = {
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 58c1e91..a04917e 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1936,3 +1936,38 @@ SMB2_set_info(const unsigned int xid, struct cifs_tcon *tcon,
 			     current->tgid, FILE_BASIC_INFORMATION, 1,
 			     (void **)&buf, &size);
 }
+
+int
+SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
+		  const u64 persistent_fid, const u64 volatile_fid,
+		  __u8 oplock_level)
+{
+	int rc = 0, buf_type;
+	struct smb2_oplock_break *req = NULL;
+	struct kvec iov[1];
+
+	cFYI(1, "SMB2_oplock_break");
+	rc = small_smb2_init(SMB2_OPLOCK_BREAK, tcon, (void **) &req);
+
+	if (rc)
+		return rc;
+
+	req->VolatileFid = volatile_fid;
+	req->PersistentFid = persistent_fid;
+	req->OplockLevel = oplock_level;
+	req->hdr.CreditRequest = cpu_to_le16(1);
+
+	iov->iov_base = (char *)req;
+	/* 4 for rfc1002 length */
+	iov->iov_len = get_rfc1002_length(req) + 4;
+
+	rc = SendReceive2(xid, tcon->ses, iov, 1, &buf_type, CIFS_OBREAK_OP);
+	/* SMB2 buffer freed by function above */
+
+	if (rc) {
+		cifs_stats_fail_inc(tcon, SMB2_OPLOCK_BREAK_HE);
+		cFYI(1, "Send error in Oplock Break = %d", rc);
+	}
+
+	return rc;
+}
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index cd64385..0e5afb7 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -613,6 +613,16 @@ struct smb2_set_info_rsp {
 	__le16 StructureSize; /* Must be 2 */
 } __packed;
 
+struct smb2_oplock_break {
+	struct smb2_hdr hdr;
+	__le16 StructureSize; /* Must be 24 */
+	__u8   OplockLevel;
+	__u8   Reserved;
+	__le32 Reserved2;
+	__u64  PersistentFid;
+	__u64  VolatileFid;
+} __packed;
+
 /*
  *	PDU infolevel structure definitions
  *	BB consider moving to a different header
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index d18339f..de554b7 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -49,6 +49,8 @@ extern int smb2_setup_async_request(struct TCP_Server_Info *server,
 				    struct kvec *iov, unsigned int nvec,
 				    struct mid_q_entry **ret_mid);
 extern void smb2_echo_request(struct work_struct *work);
+extern bool smb2_is_valid_oplock_break(char *buffer,
+				       struct TCP_Server_Info *srv);
 
 extern void move_smb2_info_to_cifs(FILE_ALL_INFO *dst,
 				   struct smb2_file_all_info *src);
@@ -133,5 +135,8 @@ extern int SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon,
 extern int SMB2_set_info(const unsigned int xid, struct cifs_tcon *tcon,
 			 u64 persistent_fid, u64 volatile_fid,
 			 FILE_BASIC_INFO *buf);
+extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
+			     const u64 persistent_fid, const u64 volatile_fid,
+			     const __u8 oplock_level);
 
 #endif			/* _SMB2PROTO_H */
-- 
1.7.1

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

* [PATCH 44/45] CIFS: Move statfs to ops struct
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (42 preceding siblings ...)
  2012-07-18 15:48   ` [PATCH 43/45] CIFS: Add oplock break support for SMB2 Pavel Shilovsky
@ 2012-07-18 15:49   ` Pavel Shilovsky
  2012-07-18 15:49   ` [PATCH 45/45] CIFS: Add statfs support for SMB2 Pavel Shilovsky
  2012-08-03 15:14   ` [PATCH 00/45] SMB2 base operation support Steve French
  45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:49 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/cifsfs.c   |   29 ++++-------------------------
 fs/cifs/cifsglob.h |    5 +++++
 fs/cifs/smb1ops.c  |   34 ++++++++++++++++++++++++++++++++++
 3 files changed, 43 insertions(+), 25 deletions(-)

diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 65f8b05..4dde869 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -51,7 +51,6 @@
 #ifdef CONFIG_CIFS_SMB2
 #include "smb2pdu.h"
 #endif
-#define CIFS_MAGIC_NUMBER 0xFF534D42	/* the first four bytes of SMB PDUs */
 
 int cifsFYI = 0;
 int cifsERROR = 1;
@@ -162,13 +161,12 @@ 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 cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
-	int rc = -EOPNOTSUPP;
+	struct TCP_Server_Info *server = tcon->ses->server;
 	unsigned int xid;
+	int rc = 0;
 
 	xid = get_xid();
 
-	buf->f_type = CIFS_MAGIC_NUMBER;
-
 	/*
 	 * PATH_MAX may be too long - it would presumably be total path,
 	 * but note that some servers (includinng Samba 3) have a shorter
@@ -180,27 +178,8 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
 	buf->f_files = 0;	/* undefined */
 	buf->f_ffree = 0;	/* unlimited */
 
-	/*
-	 * We could add a second check for a QFS Unix capability bit
-	 */
-	if ((tcon->ses->capabilities & CAP_UNIX) &&
-	    (CIFS_POSIX_EXTENSIONS & le64_to_cpu(tcon->fsUnixInfo.Capability)))
-		rc = CIFSSMBQFSPosixInfo(xid, tcon, buf);
-
-	/*
-	 * Only need to call the old QFSInfo if failed on newer one,
-	 * e.g. by OS/2.
-	 **/
-	if (rc && (tcon->ses->capabilities & CAP_NT_SMBS))
-		rc = CIFSSMBQFSInfo(xid, tcon, buf);
-
-	/*
-	 * Some old Windows servers also do not support level 103, retry with
-	 * older level one if old server failed the previous call or we
-	 * bypassed it because we detected that this was an older LANMAN sess
-	 */
-	if (rc)
-		rc = SMBOldQFSInfo(xid, tcon, buf);
+	if (server->ops->queryfs)
+		rc = server->ops->queryfs(xid, tcon, buf);
 
 	free_xid(xid);
 	return 0;
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index a8f424f..46bbbe4 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -32,6 +32,8 @@
 #include "smb2pdu.h"
 #endif
 
+#define CIFS_MAGIC_NUMBER 0xFF534D42      /* the first four bytes of SMB PDUs */
+
 /*
  * The sizes of various internal tables and strings
  */
@@ -333,6 +335,9 @@ struct smb_version_operations {
 	/* send oplock break response */
 	int (*oplock_response)(struct cifs_tcon *, struct cifs_fid *,
 			       struct cifsInodeInfo *);
+	/* query remote filesystem */
+	int (*queryfs)(const unsigned int, struct cifs_tcon *,
+		       struct kstatfs *);
 };
 
 struct smb_version_values {
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index f55b2e3..f6c7a1c 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -18,6 +18,7 @@
  */
 
 #include <linux/pagemap.h>
+#include <linux/vfs.h>
 #include "cifsglob.h"
 #include "cifsproto.h"
 #include "cifs_debug.h"
@@ -872,6 +873,38 @@ cifs_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid,
 			   cinode->clientCanCacheRead ? 1 : 0);
 }
 
+static int
+cifs_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
+	     struct kstatfs *buf)
+{
+	int rc = -EOPNOTSUPP;
+
+	buf->f_type = CIFS_MAGIC_NUMBER;
+
+	/*
+	 * We could add a second check for a QFS Unix capability bit
+	 */
+	if ((tcon->ses->capabilities & CAP_UNIX) &&
+	    (CIFS_POSIX_EXTENSIONS & le64_to_cpu(tcon->fsUnixInfo.Capability)))
+		rc = CIFSSMBQFSPosixInfo(xid, tcon, buf);
+
+	/*
+	 * Only need to call the old QFSInfo if failed on newer one,
+	 * e.g. by OS/2.
+	 **/
+	if (rc && (tcon->ses->capabilities & CAP_NT_SMBS))
+		rc = CIFSSMBQFSInfo(xid, tcon, buf);
+
+	/*
+	 * Some old Windows servers also do not support level 103, retry with
+	 * older level one if old server failed the previous call or we
+	 * bypassed it because we detected that this was an older LANMAN sess
+	 */
+	if (rc)
+		rc = SMBOldQFSInfo(xid, tcon, buf);
+	return rc;
+}
+
 struct smb_version_operations smb1_operations = {
 	.send_cancel = send_nt_cancel,
 	.compare_fids = cifs_compare_fids,
@@ -932,6 +965,7 @@ struct smb_version_operations smb1_operations = {
 	.close_dir = cifs_close_dir,
 	.calc_smb_size = smbCalcSize,
 	.oplock_response = cifs_oplock_response,
+	.queryfs = cifs_queryfs,
 };
 
 struct smb_version_values smb1_values = {
-- 
1.7.1

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

* [PATCH 45/45] CIFS: Add statfs support for SMB2
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (43 preceding siblings ...)
  2012-07-18 15:49   ` [PATCH 44/45] CIFS: Move statfs to ops struct Pavel Shilovsky
@ 2012-07-18 15:49   ` Pavel Shilovsky
  2012-08-03 15:14   ` [PATCH 00/45] SMB2 base operation support Steve French
  45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:49 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/smb2glob.h  |    2 +
 fs/cifs/smb2ops.c   |   22 ++++++++++++++
 fs/cifs/smb2pdu.c   |   81 +++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/cifs/smb2pdu.h   |   19 ++++++++++++
 fs/cifs/smb2proto.h |    3 ++
 5 files changed, 127 insertions(+), 0 deletions(-)

diff --git a/fs/cifs/smb2glob.h b/fs/cifs/smb2glob.h
index 05d429b..7c0e214 100644
--- a/fs/cifs/smb2glob.h
+++ b/fs/cifs/smb2glob.h
@@ -23,6 +23,8 @@
 #ifndef _SMB2_GLOB_H
 #define _SMB2_GLOB_H
 
+#define SMB2_MAGIC_NUMBER 0xFE534D42
+
 /*
  *****************************************************************
  * Constants go here
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 99dbb8c..a1333d2 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -17,12 +17,14 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+#include <linux/vfs.h>
 #include "cifsglob.h"
 #include "smb2pdu.h"
 #include "smb2proto.h"
 #include "cifsproto.h"
 #include "cifs_debug.h"
 #include "smb2status.h"
+#include "smb2glob.h"
 
 static int
 change_conf(struct TCP_Server_Info *server)
@@ -501,6 +503,25 @@ smb2_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid,
 				 cinode->clientCanCacheRead ? 1 : 0);
 }
 
+static int
+smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
+	     struct kstatfs *buf)
+{
+	int rc;
+	u64 persistent_fid, volatile_fid;
+	__le16 srch_path = 0; /* Null - open root of share */
+	u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
+
+	rc = SMB2_open(xid, tcon, &srch_path, &persistent_fid, &volatile_fid,
+		       FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0, &oplock, NULL);
+	if (rc)
+		return rc;
+	buf->f_type = SMB2_MAGIC_NUMBER;
+	rc = SMB2_QFS_info(xid, tcon, persistent_fid, volatile_fid, buf);
+	SMB2_close(xid, tcon, persistent_fid, volatile_fid);
+	return rc;
+}
+
 struct smb_version_operations smb21_operations = {
 	.setup_request = smb2_setup_request,
 	.setup_async_request = smb2_setup_async_request,
@@ -557,6 +578,7 @@ struct smb_version_operations smb21_operations = {
 	.calc_smb_size = smb2_calc_size,
 	.is_status_pending = smb2_is_status_pending,
 	.oplock_response = smb2_oplock_response,
+	.queryfs = smb2_queryfs,
 };
 
 struct smb_version_values smb21_values = {
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index a04917e..61a4b88 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1971,3 +1971,84 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
 
 	return rc;
 }
+
+static void
+copy_fs_info_to_kstatfs(struct smb2_fs_full_size_info *pfs_inf,
+			struct kstatfs *kst)
+{
+	kst->f_bsize = le32_to_cpu(pfs_inf->BytesPerSector) *
+			  le32_to_cpu(pfs_inf->SectorsPerAllocationUnit);
+	kst->f_blocks = le64_to_cpu(pfs_inf->TotalAllocationUnits);
+	kst->f_bfree  = le64_to_cpu(pfs_inf->ActualAvailableAllocationUnits);
+	kst->f_bavail = le64_to_cpu(pfs_inf->CallerAvailableAllocationUnits);
+	return;
+}
+
+static int
+build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon, int level,
+		   int outbuf_len, u64 persistent_fid, u64 volatile_fid)
+{
+	int rc;
+	struct smb2_query_info_req *req;
+
+	cFYI(1, "Query FSInfo level %d", level);
+
+	if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
+		return -EIO;
+
+	rc = small_smb2_init(SMB2_QUERY_INFO, tcon, (void **) &req);
+	if (rc)
+		return rc;
+
+	req->InfoType = SMB2_O_INFO_FILESYSTEM;
+	req->FileInfoClass = level;
+	req->PersistentFileId = persistent_fid;
+	req->VolatileFileId = volatile_fid;
+	/* 4 for rfc1002 length field and 1 for pad */
+	req->InputBufferOffset =
+			cpu_to_le16(sizeof(struct smb2_query_info_req) - 1 - 4);
+	req->OutputBufferLength = cpu_to_le32(
+		outbuf_len + sizeof(struct smb2_query_info_rsp) - 1 - 4);
+
+	iov->iov_base = (char *)req;
+	/* 4 for rfc1002 length field */
+	iov->iov_len = get_rfc1002_length(req) + 4;
+	return 0;
+}
+
+int
+SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
+	      u64 persistent_fid, u64 volatile_fid, struct kstatfs *fsdata)
+{
+	struct smb2_query_info_rsp *rsp = NULL;
+	struct kvec iov;
+	int rc = 0;
+	int resp_buftype;
+	struct cifs_ses *ses = tcon->ses;
+	struct smb2_fs_full_size_info *info = NULL;
+
+	rc = build_qfs_info_req(&iov, tcon, FS_FULL_SIZE_INFORMATION,
+				sizeof(struct smb2_fs_full_size_info),
+				persistent_fid, volatile_fid);
+	if (rc)
+		return rc;
+
+	rc = SendReceive2(xid, ses, &iov, 1, &resp_buftype, 0);
+	if (rc) {
+		cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE);
+		goto qinf_exit;
+	}
+	rsp = (struct smb2_query_info_rsp *)iov.iov_base;
+
+	info = (struct smb2_fs_full_size_info *)(4 /* RFC1001 len */ +
+		le16_to_cpu(rsp->OutputBufferOffset) + (char *)&rsp->hdr);
+	rc = validate_buf(le16_to_cpu(rsp->OutputBufferOffset),
+			  le32_to_cpu(rsp->OutputBufferLength), &rsp->hdr,
+			  sizeof(struct smb2_fs_full_size_info));
+	if (!rc)
+		copy_fs_info_to_kstatfs(info, fsdata);
+
+qinf_exit:
+	free_rsp_buf(resp_buftype, iov.iov_base);
+	return rc;
+}
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 0e5afb7..30c7d73 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -628,6 +628,25 @@ struct smb2_oplock_break {
  *	BB consider moving to a different header
  */
 
+/* File System Information Classes */
+#define FS_VOLUME_INFORMATION		1 /* Query */
+#define FS_LABEL_INFORMATION		2 /* Set */
+#define FS_SIZE_INFORMATION		3 /* Query */
+#define FS_DEVICE_INFORMATION		4 /* Query */
+#define FS_ATTRIBUTE_INFORMATION	5 /* Query */
+#define FS_CONTROL_INFORMATION		6 /* Query, Set */
+#define FS_FULL_SIZE_INFORMATION	7 /* Query */
+#define FS_OBJECT_ID_INFORMATION	8 /* Query, Set */
+#define FS_DRIVER_PATH_INFORMATION	9 /* Query */
+
+struct smb2_fs_full_size_info {
+	__le64 TotalAllocationUnits;
+	__le64 CallerAvailableAllocationUnits;
+	__le64 ActualAvailableAllocationUnits;
+	__le32 SectorsPerAllocationUnit;
+	__le32 BytesPerSector;
+} __packed;
+
 /* partial list of QUERY INFO levels */
 #define FILE_DIRECTORY_INFORMATION	1
 #define FILE_FULL_DIRECTORY_INFORMATION 2
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index de554b7..a73a963 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -138,5 +138,8 @@ extern int SMB2_set_info(const unsigned int xid, struct cifs_tcon *tcon,
 extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
 			     const u64 persistent_fid, const u64 volatile_fid,
 			     const __u8 oplock_level);
+extern int SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
+			 u64 persistent_file_id, u64 volatile_file_id,
+			 struct kstatfs *FSData);
 
 #endif			/* _SMB2PROTO_H */
-- 
1.7.1

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

* Re: [PATCH 01/45] CIFS: Make CAP_* checks protocol independent
       [not found]     ` <1342626541-29872-2-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
@ 2012-07-23 13:55       ` Jeff Layton
       [not found]         ` <CAKywueTxSBkBfp4wZW8Hy71F3dZ1gsthuHcLVO28--a4oEAMjw@mail.gmail.com>
  2012-07-23 20:59       ` Jeff Layton
  2012-07-24  7:21       ` [PATCH v2 1/45] " Pavel Shilovsky
  2 siblings, 1 reply; 74+ messages in thread
From: Jeff Layton @ 2012-07-23 13:55 UTC (permalink / raw)
  To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA

On Wed, 18 Jul 2012 19:48:17 +0400
Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:

> --- a/fs/cifs/file.c
> +++ b/fs/cifs/file.c
> @@ -385,9 +385,8 @@ int cifs_open(struct inode *inode, struct file *file)
>  		oplock = 0;
>  
>  	if (!tcon->broken_posix_open && tcon->unix_ext &&
> -	    (tcon->ses->capabilities & CAP_UNIX) &&
> -	    (CIFS_UNIX_POSIX_PATH_OPS_CAP &
> -			le64_to_cpu(tcon->fsUnixInfo.Capability))) {
> +	    cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
> +				le64_to_cpu(tcon->fsUnixInfo.Capability))) {
>  		/* can not refresh inode info since size could be stale */
>  		rc = cifs_posix_open(full_path, &inode, inode->i_sb,
>  				cifs_sb->mnt_file_mode /* ignored */,

While I'm in general OK with abstracting out things like this with a
set of operations, I'm not sure it makes much sense to make things so
granular in the name of code-sharing

Would it be better for instance, to simply have a different f_ops->open
routine for SMB2, and simply check the right bit for CAP_UNIX in each
one?

-- 
Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>

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

* Re: [PATCH 01/45] CIFS: Make CAP_* checks protocol independent
       [not found]     ` <1342626541-29872-2-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
  2012-07-23 13:55       ` Jeff Layton
@ 2012-07-23 20:59       ` Jeff Layton
       [not found]         ` <20120723165947.5fad3d87-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
  2012-07-24  7:21       ` [PATCH v2 1/45] " Pavel Shilovsky
  2 siblings, 1 reply; 74+ messages in thread
From: Jeff Layton @ 2012-07-23 20:59 UTC (permalink / raw)
  To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA

On Wed, 18 Jul 2012 19:48:17 +0400
Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:

> Since both CIFS and SMB2 use ses->capabilities (server->capabilities)
> field but flags are different we should make such checks protocol
> independent.
> 
> Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
> ---
>  fs/cifs/cifsglob.h |   10 ++++++++++
>  fs/cifs/connect.c  |    6 +++---
>  fs/cifs/dir.c      |    3 +--
>  fs/cifs/file.c     |   33 ++++++++++++++++-----------------
>  fs/cifs/inode.c    |   26 ++++++++++++--------------
>  fs/cifs/link.c     |    6 +++---
>  fs/cifs/readdir.c  |   16 ++++++++--------
>  fs/cifs/smb1ops.c  |    3 +++
>  fs/cifs/smb2ops.c  |    3 +++
>  fs/cifs/smb2pdu.c  |    2 ++
>  fs/cifs/smb2pdu.h  |    3 +++
>  11 files changed, 64 insertions(+), 47 deletions(-)
> 
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index 12b1176..5695693 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -258,6 +258,9 @@ struct smb_version_values {
>  	size_t		max_header_size;
>  	size_t		read_rsp_size;
>  	__le16		lock_cmd;
> +	int		cap_unix;
> +	int		cap_nt_find;
> +	int		cap_large_files;

These should probably be unsigned values, and the ses->capabilities and
server->capabilities flags should be turned into unsigned values as
well.

For that matter, it's not clear to me why we have capabilities fields
for both ses and server. I see in one case where they can be different
(if linuxExtEnabled == 0). Probably they should be converted to always
use the server one and we get rid of the ses one.

>  };
>  
>  #define HEADER_SIZE(server) (server->vals->header_size)
> @@ -554,6 +557,13 @@ struct cifs_ses {
>     which do not negotiate NTLM or POSIX dialects, but instead
>     negotiate one of the older LANMAN dialects */
>  #define CIFS_SES_LANMAN 8
> +
> +static inline bool
> +cap_unix(struct cifs_ses *ses)
> +{
> +	return ses->server->vals->cap_unix & ses->capabilities;
> +}
> +
>  /*
>   * there is one of these for each connection to a resource on a particular
>   * session
> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
> index b1ab89a..99d50bf 100644
> --- a/fs/cifs/connect.c
> +++ b/fs/cifs/connect.c
> @@ -3633,7 +3633,7 @@ try_mount_again:
>  	}
>  
>  	/* tell server which Unix caps we support */
> -	if (tcon->ses->capabilities & CAP_UNIX) {
> +	if (cap_unix(tcon->ses)) {
>  		/* reset of caps checks mount to see if unix extensions
>  		   disabled for just this mount */
>  		reset_cifs_unix_caps(xid, tcon, cifs_sb, volume_info);
> @@ -3992,7 +3992,7 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
>  	ses->flags = 0;
>  	ses->capabilities = server->capabilities;
>  	if (linuxExtEnabled == 0)
> -		ses->capabilities &= (~CAP_UNIX);
> +		ses->capabilities &= (~server->vals->cap_unix);
>  
>  	cFYI(1, "Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
>  		 server->sec_mode, server->capabilities, server->timeAdj);
> @@ -4099,7 +4099,7 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid)
>  		goto out;
>  	}
>  
> -	if (ses->capabilities & CAP_UNIX)
> +	if (cap_unix(ses))
>  		reset_cifs_unix_caps(0, tcon, NULL, vol_info);
>  out:
>  	kfree(vol_info->username);
> diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
> index 2caba0b..cbe709a 100644
> --- a/fs/cifs/dir.c
> +++ b/fs/cifs/dir.c
> @@ -182,8 +182,7 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
>  		goto out;
>  	}
>  
> -	if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
> -	    !tcon->broken_posix_open &&
> +	if (tcon->unix_ext && cap_unix(tcon->ses) && !tcon->broken_posix_open &&
>  	    (CIFS_UNIX_POSIX_PATH_OPS_CAP &
>  			le64_to_cpu(tcon->fsUnixInfo.Capability))) {
>  		rc = cifs_posix_open(full_path, &newinode,
> diff --git a/fs/cifs/file.c b/fs/cifs/file.c
> index ea1bb66..1712794 100644
> --- a/fs/cifs/file.c
> +++ b/fs/cifs/file.c
> @@ -385,9 +385,8 @@ int cifs_open(struct inode *inode, struct file *file)
>  		oplock = 0;
>  
>  	if (!tcon->broken_posix_open && tcon->unix_ext &&
> -	    (tcon->ses->capabilities & CAP_UNIX) &&
> -	    (CIFS_UNIX_POSIX_PATH_OPS_CAP &
> -			le64_to_cpu(tcon->fsUnixInfo.Capability))) {
> +	    cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
> +				le64_to_cpu(tcon->fsUnixInfo.Capability))) {
>  		/* can not refresh inode info since size could be stale */
>  		rc = cifs_posix_open(full_path, &inode, inode->i_sb,
>  				cifs_sb->mnt_file_mode /* ignored */,
> @@ -509,10 +508,9 @@ static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
>  	else
>  		oplock = 0;
>  
> -	if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
> +	if (tcon->unix_ext && cap_unix(tcon->ses) &&
>  	    (CIFS_UNIX_POSIX_PATH_OPS_CAP &
> -			le64_to_cpu(tcon->fsUnixInfo.Capability))) {
> -
> +				le64_to_cpu(tcon->fsUnixInfo.Capability))) {
>  		/*
>  		 * O_CREAT, O_EXCL and O_TRUNC already had their effect on the
>  		 * original open. Must mask them off for a reopen.
> @@ -1073,7 +1071,7 @@ cifs_push_locks(struct cifsFileInfo *cfile)
>  	struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->dentry->d_sb);
>  	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
>  
> -	if ((tcon->ses->capabilities & CAP_UNIX) &&
> +	if (cap_unix(tcon->ses) &&
>  	    (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
>  	    ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
>  		return cifs_push_posix_locks(cfile);
> @@ -1421,7 +1419,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock)
>  	netfid = cfile->netfid;
>  	cinode = CIFS_I(file->f_path.dentry->d_inode);
>  
> -	if ((tcon->ses->capabilities & CAP_UNIX) &&
> +	if (cap_unix(tcon->ses) &&
>  	    (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
>  	    ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
>  		posix_lck = true;
> @@ -2747,7 +2745,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
>  	unsigned int current_read_size;
>  	unsigned int rsize;
>  	struct cifs_sb_info *cifs_sb;
> -	struct cifs_tcon *pTcon;
> +	struct cifs_tcon *tcon;
>  	unsigned int xid;
>  	char *current_offset;
>  	struct cifsFileInfo *open_file;
> @@ -2767,7 +2765,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
>  		return rc;
>  	}
>  	open_file = file->private_data;
> -	pTcon = tlink_tcon(open_file->tlink);
> +	tcon = tlink_tcon(open_file->tlink);
>  
>  	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
>  		pid = open_file->pid;
> @@ -2781,11 +2779,12 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
>  	     read_size > total_read;
>  	     total_read += bytes_read, current_offset += bytes_read) {
>  		current_read_size = min_t(uint, read_size - total_read, rsize);
> -
> -		/* For windows me and 9x we do not want to request more
> -		than it negotiated since it will refuse the read then */
> -		if ((pTcon->ses) &&
> -			!(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
> +		/*
> +		 * For windows me and 9x we do not want to request more than it
> +		 * negotiated since it will refuse the read then.
> +		 */
> +		if ((tcon->ses) && !(tcon->ses->capabilities |
> +				tcon->ses->server->vals->cap_large_files)) {

			^^^^		
Bug? Shouldn't that be & cap_large_files ?

>  			current_read_size = min_t(uint, current_read_size,
>  					CIFSMaxBufSize);
>  		}
> @@ -2798,7 +2797,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
>  			}
>  			io_parms.netfid = open_file->netfid;
>  			io_parms.pid = pid;
> -			io_parms.tcon = pTcon;
> +			io_parms.tcon = tcon;
>  			io_parms.offset = *poffset;
>  			io_parms.length = current_read_size;
>  			rc = CIFSSMBRead(xid, &io_parms, &bytes_read,
> @@ -2812,7 +2811,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
>  				return rc;
>  			}
>  		} else {
> -			cifs_stats_bytes_read(pTcon, total_read);
> +			cifs_stats_bytes_read(tcon, total_read);
>  			*poffset += bytes_read;
>  		}
>  	}
> diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
> index def1006..35cb6a3 100644
> --- a/fs/cifs/inode.c
> +++ b/fs/cifs/inode.c
> @@ -1149,9 +1149,8 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
>  		goto unlink_out;
>  	}
>  
> -	if ((tcon->ses->capabilities & CAP_UNIX) &&
> -		(CIFS_UNIX_POSIX_PATH_OPS_CAP &
> -			le64_to_cpu(tcon->fsUnixInfo.Capability))) {
> +	if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
> +				le64_to_cpu(tcon->fsUnixInfo.Capability))) {
>  		rc = CIFSPOSIXDelFile(xid, tcon, full_path,
>  			SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls,
>  			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
> @@ -1226,7 +1225,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
>  	unsigned int xid;
>  	struct cifs_sb_info *cifs_sb;
>  	struct tcon_link *tlink;
> -	struct cifs_tcon *pTcon;
> +	struct cifs_tcon *tcon;
>  	char *full_path = NULL;
>  	struct inode *newinode = NULL;
>  	struct cifs_fattr fattr;
> @@ -1237,7 +1236,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
>  	tlink = cifs_sb_tlink(cifs_sb);
>  	if (IS_ERR(tlink))
>  		return PTR_ERR(tlink);
> -	pTcon = tlink_tcon(tlink);
> +	tcon = tlink_tcon(tlink);
>  
>  	xid = get_xid();
>  
> @@ -1247,9 +1246,8 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
>  		goto mkdir_out;
>  	}
>  
> -	if ((pTcon->ses->capabilities & CAP_UNIX) &&
> -		(CIFS_UNIX_POSIX_PATH_OPS_CAP &
> -			le64_to_cpu(pTcon->fsUnixInfo.Capability))) {
> +	if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
> +				le64_to_cpu(tcon->fsUnixInfo.Capability))) {
>  		u32 oplock = 0;
>  		FILE_UNIX_BASIC_INFO *pInfo =
>  			kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
> @@ -1259,7 +1257,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
>  		}
>  
>  		mode &= ~current_umask();
> -		rc = CIFSPOSIXCreate(xid, pTcon, SMB_O_DIRECTORY | SMB_O_CREAT,
> +		rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT,
>  				mode, NULL /* netfid */, pInfo, &oplock,
>  				full_path, cifs_sb->local_nls,
>  				cifs_sb->mnt_cifs_flags &
> @@ -1303,14 +1301,14 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
>  	}
>  mkdir_retry_old:
>  	/* BB add setting the equivalent of mode via CreateX w/ACLs */
> -	rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls,
> +	rc = CIFSSMBMkDir(xid, tcon, full_path, cifs_sb->local_nls,
>  			  cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
>  	if (rc) {
>  		cFYI(1, "cifs_mkdir returned 0x%x", rc);
>  		d_drop(direntry);
>  	} else {
>  mkdir_get_info:
> -		if (pTcon->unix_ext)
> +		if (tcon->unix_ext)
>  			rc = cifs_get_inode_info_unix(&newinode, full_path,
>  						      inode->i_sb, xid);
>  		else
> @@ -1328,7 +1326,7 @@ mkdir_get_info:
>  		if (inode->i_mode & S_ISGID)
>  			mode |= S_ISGID;
>  
> -		if (pTcon->unix_ext) {
> +		if (tcon->unix_ext) {
>  			struct cifs_unix_set_info_args args = {
>  				.mode	= mode,
>  				.ctime	= NO_CHANGE_64,
> @@ -1346,7 +1344,7 @@ mkdir_get_info:
>  				args.uid = NO_CHANGE_64;
>  				args.gid = NO_CHANGE_64;
>  			}
> -			CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args,
> +			CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
>  					       cifs_sb->local_nls,
>  					       cifs_sb->mnt_cifs_flags &
>  						CIFS_MOUNT_MAP_SPECIAL_CHR);
> @@ -1361,7 +1359,7 @@ mkdir_get_info:
>  				cifsInode = CIFS_I(newinode);
>  				dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
>  				pInfo.Attributes = cpu_to_le32(dosattrs);
> -				tmprc = CIFSSMBSetPathInfo(xid, pTcon,
> +				tmprc = CIFSSMBSetPathInfo(xid, tcon,
>  						full_path, &pInfo,
>  						cifs_sb->local_nls,
>  						cifs_sb->mnt_cifs_flags &
> diff --git a/fs/cifs/link.c b/fs/cifs/link.c
> index 77d781a..d08b76c 100644
> --- a/fs/cifs/link.c
> +++ b/fs/cifs/link.c
> @@ -495,8 +495,8 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
>  	 * but there doesn't seem to be any harm in allowing the client to
>  	 * read them.
>  	 */
> -	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
> -	    && !(tcon->ses->capabilities & CAP_UNIX)) {
> +	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) &&
> +	    !cap_unix(tcon->ses)) {
>  		rc = -EACCES;
>  		goto out;
>  	}
> @@ -518,7 +518,7 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
>  					cifs_sb->mnt_cifs_flags &
>  						CIFS_MOUNT_MAP_SPECIAL_CHR);
>  
> -	if ((rc != 0) && (tcon->ses->capabilities & CAP_UNIX))
> +	if ((rc != 0) && cap_unix(tcon->ses))
>  		rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, &target_path,
>  					     cifs_sb->local_nls);
>  
> diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
> index da30d96..d87f826 100644
> --- a/fs/cifs/readdir.c
> +++ b/fs/cifs/readdir.c
> @@ -228,7 +228,7 @@ static int initiate_cifs_search(const unsigned int xid, struct file *file)
>  	struct cifsFileInfo *cifsFile;
>  	struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
>  	struct tcon_link *tlink = NULL;
> -	struct cifs_tcon *pTcon;
> +	struct cifs_tcon *tcon;
>  
>  	if (file->private_data == NULL) {
>  		tlink = cifs_sb_tlink(cifs_sb);
> @@ -242,10 +242,10 @@ static int initiate_cifs_search(const unsigned int xid, struct file *file)
>  		}
>  		file->private_data = cifsFile;
>  		cifsFile->tlink = cifs_get_tlink(tlink);
> -		pTcon = tlink_tcon(tlink);
> +		tcon = tlink_tcon(tlink);
>  	} else {
>  		cifsFile = file->private_data;
> -		pTcon = tlink_tcon(cifsFile->tlink);
> +		tcon = tlink_tcon(cifsFile->tlink);
>  	}
>  
>  	cifsFile->invalidHandle = true;
> @@ -262,11 +262,11 @@ static int initiate_cifs_search(const unsigned int xid, struct file *file)
>  ffirst_retry:
>  	/* test for Unix extensions */
>  	/* but now check for them on the share/mount not on the SMB session */
> -/*	if (pTcon->ses->capabilities & CAP_UNIX) { */
> -	if (pTcon->unix_ext)
> +	/* if (cap_unix(tcon->ses) { */
> +	if (tcon->unix_ext)
>  		cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX;
> -	else if ((pTcon->ses->capabilities &
> -			(CAP_NT_SMBS | CAP_NT_FIND)) == 0) {
> +	else if ((tcon->ses->capabilities &
> +		  tcon->ses->server->vals->cap_nt_find) == 0) {
>  		cifsFile->srch_inf.info_level = SMB_FIND_FILE_INFO_STANDARD;
>  	} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
>  		cifsFile->srch_inf.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO;
> @@ -278,7 +278,7 @@ ffirst_retry:
>  	if (backup_cred(cifs_sb))
>  		search_flags |= CIFS_SEARCH_BACKUP_SEARCH;
>  
> -	rc = CIFSFindFirst(xid, pTcon, full_path, cifs_sb->local_nls,
> +	rc = CIFSFindFirst(xid, tcon, full_path, cifs_sb->local_nls,
>  		&cifsFile->netfid, search_flags, &cifsFile->srch_inf,
>  		cifs_sb->mnt_cifs_flags &
>  			CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
> diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
> index 5817409..c40356d 100644
> --- a/fs/cifs/smb1ops.c
> +++ b/fs/cifs/smb1ops.c
> @@ -632,4 +632,7 @@ struct smb_version_values smb1_values = {
>  	.max_header_size = MAX_CIFS_HDR_SIZE,
>  	.read_rsp_size = sizeof(READ_RSP),
>  	.lock_cmd = cpu_to_le16(SMB_COM_LOCKING_ANDX),
> +	.cap_unix = CAP_UNIX,
> +	.cap_nt_find = CAP_NT_SMBS | CAP_NT_FIND,
> +	.cap_large_files = CAP_LARGE_FILES,
>  };
> diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
> index 1018c5c..410cf92 100644
> --- a/fs/cifs/smb2ops.c
> +++ b/fs/cifs/smb2ops.c
> @@ -325,4 +325,7 @@ struct smb_version_values smb21_values = {
>  	.header_size = sizeof(struct smb2_hdr),
>  	.max_header_size = MAX_SMB2_HDR_SIZE,
>  	.lock_cmd = SMB2_LOCK,
> +	.cap_unix = 0,
> +	.cap_nt_find = SMB2_NT_FIND,
> +	.cap_large_files = SMB2_LARGE_FILES,
>  };
> diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
> index e4eb1d3..62b3f17 100644
> --- a/fs/cifs/smb2pdu.c
> +++ b/fs/cifs/smb2pdu.c
> @@ -428,6 +428,8 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
>  	/* BB Do we need to validate the SecurityMode? */
>  	server->sec_mode = le16_to_cpu(rsp->SecurityMode);
>  	server->capabilities = le32_to_cpu(rsp->Capabilities);
> +	/* Internal types */
> +	server->capabilities |= SMB2_NT_FIND | SMB2_LARGE_FILES;
>  
>  	security_blob = smb2_get_data_area_len(&blob_offset, &blob_length,
>  					       &rsp->hdr);
> diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
> index 59aae60..f37a1b4 100644
> --- a/fs/cifs/smb2pdu.h
> +++ b/fs/cifs/smb2pdu.h
> @@ -167,6 +167,9 @@ struct smb2_negotiate_req {
>  #define SMB2_GLOBAL_CAP_DFS		0x00000001
>  #define SMB2_GLOBAL_CAP_LEASING		0x00000002 /* Resp only New to SMB2.1 */
>  #define SMB2_GLOBAL_CAP_LARGE_MTU	0X00000004 /* Resp only New to SMB2.1 */
> +/* Internal types */
> +#define SMB2_NT_FIND			0x00100000
> +#define SMB2_LARGE_FILES		0x00200000
>  
>  struct smb2_negotiate_rsp {
>  	struct smb2_hdr hdr;


-- 
Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>

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

* Re: [PATCH 01/45] CIFS: Make CAP_* checks protocol independent
       [not found]         ` <20120723165947.5fad3d87-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
@ 2012-07-23 21:14           ` Steve French
  2012-07-24  6:38           ` Pavel Shilovsky
  1 sibling, 0 replies; 74+ messages in thread
From: Steve French @ 2012-07-23 21:14 UTC (permalink / raw)
  To: Jeff Layton; +Cc: Pavel Shilovsky, linux-cifs-u79uwXL29TY76Z2rM5mHXA

On Mon, Jul 23, 2012 at 3:59 PM, Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:
> On Wed, 18 Jul 2012 19:48:17 +0400
> Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:
>
>> Since both CIFS and SMB2 use ses->capabilities (server->capabilities)
>> field but flags are different we should make such checks protocol
>> independent.
>>
>> Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
>> ---
>>  fs/cifs/cifsglob.h |   10 ++++++++++
>>  fs/cifs/connect.c  |    6 +++---
>>  fs/cifs/dir.c      |    3 +--
>>  fs/cifs/file.c     |   33 ++++++++++++++++-----------------
>>  fs/cifs/inode.c    |   26 ++++++++++++--------------
>>  fs/cifs/link.c     |    6 +++---
>>  fs/cifs/readdir.c  |   16 ++++++++--------
>>  fs/cifs/smb1ops.c  |    3 +++
>>  fs/cifs/smb2ops.c  |    3 +++
>>  fs/cifs/smb2pdu.c  |    2 ++
>>  fs/cifs/smb2pdu.h  |    3 +++
>>  11 files changed, 64 insertions(+), 47 deletions(-)
>>
>> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
>> index 12b1176..5695693 100644
>> --- a/fs/cifs/cifsglob.h
>> +++ b/fs/cifs/cifsglob.h
>> @@ -258,6 +258,9 @@ struct smb_version_values {
>>       size_t          max_header_size;
>>       size_t          read_rsp_size;
>>       __le16          lock_cmd;
>> +     int             cap_unix;
>> +     int             cap_nt_find;
>> +     int             cap_large_files;
>
> These should probably be unsigned values, and the ses->capabilities and
> server->capabilities flags should be turned into unsigned values as
> well.
>
> For that matter, it's not clear to me why we have capabilities fields
> for both ses and server. I see in one case where they can be different
> (if linuxExtEnabled == 0). Probably they should be converted to always
> use the server one and we get rid of the ses one.

For the non-unix case the server returns caps on negprot (per-socket),
we negotiate them (potentially differently, less than what the server
returned on negprot) on every session setup though.  For proper
reconnection, we probably need to keep both.

For the unix specific capabilities they end up as booleans in the tcon
- as they are negotiated on the tcon (not the socket or smb session)


-- 
Thanks,

Steve

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

* Re: [PATCH 01/45] CIFS: Make CAP_* checks protocol independent
       [not found]           ` <CAKywueTxSBkBfp4wZW8Hy71F3dZ1gsthuHcLVO28--a4oEAMjw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2012-07-24  6:37             ` Pavel Shilovsky
  0 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-24  6:37 UTC (permalink / raw)
  To: Jeff Layton; +Cc: Pavel Shilovsky, linux-cifs-u79uwXL29TY76Z2rM5mHXA

2012/7/23 Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>:
> Smb2 will use posix extensions further - we can easily modify the code to
> support it and avoid code dublication. So, I created the patches this way -
> it let us abstract open code logic from protocol. I don't think that having
> several open routines with almost the same code help us to keep the code
> clean and easy to maintain.
> 23.07.2012 17:55 пользователь "Jeff Layton" <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> написал:
>
>
>>
>> On Wed, 18 Jul 2012 19:48:17 +0400
>> Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:
>>
>> > --- a/fs/cifs/file.c
>> > +++ b/fs/cifs/file.c
>> > @@ -385,9 +385,8 @@ int cifs_open(struct inode *inode, struct file
>> > *file)
>> >               oplock = 0;
>> >
>> >       if (!tcon->broken_posix_open && tcon->unix_ext &&
>> > -         (tcon->ses->capabilities & CAP_UNIX) &&
>> > -         (CIFS_UNIX_POSIX_PATH_OPS_CAP &
>> > -                     le64_to_cpu(tcon->fsUnixInfo.Capability))) {
>> > +         cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
>> > +                             le64_to_cpu(tcon->fsUnixInfo.Capability)))
>> > {
>> >               /* can not refresh inode info since size could be stale */
>> >               rc = cifs_posix_open(full_path, &inode, inode->i_sb,
>> >                               cifs_sb->mnt_file_mode /* ignored */,
>>
>> While I'm in general OK with abstracting out things like this with a
>> set of operations, I'm not sure it makes much sense to make things so
>> granular in the name of code-sharing
>>
>> Would it be better for instance, to simply have a different f_ops->open
>> routine for SMB2, and simply check the right bit for CAP_UNIX in each
>> one?
>>
>> --
>> Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
>> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html



-- 
Best regards,
Pavel Shilovsky.

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

* Re: [PATCH 01/45] CIFS: Make CAP_* checks protocol independent
       [not found]         ` <20120723165947.5fad3d87-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
  2012-07-23 21:14           ` Steve French
@ 2012-07-24  6:38           ` Pavel Shilovsky
  1 sibling, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-24  6:38 UTC (permalink / raw)
  To: Jeff Layton; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA

2012/7/24 Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>:
> On Wed, 18 Jul 2012 19:48:17 +0400
> Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:
>
>> Since both CIFS and SMB2 use ses->capabilities (server->capabilities)
>> field but flags are different we should make such checks protocol
>> independent.
>>
>> Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
>> ---
>>  fs/cifs/cifsglob.h |   10 ++++++++++
>>  fs/cifs/connect.c  |    6 +++---
>>  fs/cifs/dir.c      |    3 +--
>>  fs/cifs/file.c     |   33 ++++++++++++++++-----------------
>>  fs/cifs/inode.c    |   26 ++++++++++++--------------
>>  fs/cifs/link.c     |    6 +++---
>>  fs/cifs/readdir.c  |   16 ++++++++--------
>>  fs/cifs/smb1ops.c  |    3 +++
>>  fs/cifs/smb2ops.c  |    3 +++
>>  fs/cifs/smb2pdu.c  |    2 ++
>>  fs/cifs/smb2pdu.h  |    3 +++
>>  11 files changed, 64 insertions(+), 47 deletions(-)
>>
>> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
>> index 12b1176..5695693 100644
>> --- a/fs/cifs/cifsglob.h
>> +++ b/fs/cifs/cifsglob.h
>> @@ -258,6 +258,9 @@ struct smb_version_values {
>>       size_t          max_header_size;
>>       size_t          read_rsp_size;
>>       __le16          lock_cmd;
>> +     int             cap_unix;
>> +     int             cap_nt_find;
>> +     int             cap_large_files;
>
> These should probably be unsigned values, and the ses->capabilities and
> server->capabilities flags should be turned into unsigned values as
> well.
>
> For that matter, it's not clear to me why we have capabilities fields
> for both ses and server. I see in one case where they can be different
> (if linuxExtEnabled == 0). Probably they should be converted to always
> use the server one and we get rid of the ses one.
>
>>  };
>>
>>  #define HEADER_SIZE(server) (server->vals->header_size)
>> @@ -554,6 +557,13 @@ struct cifs_ses {
>>     which do not negotiate NTLM or POSIX dialects, but instead
>>     negotiate one of the older LANMAN dialects */
>>  #define CIFS_SES_LANMAN 8
>> +
>> +static inline bool
>> +cap_unix(struct cifs_ses *ses)
>> +{
>> +     return ses->server->vals->cap_unix & ses->capabilities;
>> +}
>> +
>>  /*
>>   * there is one of these for each connection to a resource on a particular
>>   * session
>> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
>> index b1ab89a..99d50bf 100644
>> --- a/fs/cifs/connect.c
>> +++ b/fs/cifs/connect.c
>> @@ -3633,7 +3633,7 @@ try_mount_again:
>>       }
>>
>>       /* tell server which Unix caps we support */
>> -     if (tcon->ses->capabilities & CAP_UNIX) {
>> +     if (cap_unix(tcon->ses)) {
>>               /* reset of caps checks mount to see if unix extensions
>>                  disabled for just this mount */
>>               reset_cifs_unix_caps(xid, tcon, cifs_sb, volume_info);
>> @@ -3992,7 +3992,7 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
>>       ses->flags = 0;
>>       ses->capabilities = server->capabilities;
>>       if (linuxExtEnabled == 0)
>> -             ses->capabilities &= (~CAP_UNIX);
>> +             ses->capabilities &= (~server->vals->cap_unix);
>>
>>       cFYI(1, "Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
>>                server->sec_mode, server->capabilities, server->timeAdj);
>> @@ -4099,7 +4099,7 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid)
>>               goto out;
>>       }
>>
>> -     if (ses->capabilities & CAP_UNIX)
>> +     if (cap_unix(ses))
>>               reset_cifs_unix_caps(0, tcon, NULL, vol_info);
>>  out:
>>       kfree(vol_info->username);
>> diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
>> index 2caba0b..cbe709a 100644
>> --- a/fs/cifs/dir.c
>> +++ b/fs/cifs/dir.c
>> @@ -182,8 +182,7 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
>>               goto out;
>>       }
>>
>> -     if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
>> -         !tcon->broken_posix_open &&
>> +     if (tcon->unix_ext && cap_unix(tcon->ses) && !tcon->broken_posix_open &&
>>           (CIFS_UNIX_POSIX_PATH_OPS_CAP &
>>                       le64_to_cpu(tcon->fsUnixInfo.Capability))) {
>>               rc = cifs_posix_open(full_path, &newinode,
>> diff --git a/fs/cifs/file.c b/fs/cifs/file.c
>> index ea1bb66..1712794 100644
>> --- a/fs/cifs/file.c
>> +++ b/fs/cifs/file.c
>> @@ -385,9 +385,8 @@ int cifs_open(struct inode *inode, struct file *file)
>>               oplock = 0;
>>
>>       if (!tcon->broken_posix_open && tcon->unix_ext &&
>> -         (tcon->ses->capabilities & CAP_UNIX) &&
>> -         (CIFS_UNIX_POSIX_PATH_OPS_CAP &
>> -                     le64_to_cpu(tcon->fsUnixInfo.Capability))) {
>> +         cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
>> +                             le64_to_cpu(tcon->fsUnixInfo.Capability))) {
>>               /* can not refresh inode info since size could be stale */
>>               rc = cifs_posix_open(full_path, &inode, inode->i_sb,
>>                               cifs_sb->mnt_file_mode /* ignored */,
>> @@ -509,10 +508,9 @@ static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
>>       else
>>               oplock = 0;
>>
>> -     if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
>> +     if (tcon->unix_ext && cap_unix(tcon->ses) &&
>>           (CIFS_UNIX_POSIX_PATH_OPS_CAP &
>> -                     le64_to_cpu(tcon->fsUnixInfo.Capability))) {
>> -
>> +                             le64_to_cpu(tcon->fsUnixInfo.Capability))) {
>>               /*
>>                * O_CREAT, O_EXCL and O_TRUNC already had their effect on the
>>                * original open. Must mask them off for a reopen.
>> @@ -1073,7 +1071,7 @@ cifs_push_locks(struct cifsFileInfo *cfile)
>>       struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->dentry->d_sb);
>>       struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
>>
>> -     if ((tcon->ses->capabilities & CAP_UNIX) &&
>> +     if (cap_unix(tcon->ses) &&
>>           (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
>>           ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
>>               return cifs_push_posix_locks(cfile);
>> @@ -1421,7 +1419,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock)
>>       netfid = cfile->netfid;
>>       cinode = CIFS_I(file->f_path.dentry->d_inode);
>>
>> -     if ((tcon->ses->capabilities & CAP_UNIX) &&
>> +     if (cap_unix(tcon->ses) &&
>>           (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
>>           ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
>>               posix_lck = true;
>> @@ -2747,7 +2745,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
>>       unsigned int current_read_size;
>>       unsigned int rsize;
>>       struct cifs_sb_info *cifs_sb;
>> -     struct cifs_tcon *pTcon;
>> +     struct cifs_tcon *tcon;
>>       unsigned int xid;
>>       char *current_offset;
>>       struct cifsFileInfo *open_file;
>> @@ -2767,7 +2765,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
>>               return rc;
>>       }
>>       open_file = file->private_data;
>> -     pTcon = tlink_tcon(open_file->tlink);
>> +     tcon = tlink_tcon(open_file->tlink);
>>
>>       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
>>               pid = open_file->pid;
>> @@ -2781,11 +2779,12 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
>>            read_size > total_read;
>>            total_read += bytes_read, current_offset += bytes_read) {
>>               current_read_size = min_t(uint, read_size - total_read, rsize);
>> -
>> -             /* For windows me and 9x we do not want to request more
>> -             than it negotiated since it will refuse the read then */
>> -             if ((pTcon->ses) &&
>> -                     !(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
>> +             /*
>> +              * For windows me and 9x we do not want to request more than it
>> +              * negotiated since it will refuse the read then.
>> +              */
>> +             if ((tcon->ses) && !(tcon->ses->capabilities |
>> +                             tcon->ses->server->vals->cap_large_files)) {
>
>                         ^^^^
> Bug? Shouldn't that be & cap_large_files ?

Oh, thanks! It is definitly a bug - will fix.


>
>>                       current_read_size = min_t(uint, current_read_size,
>>                                       CIFSMaxBufSize);
>>               }
>> @@ -2798,7 +2797,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
>>                       }
>>                       io_parms.netfid = open_file->netfid;
>>                       io_parms.pid = pid;
>> -                     io_parms.tcon = pTcon;
>> +                     io_parms.tcon = tcon;
>>                       io_parms.offset = *poffset;
>>                       io_parms.length = current_read_size;
>>                       rc = CIFSSMBRead(xid, &io_parms, &bytes_read,
>> @@ -2812,7 +2811,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
>>                               return rc;
>>                       }
>>               } else {
>> -                     cifs_stats_bytes_read(pTcon, total_read);
>> +                     cifs_stats_bytes_read(tcon, total_read);
>>                       *poffset += bytes_read;
>>               }
>>       }
>> diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
>> index def1006..35cb6a3 100644
>> --- a/fs/cifs/inode.c
>> +++ b/fs/cifs/inode.c
>> @@ -1149,9 +1149,8 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
>>               goto unlink_out;
>>       }
>>
>> -     if ((tcon->ses->capabilities & CAP_UNIX) &&
>> -             (CIFS_UNIX_POSIX_PATH_OPS_CAP &
>> -                     le64_to_cpu(tcon->fsUnixInfo.Capability))) {
>> +     if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
>> +                             le64_to_cpu(tcon->fsUnixInfo.Capability))) {
>>               rc = CIFSPOSIXDelFile(xid, tcon, full_path,
>>                       SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls,
>>                       cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
>> @@ -1226,7 +1225,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
>>       unsigned int xid;
>>       struct cifs_sb_info *cifs_sb;
>>       struct tcon_link *tlink;
>> -     struct cifs_tcon *pTcon;
>> +     struct cifs_tcon *tcon;
>>       char *full_path = NULL;
>>       struct inode *newinode = NULL;
>>       struct cifs_fattr fattr;
>> @@ -1237,7 +1236,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
>>       tlink = cifs_sb_tlink(cifs_sb);
>>       if (IS_ERR(tlink))
>>               return PTR_ERR(tlink);
>> -     pTcon = tlink_tcon(tlink);
>> +     tcon = tlink_tcon(tlink);
>>
>>       xid = get_xid();
>>
>> @@ -1247,9 +1246,8 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
>>               goto mkdir_out;
>>       }
>>
>> -     if ((pTcon->ses->capabilities & CAP_UNIX) &&
>> -             (CIFS_UNIX_POSIX_PATH_OPS_CAP &
>> -                     le64_to_cpu(pTcon->fsUnixInfo.Capability))) {
>> +     if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
>> +                             le64_to_cpu(tcon->fsUnixInfo.Capability))) {
>>               u32 oplock = 0;
>>               FILE_UNIX_BASIC_INFO *pInfo =
>>                       kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
>> @@ -1259,7 +1257,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
>>               }
>>
>>               mode &= ~current_umask();
>> -             rc = CIFSPOSIXCreate(xid, pTcon, SMB_O_DIRECTORY | SMB_O_CREAT,
>> +             rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT,
>>                               mode, NULL /* netfid */, pInfo, &oplock,
>>                               full_path, cifs_sb->local_nls,
>>                               cifs_sb->mnt_cifs_flags &
>> @@ -1303,14 +1301,14 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
>>       }
>>  mkdir_retry_old:
>>       /* BB add setting the equivalent of mode via CreateX w/ACLs */
>> -     rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls,
>> +     rc = CIFSSMBMkDir(xid, tcon, full_path, cifs_sb->local_nls,
>>                         cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
>>       if (rc) {
>>               cFYI(1, "cifs_mkdir returned 0x%x", rc);
>>               d_drop(direntry);
>>       } else {
>>  mkdir_get_info:
>> -             if (pTcon->unix_ext)
>> +             if (tcon->unix_ext)
>>                       rc = cifs_get_inode_info_unix(&newinode, full_path,
>>                                                     inode->i_sb, xid);
>>               else
>> @@ -1328,7 +1326,7 @@ mkdir_get_info:
>>               if (inode->i_mode & S_ISGID)
>>                       mode |= S_ISGID;
>>
>> -             if (pTcon->unix_ext) {
>> +             if (tcon->unix_ext) {
>>                       struct cifs_unix_set_info_args args = {
>>                               .mode   = mode,
>>                               .ctime  = NO_CHANGE_64,
>> @@ -1346,7 +1344,7 @@ mkdir_get_info:
>>                               args.uid = NO_CHANGE_64;
>>                               args.gid = NO_CHANGE_64;
>>                       }
>> -                     CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args,
>> +                     CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
>>                                              cifs_sb->local_nls,
>>                                              cifs_sb->mnt_cifs_flags &
>>                                               CIFS_MOUNT_MAP_SPECIAL_CHR);
>> @@ -1361,7 +1359,7 @@ mkdir_get_info:
>>                               cifsInode = CIFS_I(newinode);
>>                               dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
>>                               pInfo.Attributes = cpu_to_le32(dosattrs);
>> -                             tmprc = CIFSSMBSetPathInfo(xid, pTcon,
>> +                             tmprc = CIFSSMBSetPathInfo(xid, tcon,
>>                                               full_path, &pInfo,
>>                                               cifs_sb->local_nls,
>>                                               cifs_sb->mnt_cifs_flags &
>> diff --git a/fs/cifs/link.c b/fs/cifs/link.c
>> index 77d781a..d08b76c 100644
>> --- a/fs/cifs/link.c
>> +++ b/fs/cifs/link.c
>> @@ -495,8 +495,8 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
>>        * but there doesn't seem to be any harm in allowing the client to
>>        * read them.
>>        */
>> -     if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
>> -         && !(tcon->ses->capabilities & CAP_UNIX)) {
>> +     if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) &&
>> +         !cap_unix(tcon->ses)) {
>>               rc = -EACCES;
>>               goto out;
>>       }
>> @@ -518,7 +518,7 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
>>                                       cifs_sb->mnt_cifs_flags &
>>                                               CIFS_MOUNT_MAP_SPECIAL_CHR);
>>
>> -     if ((rc != 0) && (tcon->ses->capabilities & CAP_UNIX))
>> +     if ((rc != 0) && cap_unix(tcon->ses))
>>               rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, &target_path,
>>                                            cifs_sb->local_nls);
>>
>> diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
>> index da30d96..d87f826 100644
>> --- a/fs/cifs/readdir.c
>> +++ b/fs/cifs/readdir.c
>> @@ -228,7 +228,7 @@ static int initiate_cifs_search(const unsigned int xid, struct file *file)
>>       struct cifsFileInfo *cifsFile;
>>       struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
>>       struct tcon_link *tlink = NULL;
>> -     struct cifs_tcon *pTcon;
>> +     struct cifs_tcon *tcon;
>>
>>       if (file->private_data == NULL) {
>>               tlink = cifs_sb_tlink(cifs_sb);
>> @@ -242,10 +242,10 @@ static int initiate_cifs_search(const unsigned int xid, struct file *file)
>>               }
>>               file->private_data = cifsFile;
>>               cifsFile->tlink = cifs_get_tlink(tlink);
>> -             pTcon = tlink_tcon(tlink);
>> +             tcon = tlink_tcon(tlink);
>>       } else {
>>               cifsFile = file->private_data;
>> -             pTcon = tlink_tcon(cifsFile->tlink);
>> +             tcon = tlink_tcon(cifsFile->tlink);
>>       }
>>
>>       cifsFile->invalidHandle = true;
>> @@ -262,11 +262,11 @@ static int initiate_cifs_search(const unsigned int xid, struct file *file)
>>  ffirst_retry:
>>       /* test for Unix extensions */
>>       /* but now check for them on the share/mount not on the SMB session */
>> -/*   if (pTcon->ses->capabilities & CAP_UNIX) { */
>> -     if (pTcon->unix_ext)
>> +     /* if (cap_unix(tcon->ses) { */
>> +     if (tcon->unix_ext)
>>               cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX;
>> -     else if ((pTcon->ses->capabilities &
>> -                     (CAP_NT_SMBS | CAP_NT_FIND)) == 0) {
>> +     else if ((tcon->ses->capabilities &
>> +               tcon->ses->server->vals->cap_nt_find) == 0) {
>>               cifsFile->srch_inf.info_level = SMB_FIND_FILE_INFO_STANDARD;
>>       } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
>>               cifsFile->srch_inf.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO;
>> @@ -278,7 +278,7 @@ ffirst_retry:
>>       if (backup_cred(cifs_sb))
>>               search_flags |= CIFS_SEARCH_BACKUP_SEARCH;
>>
>> -     rc = CIFSFindFirst(xid, pTcon, full_path, cifs_sb->local_nls,
>> +     rc = CIFSFindFirst(xid, tcon, full_path, cifs_sb->local_nls,
>>               &cifsFile->netfid, search_flags, &cifsFile->srch_inf,
>>               cifs_sb->mnt_cifs_flags &
>>                       CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
>> diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
>> index 5817409..c40356d 100644
>> --- a/fs/cifs/smb1ops.c
>> +++ b/fs/cifs/smb1ops.c
>> @@ -632,4 +632,7 @@ struct smb_version_values smb1_values = {
>>       .max_header_size = MAX_CIFS_HDR_SIZE,
>>       .read_rsp_size = sizeof(READ_RSP),
>>       .lock_cmd = cpu_to_le16(SMB_COM_LOCKING_ANDX),
>> +     .cap_unix = CAP_UNIX,
>> +     .cap_nt_find = CAP_NT_SMBS | CAP_NT_FIND,
>> +     .cap_large_files = CAP_LARGE_FILES,
>>  };
>> diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
>> index 1018c5c..410cf92 100644
>> --- a/fs/cifs/smb2ops.c
>> +++ b/fs/cifs/smb2ops.c
>> @@ -325,4 +325,7 @@ struct smb_version_values smb21_values = {
>>       .header_size = sizeof(struct smb2_hdr),
>>       .max_header_size = MAX_SMB2_HDR_SIZE,
>>       .lock_cmd = SMB2_LOCK,
>> +     .cap_unix = 0,
>> +     .cap_nt_find = SMB2_NT_FIND,
>> +     .cap_large_files = SMB2_LARGE_FILES,
>>  };
>> diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
>> index e4eb1d3..62b3f17 100644
>> --- a/fs/cifs/smb2pdu.c
>> +++ b/fs/cifs/smb2pdu.c
>> @@ -428,6 +428,8 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
>>       /* BB Do we need to validate the SecurityMode? */
>>       server->sec_mode = le16_to_cpu(rsp->SecurityMode);
>>       server->capabilities = le32_to_cpu(rsp->Capabilities);
>> +     /* Internal types */
>> +     server->capabilities |= SMB2_NT_FIND | SMB2_LARGE_FILES;
>>
>>       security_blob = smb2_get_data_area_len(&blob_offset, &blob_length,
>>                                              &rsp->hdr);
>> diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
>> index 59aae60..f37a1b4 100644
>> --- a/fs/cifs/smb2pdu.h
>> +++ b/fs/cifs/smb2pdu.h
>> @@ -167,6 +167,9 @@ struct smb2_negotiate_req {
>>  #define SMB2_GLOBAL_CAP_DFS          0x00000001
>>  #define SMB2_GLOBAL_CAP_LEASING              0x00000002 /* Resp only New to SMB2.1 */
>>  #define SMB2_GLOBAL_CAP_LARGE_MTU    0X00000004 /* Resp only New to SMB2.1 */
>> +/* Internal types */
>> +#define SMB2_NT_FIND                 0x00100000
>> +#define SMB2_LARGE_FILES             0x00200000
>>
>>  struct smb2_negotiate_rsp {
>>       struct smb2_hdr hdr;
>
>
> --
> Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html



-- 
Best regards,
Pavel Shilovsky.

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

* [PATCH v2 1/45] CIFS: Make CAP_* checks protocol independent
       [not found]     ` <1342626541-29872-2-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
  2012-07-23 13:55       ` Jeff Layton
  2012-07-23 20:59       ` Jeff Layton
@ 2012-07-24  7:21       ` Pavel Shilovsky
       [not found]         ` <1343114502-7908-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
  2 siblings, 1 reply; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-24  7:21 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Since both CIFS and SMB2 use ses->capabilities (server->capabilities)
field but flags are different we should make such checks protocol
independent.

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/cifsglob.h |   14 ++++++++++++--
 fs/cifs/connect.c  |    6 +++---
 fs/cifs/dir.c      |    3 +--
 fs/cifs/file.c     |   33 ++++++++++++++++-----------------
 fs/cifs/inode.c    |   26 ++++++++++++--------------
 fs/cifs/link.c     |    6 +++---
 fs/cifs/readdir.c  |   16 ++++++++--------
 fs/cifs/smb1ops.c  |    3 +++
 fs/cifs/smb2ops.c  |    3 +++
 fs/cifs/smb2pdu.c  |    2 ++
 fs/cifs/smb2pdu.h  |    3 +++
 11 files changed, 66 insertions(+), 49 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 12b1176..bcdf4d4 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -258,6 +258,9 @@ struct smb_version_values {
 	size_t		max_header_size;
 	size_t		read_rsp_size;
 	__le16		lock_cmd;
+	unsigned int	cap_unix;
+	unsigned int	cap_nt_find;
+	unsigned int	cap_large_files;
 };
 
 #define HEADER_SIZE(server) (server->vals->header_size)
@@ -408,7 +411,7 @@ struct TCP_Server_Info {
 	unsigned int max_vcs;	/* maximum number of smb sessions, at least
 				   those that can be specified uniquely with
 				   vcnumbers */
-	int capabilities; /* allow selective disabling of caps by smb sess */
+	unsigned int capabilities; /* selective disabling of caps by smb sess */
 	int timeAdj;  /* Adjust for difference in server time zone in sec */
 	__u64 CurrentMid;         /* multiplex id - rotating counter */
 	char cryptkey[CIFS_CRYPTO_KEY_SIZE]; /* used by ntlm, ntlmv2 etc */
@@ -532,7 +535,7 @@ struct cifs_ses {
 	__u64 Suid;		/* remote smb uid  */
 	uid_t linux_uid;        /* overriding owner of files on the mount */
 	uid_t cred_uid;		/* owner of credentials */
-	int capabilities;
+	unsigned int capabilities;
 	char serverName[SERVER_NAME_LEN_WITH_NULL * 2];	/* BB make bigger for
 				TCP names - will ipv6 and sctp addresses fit? */
 	char *user_name;	/* must not be null except during init of sess
@@ -554,6 +557,13 @@ struct cifs_ses {
    which do not negotiate NTLM or POSIX dialects, but instead
    negotiate one of the older LANMAN dialects */
 #define CIFS_SES_LANMAN 8
+
+static inline bool
+cap_unix(struct cifs_ses *ses)
+{
+	return ses->server->vals->cap_unix & ses->capabilities;
+}
+
 /*
  * there is one of these for each connection to a resource on a particular
  * session
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 5ab173f..6df6fa1 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -3634,7 +3634,7 @@ try_mount_again:
 	}
 
 	/* tell server which Unix caps we support */
-	if (tcon->ses->capabilities & CAP_UNIX) {
+	if (cap_unix(tcon->ses)) {
 		/* reset of caps checks mount to see if unix extensions
 		   disabled for just this mount */
 		reset_cifs_unix_caps(xid, tcon, cifs_sb, volume_info);
@@ -3993,7 +3993,7 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
 	ses->flags = 0;
 	ses->capabilities = server->capabilities;
 	if (linuxExtEnabled == 0)
-		ses->capabilities &= (~CAP_UNIX);
+		ses->capabilities &= (~server->vals->cap_unix);
 
 	cFYI(1, "Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
 		 server->sec_mode, server->capabilities, server->timeAdj);
@@ -4100,7 +4100,7 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid)
 		goto out;
 	}
 
-	if (ses->capabilities & CAP_UNIX)
+	if (cap_unix(ses))
 		reset_cifs_unix_caps(0, tcon, NULL, vol_info);
 out:
 	kfree(vol_info->username);
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 2caba0b..cbe709a 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -182,8 +182,7 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
 		goto out;
 	}
 
-	if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
-	    !tcon->broken_posix_open &&
+	if (tcon->unix_ext && cap_unix(tcon->ses) && !tcon->broken_posix_open &&
 	    (CIFS_UNIX_POSIX_PATH_OPS_CAP &
 			le64_to_cpu(tcon->fsUnixInfo.Capability))) {
 		rc = cifs_posix_open(full_path, &newinode,
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 93b3b13..07e9d41 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -385,9 +385,8 @@ int cifs_open(struct inode *inode, struct file *file)
 		oplock = 0;
 
 	if (!tcon->broken_posix_open && tcon->unix_ext &&
-	    (tcon->ses->capabilities & CAP_UNIX) &&
-	    (CIFS_UNIX_POSIX_PATH_OPS_CAP &
-			le64_to_cpu(tcon->fsUnixInfo.Capability))) {
+	    cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
+				le64_to_cpu(tcon->fsUnixInfo.Capability))) {
 		/* can not refresh inode info since size could be stale */
 		rc = cifs_posix_open(full_path, &inode, inode->i_sb,
 				cifs_sb->mnt_file_mode /* ignored */,
@@ -509,10 +508,9 @@ static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
 	else
 		oplock = 0;
 
-	if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
+	if (tcon->unix_ext && cap_unix(tcon->ses) &&
 	    (CIFS_UNIX_POSIX_PATH_OPS_CAP &
-			le64_to_cpu(tcon->fsUnixInfo.Capability))) {
-
+				le64_to_cpu(tcon->fsUnixInfo.Capability))) {
 		/*
 		 * O_CREAT, O_EXCL and O_TRUNC already had their effect on the
 		 * original open. Must mask them off for a reopen.
@@ -1071,7 +1069,7 @@ cifs_push_locks(struct cifsFileInfo *cfile)
 	struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->dentry->d_sb);
 	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
 
-	if ((tcon->ses->capabilities & CAP_UNIX) &&
+	if (cap_unix(tcon->ses) &&
 	    (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
 	    ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
 		return cifs_push_posix_locks(cfile);
@@ -1419,7 +1417,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock)
 	netfid = cfile->netfid;
 	cinode = CIFS_I(file->f_path.dentry->d_inode);
 
-	if ((tcon->ses->capabilities & CAP_UNIX) &&
+	if (cap_unix(tcon->ses) &&
 	    (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
 	    ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
 		posix_lck = true;
@@ -2745,7 +2743,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
 	unsigned int current_read_size;
 	unsigned int rsize;
 	struct cifs_sb_info *cifs_sb;
-	struct cifs_tcon *pTcon;
+	struct cifs_tcon *tcon;
 	unsigned int xid;
 	char *current_offset;
 	struct cifsFileInfo *open_file;
@@ -2765,7 +2763,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
 		return rc;
 	}
 	open_file = file->private_data;
-	pTcon = tlink_tcon(open_file->tlink);
+	tcon = tlink_tcon(open_file->tlink);
 
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
 		pid = open_file->pid;
@@ -2779,11 +2777,12 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
 	     read_size > total_read;
 	     total_read += bytes_read, current_offset += bytes_read) {
 		current_read_size = min_t(uint, read_size - total_read, rsize);
-
-		/* For windows me and 9x we do not want to request more
-		than it negotiated since it will refuse the read then */
-		if ((pTcon->ses) &&
-			!(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
+		/*
+		 * For windows me and 9x we do not want to request more than it
+		 * negotiated since it will refuse the read then.
+		 */
+		if ((tcon->ses) && !(tcon->ses->capabilities &
+				tcon->ses->server->vals->cap_large_files)) {
 			current_read_size = min_t(uint, current_read_size,
 					CIFSMaxBufSize);
 		}
@@ -2796,7 +2795,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
 			}
 			io_parms.netfid = open_file->netfid;
 			io_parms.pid = pid;
-			io_parms.tcon = pTcon;
+			io_parms.tcon = tcon;
 			io_parms.offset = *poffset;
 			io_parms.length = current_read_size;
 			rc = CIFSSMBRead(xid, &io_parms, &bytes_read,
@@ -2810,7 +2809,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
 				return rc;
 			}
 		} else {
-			cifs_stats_bytes_read(pTcon, total_read);
+			cifs_stats_bytes_read(tcon, total_read);
 			*poffset += bytes_read;
 		}
 	}
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index def1006..35cb6a3 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1149,9 +1149,8 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
 		goto unlink_out;
 	}
 
-	if ((tcon->ses->capabilities & CAP_UNIX) &&
-		(CIFS_UNIX_POSIX_PATH_OPS_CAP &
-			le64_to_cpu(tcon->fsUnixInfo.Capability))) {
+	if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
+				le64_to_cpu(tcon->fsUnixInfo.Capability))) {
 		rc = CIFSPOSIXDelFile(xid, tcon, full_path,
 			SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls,
 			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -1226,7 +1225,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
 	unsigned int xid;
 	struct cifs_sb_info *cifs_sb;
 	struct tcon_link *tlink;
-	struct cifs_tcon *pTcon;
+	struct cifs_tcon *tcon;
 	char *full_path = NULL;
 	struct inode *newinode = NULL;
 	struct cifs_fattr fattr;
@@ -1237,7 +1236,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
 	tlink = cifs_sb_tlink(cifs_sb);
 	if (IS_ERR(tlink))
 		return PTR_ERR(tlink);
-	pTcon = tlink_tcon(tlink);
+	tcon = tlink_tcon(tlink);
 
 	xid = get_xid();
 
@@ -1247,9 +1246,8 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
 		goto mkdir_out;
 	}
 
-	if ((pTcon->ses->capabilities & CAP_UNIX) &&
-		(CIFS_UNIX_POSIX_PATH_OPS_CAP &
-			le64_to_cpu(pTcon->fsUnixInfo.Capability))) {
+	if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
+				le64_to_cpu(tcon->fsUnixInfo.Capability))) {
 		u32 oplock = 0;
 		FILE_UNIX_BASIC_INFO *pInfo =
 			kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
@@ -1259,7 +1257,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
 		}
 
 		mode &= ~current_umask();
-		rc = CIFSPOSIXCreate(xid, pTcon, SMB_O_DIRECTORY | SMB_O_CREAT,
+		rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT,
 				mode, NULL /* netfid */, pInfo, &oplock,
 				full_path, cifs_sb->local_nls,
 				cifs_sb->mnt_cifs_flags &
@@ -1303,14 +1301,14 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
 	}
 mkdir_retry_old:
 	/* BB add setting the equivalent of mode via CreateX w/ACLs */
-	rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls,
+	rc = CIFSSMBMkDir(xid, tcon, full_path, cifs_sb->local_nls,
 			  cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 	if (rc) {
 		cFYI(1, "cifs_mkdir returned 0x%x", rc);
 		d_drop(direntry);
 	} else {
 mkdir_get_info:
-		if (pTcon->unix_ext)
+		if (tcon->unix_ext)
 			rc = cifs_get_inode_info_unix(&newinode, full_path,
 						      inode->i_sb, xid);
 		else
@@ -1328,7 +1326,7 @@ mkdir_get_info:
 		if (inode->i_mode & S_ISGID)
 			mode |= S_ISGID;
 
-		if (pTcon->unix_ext) {
+		if (tcon->unix_ext) {
 			struct cifs_unix_set_info_args args = {
 				.mode	= mode,
 				.ctime	= NO_CHANGE_64,
@@ -1346,7 +1344,7 @@ mkdir_get_info:
 				args.uid = NO_CHANGE_64;
 				args.gid = NO_CHANGE_64;
 			}
-			CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args,
+			CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
 					       cifs_sb->local_nls,
 					       cifs_sb->mnt_cifs_flags &
 						CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -1361,7 +1359,7 @@ mkdir_get_info:
 				cifsInode = CIFS_I(newinode);
 				dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
 				pInfo.Attributes = cpu_to_le32(dosattrs);
-				tmprc = CIFSSMBSetPathInfo(xid, pTcon,
+				tmprc = CIFSSMBSetPathInfo(xid, tcon,
 						full_path, &pInfo,
 						cifs_sb->local_nls,
 						cifs_sb->mnt_cifs_flags &
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index f789715..09e4b3a 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -495,8 +495,8 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
 	 * but there doesn't seem to be any harm in allowing the client to
 	 * read them.
 	 */
-	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
-	    && !(tcon->ses->capabilities & CAP_UNIX)) {
+	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) &&
+	    !cap_unix(tcon->ses)) {
 		rc = -EACCES;
 		goto out;
 	}
@@ -518,7 +518,7 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
 					cifs_sb->mnt_cifs_flags &
 						CIFS_MOUNT_MAP_SPECIAL_CHR);
 
-	if ((rc != 0) && (tcon->ses->capabilities & CAP_UNIX))
+	if ((rc != 0) && cap_unix(tcon->ses))
 		rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, &target_path,
 					     cifs_sb->local_nls);
 
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index da30d96..d87f826 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -228,7 +228,7 @@ static int initiate_cifs_search(const unsigned int xid, struct file *file)
 	struct cifsFileInfo *cifsFile;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
 	struct tcon_link *tlink = NULL;
-	struct cifs_tcon *pTcon;
+	struct cifs_tcon *tcon;
 
 	if (file->private_data == NULL) {
 		tlink = cifs_sb_tlink(cifs_sb);
@@ -242,10 +242,10 @@ static int initiate_cifs_search(const unsigned int xid, struct file *file)
 		}
 		file->private_data = cifsFile;
 		cifsFile->tlink = cifs_get_tlink(tlink);
-		pTcon = tlink_tcon(tlink);
+		tcon = tlink_tcon(tlink);
 	} else {
 		cifsFile = file->private_data;
-		pTcon = tlink_tcon(cifsFile->tlink);
+		tcon = tlink_tcon(cifsFile->tlink);
 	}
 
 	cifsFile->invalidHandle = true;
@@ -262,11 +262,11 @@ static int initiate_cifs_search(const unsigned int xid, struct file *file)
 ffirst_retry:
 	/* test for Unix extensions */
 	/* but now check for them on the share/mount not on the SMB session */
-/*	if (pTcon->ses->capabilities & CAP_UNIX) { */
-	if (pTcon->unix_ext)
+	/* if (cap_unix(tcon->ses) { */
+	if (tcon->unix_ext)
 		cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX;
-	else if ((pTcon->ses->capabilities &
-			(CAP_NT_SMBS | CAP_NT_FIND)) == 0) {
+	else if ((tcon->ses->capabilities &
+		  tcon->ses->server->vals->cap_nt_find) == 0) {
 		cifsFile->srch_inf.info_level = SMB_FIND_FILE_INFO_STANDARD;
 	} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
 		cifsFile->srch_inf.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO;
@@ -278,7 +278,7 @@ ffirst_retry:
 	if (backup_cred(cifs_sb))
 		search_flags |= CIFS_SEARCH_BACKUP_SEARCH;
 
-	rc = CIFSFindFirst(xid, pTcon, full_path, cifs_sb->local_nls,
+	rc = CIFSFindFirst(xid, tcon, full_path, cifs_sb->local_nls,
 		&cifsFile->netfid, search_flags, &cifsFile->srch_inf,
 		cifs_sb->mnt_cifs_flags &
 			CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 5817409..c40356d 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -632,4 +632,7 @@ struct smb_version_values smb1_values = {
 	.max_header_size = MAX_CIFS_HDR_SIZE,
 	.read_rsp_size = sizeof(READ_RSP),
 	.lock_cmd = cpu_to_le16(SMB_COM_LOCKING_ANDX),
+	.cap_unix = CAP_UNIX,
+	.cap_nt_find = CAP_NT_SMBS | CAP_NT_FIND,
+	.cap_large_files = CAP_LARGE_FILES,
 };
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 1018c5c..410cf92 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -325,4 +325,7 @@ struct smb_version_values smb21_values = {
 	.header_size = sizeof(struct smb2_hdr),
 	.max_header_size = MAX_SMB2_HDR_SIZE,
 	.lock_cmd = SMB2_LOCK,
+	.cap_unix = 0,
+	.cap_nt_find = SMB2_NT_FIND,
+	.cap_large_files = SMB2_LARGE_FILES,
 };
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index e4eb1d3..62b3f17 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -428,6 +428,8 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
 	/* BB Do we need to validate the SecurityMode? */
 	server->sec_mode = le16_to_cpu(rsp->SecurityMode);
 	server->capabilities = le32_to_cpu(rsp->Capabilities);
+	/* Internal types */
+	server->capabilities |= SMB2_NT_FIND | SMB2_LARGE_FILES;
 
 	security_blob = smb2_get_data_area_len(&blob_offset, &blob_length,
 					       &rsp->hdr);
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 59aae60..f37a1b4 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -167,6 +167,9 @@ struct smb2_negotiate_req {
 #define SMB2_GLOBAL_CAP_DFS		0x00000001
 #define SMB2_GLOBAL_CAP_LEASING		0x00000002 /* Resp only New to SMB2.1 */
 #define SMB2_GLOBAL_CAP_LARGE_MTU	0X00000004 /* Resp only New to SMB2.1 */
+/* Internal types */
+#define SMB2_NT_FIND			0x00100000
+#define SMB2_LARGE_FILES		0x00200000
 
 struct smb2_negotiate_rsp {
 	struct smb2_hdr hdr;
-- 
1.7.1

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

* Re: [PATCH v2 1/45] CIFS: Make CAP_* checks protocol independent
       [not found]         ` <1343114502-7908-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
@ 2012-07-24 17:44           ` Jeff Layton
  0 siblings, 0 replies; 74+ messages in thread
From: Jeff Layton @ 2012-07-24 17:44 UTC (permalink / raw)
  To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA

On Tue, 24 Jul 2012 11:21:42 +0400
Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:

> Since both CIFS and SMB2 use ses->capabilities (server->capabilities)
> field but flags are different we should make such checks protocol
> independent.
> 
> Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
> ---
>  fs/cifs/cifsglob.h |   14 ++++++++++++--
>  fs/cifs/connect.c  |    6 +++---
>  fs/cifs/dir.c      |    3 +--
>  fs/cifs/file.c     |   33 ++++++++++++++++-----------------
>  fs/cifs/inode.c    |   26 ++++++++++++--------------
>  fs/cifs/link.c     |    6 +++---
>  fs/cifs/readdir.c  |   16 ++++++++--------
>  fs/cifs/smb1ops.c  |    3 +++
>  fs/cifs/smb2ops.c  |    3 +++
>  fs/cifs/smb2pdu.c  |    2 ++
>  fs/cifs/smb2pdu.h  |    3 +++
>  11 files changed, 66 insertions(+), 49 deletions(-)
> 
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index 12b1176..bcdf4d4 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -258,6 +258,9 @@ struct smb_version_values {
>  	size_t		max_header_size;
>  	size_t		read_rsp_size;
>  	__le16		lock_cmd;
> +	unsigned int	cap_unix;
> +	unsigned int	cap_nt_find;
> +	unsigned int	cap_large_files;
>  };
>  
>  #define HEADER_SIZE(server) (server->vals->header_size)
> @@ -408,7 +411,7 @@ struct TCP_Server_Info {
>  	unsigned int max_vcs;	/* maximum number of smb sessions, at least
>  				   those that can be specified uniquely with
>  				   vcnumbers */
> -	int capabilities; /* allow selective disabling of caps by smb sess */
> +	unsigned int capabilities; /* selective disabling of caps by smb sess */
>  	int timeAdj;  /* Adjust for difference in server time zone in sec */
>  	__u64 CurrentMid;         /* multiplex id - rotating counter */
>  	char cryptkey[CIFS_CRYPTO_KEY_SIZE]; /* used by ntlm, ntlmv2 etc */
> @@ -532,7 +535,7 @@ struct cifs_ses {
>  	__u64 Suid;		/* remote smb uid  */
>  	uid_t linux_uid;        /* overriding owner of files on the mount */
>  	uid_t cred_uid;		/* owner of credentials */
> -	int capabilities;
> +	unsigned int capabilities;
>  	char serverName[SERVER_NAME_LEN_WITH_NULL * 2];	/* BB make bigger for
>  				TCP names - will ipv6 and sctp addresses fit? */
>  	char *user_name;	/* must not be null except during init of sess
> @@ -554,6 +557,13 @@ struct cifs_ses {
>     which do not negotiate NTLM or POSIX dialects, but instead
>     negotiate one of the older LANMAN dialects */
>  #define CIFS_SES_LANMAN 8
> +
> +static inline bool
> +cap_unix(struct cifs_ses *ses)
> +{
> +	return ses->server->vals->cap_unix & ses->capabilities;
> +}
> +
>  /*
>   * there is one of these for each connection to a resource on a particular
>   * session
> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
> index 5ab173f..6df6fa1 100644
> --- a/fs/cifs/connect.c
> +++ b/fs/cifs/connect.c
> @@ -3634,7 +3634,7 @@ try_mount_again:
>  	}
>  
>  	/* tell server which Unix caps we support */
> -	if (tcon->ses->capabilities & CAP_UNIX) {
> +	if (cap_unix(tcon->ses)) {
>  		/* reset of caps checks mount to see if unix extensions
>  		   disabled for just this mount */
>  		reset_cifs_unix_caps(xid, tcon, cifs_sb, volume_info);
> @@ -3993,7 +3993,7 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
>  	ses->flags = 0;
>  	ses->capabilities = server->capabilities;
>  	if (linuxExtEnabled == 0)
> -		ses->capabilities &= (~CAP_UNIX);
> +		ses->capabilities &= (~server->vals->cap_unix);
>  
>  	cFYI(1, "Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
>  		 server->sec_mode, server->capabilities, server->timeAdj);
> @@ -4100,7 +4100,7 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid)
>  		goto out;
>  	}
>  
> -	if (ses->capabilities & CAP_UNIX)
> +	if (cap_unix(ses))
>  		reset_cifs_unix_caps(0, tcon, NULL, vol_info);
>  out:
>  	kfree(vol_info->username);
> diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
> index 2caba0b..cbe709a 100644
> --- a/fs/cifs/dir.c
> +++ b/fs/cifs/dir.c
> @@ -182,8 +182,7 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
>  		goto out;
>  	}
>  
> -	if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
> -	    !tcon->broken_posix_open &&
> +	if (tcon->unix_ext && cap_unix(tcon->ses) && !tcon->broken_posix_open &&
>  	    (CIFS_UNIX_POSIX_PATH_OPS_CAP &
>  			le64_to_cpu(tcon->fsUnixInfo.Capability))) {
>  		rc = cifs_posix_open(full_path, &newinode,
> diff --git a/fs/cifs/file.c b/fs/cifs/file.c
> index 93b3b13..07e9d41 100644
> --- a/fs/cifs/file.c
> +++ b/fs/cifs/file.c
> @@ -385,9 +385,8 @@ int cifs_open(struct inode *inode, struct file *file)
>  		oplock = 0;
>  
>  	if (!tcon->broken_posix_open && tcon->unix_ext &&
> -	    (tcon->ses->capabilities & CAP_UNIX) &&
> -	    (CIFS_UNIX_POSIX_PATH_OPS_CAP &
> -			le64_to_cpu(tcon->fsUnixInfo.Capability))) {
> +	    cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
> +				le64_to_cpu(tcon->fsUnixInfo.Capability))) {
>  		/* can not refresh inode info since size could be stale */
>  		rc = cifs_posix_open(full_path, &inode, inode->i_sb,
>  				cifs_sb->mnt_file_mode /* ignored */,
> @@ -509,10 +508,9 @@ static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
>  	else
>  		oplock = 0;
>  
> -	if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
> +	if (tcon->unix_ext && cap_unix(tcon->ses) &&
>  	    (CIFS_UNIX_POSIX_PATH_OPS_CAP &
> -			le64_to_cpu(tcon->fsUnixInfo.Capability))) {
> -
> +				le64_to_cpu(tcon->fsUnixInfo.Capability))) {
>  		/*
>  		 * O_CREAT, O_EXCL and O_TRUNC already had their effect on the
>  		 * original open. Must mask them off for a reopen.
> @@ -1071,7 +1069,7 @@ cifs_push_locks(struct cifsFileInfo *cfile)
>  	struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->dentry->d_sb);
>  	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
>  
> -	if ((tcon->ses->capabilities & CAP_UNIX) &&
> +	if (cap_unix(tcon->ses) &&
>  	    (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
>  	    ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
>  		return cifs_push_posix_locks(cfile);
> @@ -1419,7 +1417,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock)
>  	netfid = cfile->netfid;
>  	cinode = CIFS_I(file->f_path.dentry->d_inode);
>  
> -	if ((tcon->ses->capabilities & CAP_UNIX) &&
> +	if (cap_unix(tcon->ses) &&
>  	    (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
>  	    ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
>  		posix_lck = true;
> @@ -2745,7 +2743,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
>  	unsigned int current_read_size;
>  	unsigned int rsize;
>  	struct cifs_sb_info *cifs_sb;
> -	struct cifs_tcon *pTcon;
> +	struct cifs_tcon *tcon;
>  	unsigned int xid;
>  	char *current_offset;
>  	struct cifsFileInfo *open_file;
> @@ -2765,7 +2763,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
>  		return rc;
>  	}
>  	open_file = file->private_data;
> -	pTcon = tlink_tcon(open_file->tlink);
> +	tcon = tlink_tcon(open_file->tlink);
>  
>  	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
>  		pid = open_file->pid;
> @@ -2779,11 +2777,12 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
>  	     read_size > total_read;
>  	     total_read += bytes_read, current_offset += bytes_read) {
>  		current_read_size = min_t(uint, read_size - total_read, rsize);
> -
> -		/* For windows me and 9x we do not want to request more
> -		than it negotiated since it will refuse the read then */
> -		if ((pTcon->ses) &&
> -			!(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
> +		/*
> +		 * For windows me and 9x we do not want to request more than it
> +		 * negotiated since it will refuse the read then.
> +		 */
> +		if ((tcon->ses) && !(tcon->ses->capabilities &
> +				tcon->ses->server->vals->cap_large_files)) {
>  			current_read_size = min_t(uint, current_read_size,
>  					CIFSMaxBufSize);
>  		}
> @@ -2796,7 +2795,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
>  			}
>  			io_parms.netfid = open_file->netfid;
>  			io_parms.pid = pid;
> -			io_parms.tcon = pTcon;
> +			io_parms.tcon = tcon;
>  			io_parms.offset = *poffset;
>  			io_parms.length = current_read_size;
>  			rc = CIFSSMBRead(xid, &io_parms, &bytes_read,
> @@ -2810,7 +2809,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
>  				return rc;
>  			}
>  		} else {
> -			cifs_stats_bytes_read(pTcon, total_read);
> +			cifs_stats_bytes_read(tcon, total_read);
>  			*poffset += bytes_read;
>  		}
>  	}
> diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
> index def1006..35cb6a3 100644
> --- a/fs/cifs/inode.c
> +++ b/fs/cifs/inode.c
> @@ -1149,9 +1149,8 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
>  		goto unlink_out;
>  	}
>  
> -	if ((tcon->ses->capabilities & CAP_UNIX) &&
> -		(CIFS_UNIX_POSIX_PATH_OPS_CAP &
> -			le64_to_cpu(tcon->fsUnixInfo.Capability))) {
> +	if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
> +				le64_to_cpu(tcon->fsUnixInfo.Capability))) {
>  		rc = CIFSPOSIXDelFile(xid, tcon, full_path,
>  			SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls,
>  			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
> @@ -1226,7 +1225,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
>  	unsigned int xid;
>  	struct cifs_sb_info *cifs_sb;
>  	struct tcon_link *tlink;
> -	struct cifs_tcon *pTcon;
> +	struct cifs_tcon *tcon;
>  	char *full_path = NULL;
>  	struct inode *newinode = NULL;
>  	struct cifs_fattr fattr;
> @@ -1237,7 +1236,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
>  	tlink = cifs_sb_tlink(cifs_sb);
>  	if (IS_ERR(tlink))
>  		return PTR_ERR(tlink);
> -	pTcon = tlink_tcon(tlink);
> +	tcon = tlink_tcon(tlink);
>  
>  	xid = get_xid();
>  
> @@ -1247,9 +1246,8 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
>  		goto mkdir_out;
>  	}
>  
> -	if ((pTcon->ses->capabilities & CAP_UNIX) &&
> -		(CIFS_UNIX_POSIX_PATH_OPS_CAP &
> -			le64_to_cpu(pTcon->fsUnixInfo.Capability))) {
> +	if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
> +				le64_to_cpu(tcon->fsUnixInfo.Capability))) {
>  		u32 oplock = 0;
>  		FILE_UNIX_BASIC_INFO *pInfo =
>  			kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
> @@ -1259,7 +1257,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
>  		}
>  
>  		mode &= ~current_umask();
> -		rc = CIFSPOSIXCreate(xid, pTcon, SMB_O_DIRECTORY | SMB_O_CREAT,
> +		rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT,
>  				mode, NULL /* netfid */, pInfo, &oplock,
>  				full_path, cifs_sb->local_nls,
>  				cifs_sb->mnt_cifs_flags &
> @@ -1303,14 +1301,14 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
>  	}
>  mkdir_retry_old:
>  	/* BB add setting the equivalent of mode via CreateX w/ACLs */
> -	rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls,
> +	rc = CIFSSMBMkDir(xid, tcon, full_path, cifs_sb->local_nls,
>  			  cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
>  	if (rc) {
>  		cFYI(1, "cifs_mkdir returned 0x%x", rc);
>  		d_drop(direntry);
>  	} else {
>  mkdir_get_info:
> -		if (pTcon->unix_ext)
> +		if (tcon->unix_ext)
>  			rc = cifs_get_inode_info_unix(&newinode, full_path,
>  						      inode->i_sb, xid);
>  		else
> @@ -1328,7 +1326,7 @@ mkdir_get_info:
>  		if (inode->i_mode & S_ISGID)
>  			mode |= S_ISGID;
>  
> -		if (pTcon->unix_ext) {
> +		if (tcon->unix_ext) {
>  			struct cifs_unix_set_info_args args = {
>  				.mode	= mode,
>  				.ctime	= NO_CHANGE_64,
> @@ -1346,7 +1344,7 @@ mkdir_get_info:
>  				args.uid = NO_CHANGE_64;
>  				args.gid = NO_CHANGE_64;
>  			}
> -			CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args,
> +			CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
>  					       cifs_sb->local_nls,
>  					       cifs_sb->mnt_cifs_flags &
>  						CIFS_MOUNT_MAP_SPECIAL_CHR);
> @@ -1361,7 +1359,7 @@ mkdir_get_info:
>  				cifsInode = CIFS_I(newinode);
>  				dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
>  				pInfo.Attributes = cpu_to_le32(dosattrs);
> -				tmprc = CIFSSMBSetPathInfo(xid, pTcon,
> +				tmprc = CIFSSMBSetPathInfo(xid, tcon,
>  						full_path, &pInfo,
>  						cifs_sb->local_nls,
>  						cifs_sb->mnt_cifs_flags &
> diff --git a/fs/cifs/link.c b/fs/cifs/link.c
> index f789715..09e4b3a 100644
> --- a/fs/cifs/link.c
> +++ b/fs/cifs/link.c
> @@ -495,8 +495,8 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
>  	 * but there doesn't seem to be any harm in allowing the client to
>  	 * read them.
>  	 */
> -	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
> -	    && !(tcon->ses->capabilities & CAP_UNIX)) {
> +	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) &&
> +	    !cap_unix(tcon->ses)) {
>  		rc = -EACCES;
>  		goto out;
>  	}
> @@ -518,7 +518,7 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
>  					cifs_sb->mnt_cifs_flags &
>  						CIFS_MOUNT_MAP_SPECIAL_CHR);
>  
> -	if ((rc != 0) && (tcon->ses->capabilities & CAP_UNIX))
> +	if ((rc != 0) && cap_unix(tcon->ses))
>  		rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, &target_path,
>  					     cifs_sb->local_nls);
>  
> diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
> index da30d96..d87f826 100644
> --- a/fs/cifs/readdir.c
> +++ b/fs/cifs/readdir.c
> @@ -228,7 +228,7 @@ static int initiate_cifs_search(const unsigned int xid, struct file *file)
>  	struct cifsFileInfo *cifsFile;
>  	struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
>  	struct tcon_link *tlink = NULL;
> -	struct cifs_tcon *pTcon;
> +	struct cifs_tcon *tcon;
>  
>  	if (file->private_data == NULL) {
>  		tlink = cifs_sb_tlink(cifs_sb);
> @@ -242,10 +242,10 @@ static int initiate_cifs_search(const unsigned int xid, struct file *file)
>  		}
>  		file->private_data = cifsFile;
>  		cifsFile->tlink = cifs_get_tlink(tlink);
> -		pTcon = tlink_tcon(tlink);
> +		tcon = tlink_tcon(tlink);
>  	} else {
>  		cifsFile = file->private_data;
> -		pTcon = tlink_tcon(cifsFile->tlink);
> +		tcon = tlink_tcon(cifsFile->tlink);
>  	}
>  
>  	cifsFile->invalidHandle = true;
> @@ -262,11 +262,11 @@ static int initiate_cifs_search(const unsigned int xid, struct file *file)
>  ffirst_retry:
>  	/* test for Unix extensions */
>  	/* but now check for them on the share/mount not on the SMB session */
> -/*	if (pTcon->ses->capabilities & CAP_UNIX) { */
> -	if (pTcon->unix_ext)
> +	/* if (cap_unix(tcon->ses) { */
> +	if (tcon->unix_ext)
>  		cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX;
> -	else if ((pTcon->ses->capabilities &
> -			(CAP_NT_SMBS | CAP_NT_FIND)) == 0) {
> +	else if ((tcon->ses->capabilities &
> +		  tcon->ses->server->vals->cap_nt_find) == 0) {
>  		cifsFile->srch_inf.info_level = SMB_FIND_FILE_INFO_STANDARD;
>  	} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
>  		cifsFile->srch_inf.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO;
> @@ -278,7 +278,7 @@ ffirst_retry:
>  	if (backup_cred(cifs_sb))
>  		search_flags |= CIFS_SEARCH_BACKUP_SEARCH;
>  
> -	rc = CIFSFindFirst(xid, pTcon, full_path, cifs_sb->local_nls,
> +	rc = CIFSFindFirst(xid, tcon, full_path, cifs_sb->local_nls,
>  		&cifsFile->netfid, search_flags, &cifsFile->srch_inf,
>  		cifs_sb->mnt_cifs_flags &
>  			CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
> diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
> index 5817409..c40356d 100644
> --- a/fs/cifs/smb1ops.c
> +++ b/fs/cifs/smb1ops.c
> @@ -632,4 +632,7 @@ struct smb_version_values smb1_values = {
>  	.max_header_size = MAX_CIFS_HDR_SIZE,
>  	.read_rsp_size = sizeof(READ_RSP),
>  	.lock_cmd = cpu_to_le16(SMB_COM_LOCKING_ANDX),
> +	.cap_unix = CAP_UNIX,
> +	.cap_nt_find = CAP_NT_SMBS | CAP_NT_FIND,
> +	.cap_large_files = CAP_LARGE_FILES,
>  };
> diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
> index 1018c5c..410cf92 100644
> --- a/fs/cifs/smb2ops.c
> +++ b/fs/cifs/smb2ops.c
> @@ -325,4 +325,7 @@ struct smb_version_values smb21_values = {
>  	.header_size = sizeof(struct smb2_hdr),
>  	.max_header_size = MAX_SMB2_HDR_SIZE,
>  	.lock_cmd = SMB2_LOCK,
> +	.cap_unix = 0,
> +	.cap_nt_find = SMB2_NT_FIND,
> +	.cap_large_files = SMB2_LARGE_FILES,
>  };
> diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
> index e4eb1d3..62b3f17 100644
> --- a/fs/cifs/smb2pdu.c
> +++ b/fs/cifs/smb2pdu.c
> @@ -428,6 +428,8 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
>  	/* BB Do we need to validate the SecurityMode? */
>  	server->sec_mode = le16_to_cpu(rsp->SecurityMode);
>  	server->capabilities = le32_to_cpu(rsp->Capabilities);
> +	/* Internal types */
> +	server->capabilities |= SMB2_NT_FIND | SMB2_LARGE_FILES;
>  
>  	security_blob = smb2_get_data_area_len(&blob_offset, &blob_length,
>  					       &rsp->hdr);
> diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
> index 59aae60..f37a1b4 100644
> --- a/fs/cifs/smb2pdu.h
> +++ b/fs/cifs/smb2pdu.h
> @@ -167,6 +167,9 @@ struct smb2_negotiate_req {
>  #define SMB2_GLOBAL_CAP_DFS		0x00000001
>  #define SMB2_GLOBAL_CAP_LEASING		0x00000002 /* Resp only New to SMB2.1 */
>  #define SMB2_GLOBAL_CAP_LARGE_MTU	0X00000004 /* Resp only New to SMB2.1 */
> +/* Internal types */
> +#define SMB2_NT_FIND			0x00100000
> +#define SMB2_LARGE_FILES		0x00200000
>  
>  struct smb2_negotiate_rsp {
>  	struct smb2_hdr hdr;

Looks good...

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

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

* Re: [PATCH 07/45] CIFS: Protect i_nlink from being negative
       [not found]     ` <1342626541-29872-8-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
@ 2012-07-28 11:48       ` Jeff Layton
  0 siblings, 0 replies; 74+ messages in thread
From: Jeff Layton @ 2012-07-28 11:48 UTC (permalink / raw)
  To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA

On Wed, 18 Jul 2012 19:48:23 +0400
Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:

> that can cause warning messages.
> 
> Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
> ---
>  fs/cifs/inode.c |   13 +++++++++++--
>  1 files changed, 11 insertions(+), 2 deletions(-)
> 
> diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
> index 7354877..88afb1a 100644
> --- a/fs/cifs/inode.c
> +++ b/fs/cifs/inode.c
> @@ -1110,6 +1110,15 @@ undo_setattr:
>  	goto out_close;
>  }
>  
> +/* copied from fs/nfs/dir.c with small changes */
> +static void
> +cifs_drop_nlink(struct inode *inode)
> +{
> +	spin_lock(&inode->i_lock);
> +	if (inode->i_nlink > 0)
> +		drop_nlink(inode);
> +	spin_unlock(&inode->i_lock);
> +}
>  

As I mentioned to Steve yesterday, the spinlocking above doesn't really
do you any good. Other updates to i_nlink are not serialized by the
i_lock. It's easily possible for another thread to race in and set
i_nlink to 0 after you check it but before calling drop_nlink.

The above change looks reasonable if you also fix those places to be
done under the i_lock as well. In fact, what might be best is a patch
that fixes the code to do all inode attribute updates under the i_lock.

If a CPU ends up reordering some of the stores, then you could end up
with an inode that represents some attributes from one update and some
from another.

>  /*
>   * If dentry->d_inode is null (usually meaning the cached dentry
> @@ -1166,13 +1175,13 @@ retry_std_delete:
>  psx_del_no_retry:
>  	if (!rc) {
>  		if (inode)
> -			drop_nlink(inode);
> +			cifs_drop_nlink(inode);
>  	} else if (rc == -ENOENT) {
>  		d_drop(dentry);
>  	} else if (rc == -ETXTBSY) {
>  		rc = cifs_rename_pending_delete(full_path, dentry, xid);
>  		if (rc == 0)
> -			drop_nlink(inode);
> +			cifs_drop_nlink(inode);
>  	} else if ((rc == -EACCES) && (dosattr == 0) && inode) {
>  		attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
>  		if (attrs == NULL) {


-- 
Jeff Layton <jlayton-vpEMnDpepFuMZCB2o+C8xQ@public.gmane.org>

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

* Re: [PATCH 02/45] CIFS: Simpliify cifs_mkdir call
       [not found]     ` <1342626541-29872-3-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
@ 2012-08-01 19:39       ` Jeff Layton
  0 siblings, 0 replies; 74+ messages in thread
From: Jeff Layton @ 2012-08-01 19:39 UTC (permalink / raw)
  To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA

On Wed, 18 Jul 2012 19:48:18 +0400
Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:

> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
> ---
>  fs/cifs/cifsproto.h |    4 +-
>  fs/cifs/cifssmb.c   |    8 +-
>  fs/cifs/inode.c     |  295 ++++++++++++++++++++++++++++-----------------------
>  3 files changed, 167 insertions(+), 140 deletions(-)
> 
> diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
> index 5aadeec..51fbdf2 100644
> --- a/fs/cifs/cifsproto.h
> +++ b/fs/cifs/cifsproto.h
> @@ -289,10 +289,10 @@ extern int CIFSSMBUnixSetFileInfo(const unsigned int xid,
>  				  u16 fid, u32 pid_of_opener);
>  
>  extern int CIFSSMBUnixSetPathInfo(const unsigned int xid,
> -				  struct cifs_tcon *tcon, char *file_name,
> +				  struct cifs_tcon *tcon, const char *file_name,
>  				  const struct cifs_unix_set_info_args *args,
>  				  const struct nls_table *nls_codepage,
> -				  int remap_special_chars);
> +				  int remap);
>  
>  extern int CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon,
>  			const char *newName,
> diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
> index 846b803..ed472aa 100644
> --- a/fs/cifs/cifssmb.c
> +++ b/fs/cifs/cifssmb.c
> @@ -5945,7 +5945,7 @@ CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
>  
>  int
>  CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
> -		       char *fileName,
> +		       const char *file_name,
>  		       const struct cifs_unix_set_info_args *args,
>  		       const struct nls_table *nls_codepage, int remap)
>  {
> @@ -5966,14 +5966,14 @@ setPermsRetry:
>  
>  	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
>  		name_len =
> -		    cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
> +		    cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
>  				       PATH_MAX, nls_codepage, remap);
>  		name_len++;	/* trailing null */
>  		name_len *= 2;
>  	} else {	/* BB improve the check for buffer overruns BB */
> -		name_len = strnlen(fileName, PATH_MAX);
> +		name_len = strnlen(file_name, PATH_MAX);
>  		name_len++;	/* trailing null */
> -		strncpy(pSMB->FileName, fileName, name_len);
> +		strncpy(pSMB->FileName, file_name, name_len);
>  	}
>  
>  	params = 6 + name_len;
> diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
> index 35cb6a3..e9ba1a1 100644
> --- a/fs/cifs/inode.c
> +++ b/fs/cifs/inode.c
> @@ -1219,16 +1219,165 @@ unlink_out:
>  	return rc;
>  }
>  
> +static int
> +cifs_mkdir_qinfo(struct inode *inode, struct dentry *dentry, umode_t mode,
> +		 const char *full_path, struct cifs_sb_info *cifs_sb,
> +		 struct cifs_tcon *tcon, const unsigned int xid)
> +{
> +	int rc = 0;
> +	struct inode *newinode = NULL;
> +
> +	if (tcon->unix_ext)
> +		rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb,
> +					      xid);
> +	else
> +		rc = cifs_get_inode_info(&newinode, full_path, NULL,
> +					 inode->i_sb, xid, NULL);
> +	if (rc)
> +		return rc;
> +
> +	d_instantiate(dentry, newinode);
> +	/*
> +	 * setting nlink not necessary except in cases where we failed to get it
> +	 * from the server or was set bogus
> +	 */
> +	if ((dentry->d_inode) && (dentry->d_inode->i_nlink < 2))
> +		set_nlink(dentry->d_inode, 2);
> +
> +	mode &= ~current_umask();
> +	/* must turn on setgid bit if parent dir has it */
> +	if (inode->i_mode & S_ISGID)
> +		mode |= S_ISGID;
> +
> +	if (tcon->unix_ext) {
> +		struct cifs_unix_set_info_args args = {
> +			.mode	= mode,
> +			.ctime	= NO_CHANGE_64,
> +			.atime	= NO_CHANGE_64,
> +			.mtime	= NO_CHANGE_64,
> +			.device	= 0,
> +		};
> +		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
> +			args.uid = (__u64)current_fsuid();
> +			if (inode->i_mode & S_ISGID)
> +				args.gid = (__u64)inode->i_gid;
> +			else
> +				args.gid = (__u64)current_fsgid();
> +		} else {
> +			args.uid = NO_CHANGE_64;
> +			args.gid = NO_CHANGE_64;
> +		}
> +		CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
> +				       cifs_sb->local_nls,
> +				       cifs_sb->mnt_cifs_flags &
> +				       CIFS_MOUNT_MAP_SPECIAL_CHR);
> +	} else {
> +		if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
> +		    (mode & S_IWUGO) == 0) {
> +			FILE_BASIC_INFO info;
> +			struct cifsInodeInfo *cifsInode;
> +			u32 dosattrs;
> +			int tmprc;
> +
> +			memset(&info, 0, sizeof(info));
> +			cifsInode = CIFS_I(newinode);
> +			dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
> +			info.Attributes = cpu_to_le32(dosattrs);
> +			tmprc = CIFSSMBSetPathInfo(xid, tcon, full_path, &info,
> +						   cifs_sb->local_nls,
> +						   cifs_sb->mnt_cifs_flags &
> +						   CIFS_MOUNT_MAP_SPECIAL_CHR);
> +			if (tmprc == 0)
> +				cifsInode->cifsAttrs = dosattrs;
> +		}
> +		if (dentry->d_inode) {
> +			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
> +				dentry->d_inode->i_mode = (mode | S_IFDIR);
> +
> +			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
> +				dentry->d_inode->i_uid = current_fsuid();
> +				if (inode->i_mode & S_ISGID)
> +					dentry->d_inode->i_gid = inode->i_gid;
> +				else
> +					dentry->d_inode->i_gid =
> +								current_fsgid();
> +			}
> +		}
> +	}
> +	return rc;
> +}
> +
> +static int
> +cifs_posix_mkdir(struct inode *inode, struct dentry *dentry, umode_t mode,
> +		 const char *full_path, struct cifs_sb_info *cifs_sb,
> +		 struct cifs_tcon *tcon, const unsigned int xid)
> +{
> +	int rc = 0;
> +	u32 oplock = 0;
> +	FILE_UNIX_BASIC_INFO *info = NULL;
> +	struct inode *newinode = NULL;
> +	struct cifs_fattr fattr;
> +
> +	info = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
> +	if (info == NULL) {
> +		rc = -ENOMEM;
> +		goto posix_mkdir_out;
> +	}
> +
> +	mode &= ~current_umask();
> +	rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT, mode,
> +			     NULL /* netfid */, info, &oplock, full_path,
> +			     cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
> +			     CIFS_MOUNT_MAP_SPECIAL_CHR);
> +	if (rc == -EOPNOTSUPP)
> +		goto posix_mkdir_out;
> +	else if (rc) {
> +		cFYI(1, "posix mkdir returned 0x%x", rc);
> +		d_drop(dentry);
> +		goto posix_mkdir_out;
> +	}
> +
> +	if (info->Type == cpu_to_le32(-1))
> +		/* no return info, go query for it */
> +		goto posix_mkdir_get_info;
> +	/*
> +	 * BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if
> +	 * need to set uid/gid.
> +	 */
> +
> +	cifs_unix_basic_to_fattr(&fattr, info, cifs_sb);
> +	cifs_fill_uniqueid(inode->i_sb, &fattr);
> +	newinode = cifs_iget(inode->i_sb, &fattr);
> +	if (!newinode)
> +		goto posix_mkdir_get_info;
> +
> +	d_instantiate(dentry, newinode);
> +
> +#ifdef CONFIG_CIFS_DEBUG2
> +	cFYI(1, "instantiated dentry %p %s to inode %p", dentry,
> +	     dentry->d_name.name, newinode);
> +
> +	if (newinode->i_nlink != 2)
> +		cFYI(1, "unexpected number of links %d", newinode->i_nlink);
> +#endif
> +
> +posix_mkdir_out:
> +	kfree(info);
> +	return rc;
> +posix_mkdir_get_info:
> +	rc = cifs_mkdir_qinfo(inode, dentry, mode, full_path, cifs_sb, tcon,
> +			      xid);
> +	goto posix_mkdir_out;
> +}
> +
>  int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
>  {
> -	int rc = 0, tmprc;
> +	int rc = 0;
>  	unsigned int xid;
>  	struct cifs_sb_info *cifs_sb;
>  	struct tcon_link *tlink;
>  	struct cifs_tcon *tcon;
> -	char *full_path = NULL;
> -	struct inode *newinode = NULL;
> -	struct cifs_fattr fattr;
> +	char *full_path;
>  
>  	cFYI(1, "In cifs_mkdir, mode = 0x%hx inode = 0x%p", mode, inode);
>  
> @@ -1248,145 +1397,23 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
>  
>  	if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
>  				le64_to_cpu(tcon->fsUnixInfo.Capability))) {
> -		u32 oplock = 0;
> -		FILE_UNIX_BASIC_INFO *pInfo =
> -			kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
> -		if (pInfo == NULL) {
> -			rc = -ENOMEM;
> +		rc = cifs_posix_mkdir(inode, direntry, mode, full_path, cifs_sb,
> +				      tcon, xid);
> +		if (rc != -EOPNOTSUPP)
>  			goto mkdir_out;
> -		}
> -
> -		mode &= ~current_umask();
> -		rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT,
> -				mode, NULL /* netfid */, pInfo, &oplock,
> -				full_path, cifs_sb->local_nls,
> -				cifs_sb->mnt_cifs_flags &
> -					CIFS_MOUNT_MAP_SPECIAL_CHR);
> -		if (rc == -EOPNOTSUPP) {
> -			kfree(pInfo);
> -			goto mkdir_retry_old;
> -		} else if (rc) {
> -			cFYI(1, "posix mkdir returned 0x%x", rc);
> -			d_drop(direntry);
> -		} else {
> -			if (pInfo->Type == cpu_to_le32(-1)) {
> -				/* no return info, go query for it */
> -				kfree(pInfo);
> -				goto mkdir_get_info;
> -			}
> -/*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need
> -	to set uid/gid */
> -
> -			cifs_unix_basic_to_fattr(&fattr, pInfo, cifs_sb);
> -			cifs_fill_uniqueid(inode->i_sb, &fattr);
> -			newinode = cifs_iget(inode->i_sb, &fattr);
> -			if (!newinode) {
> -				kfree(pInfo);
> -				goto mkdir_get_info;
> -			}
> -
> -			d_instantiate(direntry, newinode);
> -
> -#ifdef CONFIG_CIFS_DEBUG2
> -			cFYI(1, "instantiated dentry %p %s to inode %p",
> -				direntry, direntry->d_name.name, newinode);
> -
> -			if (newinode->i_nlink != 2)
> -				cFYI(1, "unexpected number of links %d",
> -					newinode->i_nlink);
> -#endif
> -		}
> -		kfree(pInfo);
> -		goto mkdir_out;
>  	}
> -mkdir_retry_old:
> +
>  	/* BB add setting the equivalent of mode via CreateX w/ACLs */
>  	rc = CIFSSMBMkDir(xid, tcon, full_path, cifs_sb->local_nls,
>  			  cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
>  	if (rc) {
>  		cFYI(1, "cifs_mkdir returned 0x%x", rc);
>  		d_drop(direntry);
> -	} else {
> -mkdir_get_info:
> -		if (tcon->unix_ext)
> -			rc = cifs_get_inode_info_unix(&newinode, full_path,
> -						      inode->i_sb, xid);
> -		else
> -			rc = cifs_get_inode_info(&newinode, full_path, NULL,
> -						 inode->i_sb, xid, NULL);
> -
> -		d_instantiate(direntry, newinode);
> -		 /* setting nlink not necessary except in cases where we
> -		  * failed to get it from the server or was set bogus */
> -		if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2))
> -			set_nlink(direntry->d_inode, 2);
> -
> -		mode &= ~current_umask();
> -		/* must turn on setgid bit if parent dir has it */
> -		if (inode->i_mode & S_ISGID)
> -			mode |= S_ISGID;
> -
> -		if (tcon->unix_ext) {
> -			struct cifs_unix_set_info_args args = {
> -				.mode	= mode,
> -				.ctime	= NO_CHANGE_64,
> -				.atime	= NO_CHANGE_64,
> -				.mtime	= NO_CHANGE_64,
> -				.device	= 0,
> -			};
> -			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
> -				args.uid = (__u64)current_fsuid();
> -				if (inode->i_mode & S_ISGID)
> -					args.gid = (__u64)inode->i_gid;
> -				else
> -					args.gid = (__u64)current_fsgid();
> -			} else {
> -				args.uid = NO_CHANGE_64;
> -				args.gid = NO_CHANGE_64;
> -			}
> -			CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
> -					       cifs_sb->local_nls,
> -					       cifs_sb->mnt_cifs_flags &
> -						CIFS_MOUNT_MAP_SPECIAL_CHR);
> -		} else {
> -			if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
> -			    (mode & S_IWUGO) == 0) {
> -				FILE_BASIC_INFO pInfo;
> -				struct cifsInodeInfo *cifsInode;
> -				u32 dosattrs;
> -
> -				memset(&pInfo, 0, sizeof(pInfo));
> -				cifsInode = CIFS_I(newinode);
> -				dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
> -				pInfo.Attributes = cpu_to_le32(dosattrs);
> -				tmprc = CIFSSMBSetPathInfo(xid, tcon,
> -						full_path, &pInfo,
> -						cifs_sb->local_nls,
> -						cifs_sb->mnt_cifs_flags &
> -						CIFS_MOUNT_MAP_SPECIAL_CHR);
> -				if (tmprc == 0)
> -					cifsInode->cifsAttrs = dosattrs;
> -			}
> -			if (direntry->d_inode) {
> -				if (cifs_sb->mnt_cifs_flags &
> -				     CIFS_MOUNT_DYNPERM)
> -					direntry->d_inode->i_mode =
> -						(mode | S_IFDIR);
> -
> -				if (cifs_sb->mnt_cifs_flags &
> -				     CIFS_MOUNT_SET_UID) {
> -					direntry->d_inode->i_uid =
> -						current_fsuid();
> -					if (inode->i_mode & S_ISGID)
> -						direntry->d_inode->i_gid =
> -							inode->i_gid;
> -					else
> -						direntry->d_inode->i_gid =
> -							current_fsgid();
> -				}
> -			}
> -		}
> +		goto mkdir_out;
>  	}
> +
> +	rc = cifs_mkdir_qinfo(inode, direntry, mode, full_path, cifs_sb, tcon,
> +			      xid);
>  mkdir_out:
>  	/*
>  	 * Force revalidate to get parent dir info when needed since cached

Nice cleanup...

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

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

* Re: [PATCH 03/45] CIFS: Separate protocol specific part from mkdir
       [not found]     ` <1342626541-29872-4-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
@ 2012-08-01 19:41       ` Jeff Layton
  0 siblings, 0 replies; 74+ messages in thread
From: Jeff Layton @ 2012-08-01 19:41 UTC (permalink / raw)
  To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA, Pavel Shilovsky

On Wed, 18 Jul 2012 19:48:19 +0400
Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:

> From: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
> 
> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
> ---
>  fs/cifs/cifsglob.h  |    7 +++++++
>  fs/cifs/cifsproto.h |    4 +---
>  fs/cifs/cifssmb.c   |    8 +++++---
>  fs/cifs/inode.c     |   32 +++++++++++++-------------------
>  fs/cifs/smb1ops.c   |   23 +++++++++++++++++++++++
>  5 files changed, 49 insertions(+), 25 deletions(-)
> 
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index 5695693..1ae7531 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -246,6 +246,13 @@ struct smb_version_operations {
>  	bool (*can_echo)(struct TCP_Server_Info *);
>  	/* send echo request */
>  	int (*echo)(struct TCP_Server_Info *);
> +	/* create directory */
> +	int (*mkdir)(const unsigned int, struct cifs_tcon *, const char *,
> +		     struct cifs_sb_info *);
> +	/* set info on created directory */
> +	void (*mkdir_setinfo)(struct inode *, const char *,
> +			      struct cifs_sb_info *, struct cifs_tcon *,
> +			      const unsigned int);

Do we really need a "mkdir_setinfo"? Why not just a "set inode info by
path" op that would be a little more general purpose?

>  };
>  
>  struct smb_version_values {
> diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
> index 51fbdf2..7e02362 100644
> --- a/fs/cifs/cifsproto.h
> +++ b/fs/cifs/cifsproto.h
> @@ -295,9 +295,7 @@ extern int CIFSSMBUnixSetPathInfo(const unsigned int xid,
>  				  int remap);
>  
>  extern int CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon,
> -			const char *newName,
> -			const struct nls_table *nls_codepage,
> -			int remap_special_chars);
> +			const char *name, struct cifs_sb_info *cifs_sb);
>  extern int CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon,
>  			const char *name, const struct nls_table *nls_codepage,
>  			int remap_special_chars);
> diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
> index ed472aa..d49eedf 100644
> --- a/fs/cifs/cifssmb.c
> +++ b/fs/cifs/cifssmb.c
> @@ -992,14 +992,15 @@ RmDirRetry:
>  }
>  
>  int
> -CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon,
> -	     const char *name, const struct nls_table *nls_codepage, int remap)
> +CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
> +	     struct cifs_sb_info *cifs_sb)
>  {
>  	int rc = 0;
>  	CREATE_DIRECTORY_REQ *pSMB = NULL;
>  	CREATE_DIRECTORY_RSP *pSMBr = NULL;
>  	int bytes_returned;
>  	int name_len;
> +	int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
>  
>  	cFYI(1, "In CIFSSMBMkDir");
>  MkDirRetry:
> @@ -1010,7 +1011,8 @@ MkDirRetry:
>  
>  	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
>  		name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
> -					      PATH_MAX, nls_codepage, remap);
> +					      PATH_MAX, cifs_sb->local_nls,
> +					      remap);
>  		name_len++;	/* trailing null */
>  		name_len *= 2;
>  	} else {		/* BB improve check for buffer overruns BB */
> diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
> index e9ba1a1..d7e74b1 100644
> --- a/fs/cifs/inode.c
> +++ b/fs/cifs/inode.c
> @@ -1272,24 +1272,11 @@ cifs_mkdir_qinfo(struct inode *inode, struct dentry *dentry, umode_t mode,
>  				       cifs_sb->mnt_cifs_flags &
>  				       CIFS_MOUNT_MAP_SPECIAL_CHR);
>  	} else {
> +		struct TCP_Server_Info *server = tcon->ses->server;
>  		if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
> -		    (mode & S_IWUGO) == 0) {
> -			FILE_BASIC_INFO info;
> -			struct cifsInodeInfo *cifsInode;
> -			u32 dosattrs;
> -			int tmprc;
> -
> -			memset(&info, 0, sizeof(info));
> -			cifsInode = CIFS_I(newinode);
> -			dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
> -			info.Attributes = cpu_to_le32(dosattrs);
> -			tmprc = CIFSSMBSetPathInfo(xid, tcon, full_path, &info,
> -						   cifs_sb->local_nls,
> -						   cifs_sb->mnt_cifs_flags &
> -						   CIFS_MOUNT_MAP_SPECIAL_CHR);
> -			if (tmprc == 0)
> -				cifsInode->cifsAttrs = dosattrs;
> -		}
> +		    (mode & S_IWUGO) == 0 && server->ops->mkdir_setinfo)
> +			server->ops->mkdir_setinfo(newinode, full_path, cifs_sb,
> +						   tcon, xid);
>  		if (dentry->d_inode) {
>  			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
>  				dentry->d_inode->i_mode = (mode | S_IFDIR);
> @@ -1377,6 +1364,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
>  	struct cifs_sb_info *cifs_sb;
>  	struct tcon_link *tlink;
>  	struct cifs_tcon *tcon;
> +	struct TCP_Server_Info *server;
>  	char *full_path;
>  
>  	cFYI(1, "In cifs_mkdir, mode = 0x%hx inode = 0x%p", mode, inode);
> @@ -1403,9 +1391,15 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
>  			goto mkdir_out;
>  	}
>  
> +	server = tcon->ses->server;
> +
> +	if (!server->ops->mkdir) {
> +		rc = -ENOSYS;
> +		goto mkdir_out;
> +	}
> +
>  	/* BB add setting the equivalent of mode via CreateX w/ACLs */
> -	rc = CIFSSMBMkDir(xid, tcon, full_path, cifs_sb->local_nls,
> -			  cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
> +	rc = server->ops->mkdir(xid, tcon, full_path, cifs_sb);
>  	if (rc) {
>  		cFYI(1, "cifs_mkdir returned 0x%x", rc);
>  		d_drop(direntry);
> diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
> index c40356d..861e2df 100644
> --- a/fs/cifs/smb1ops.c
> +++ b/fs/cifs/smb1ops.c
> @@ -586,6 +586,27 @@ cifs_print_stats(struct seq_file *m, struct cifs_tcon *tcon)
>  #endif
>  }
>  
> +static void
> +cifs_mkdir_setinfo(struct inode *inode, const char *full_path,
> +		   struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon,
> +		   const unsigned int xid)
> +{
> +	FILE_BASIC_INFO info;
> +	struct cifsInodeInfo *cifsInode;
> +	u32 dosattrs;
> +	int rc;
> +
> +	memset(&info, 0, sizeof(info));
> +	cifsInode = CIFS_I(inode);
> +	dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
> +	info.Attributes = cpu_to_le32(dosattrs);
> +	rc = CIFSSMBSetPathInfo(xid, tcon, full_path, &info, cifs_sb->local_nls,
> +				cifs_sb->mnt_cifs_flags &
> +						CIFS_MOUNT_MAP_SPECIAL_CHR);
> +	if (rc == 0)
> +		cifsInode->cifsAttrs = dosattrs;
> +}
> +
>  struct smb_version_operations smb1_operations = {
>  	.send_cancel = send_nt_cancel,
>  	.compare_fids = cifs_compare_fids,
> @@ -620,6 +641,8 @@ struct smb_version_operations smb1_operations = {
>  	.get_srv_inum = cifs_get_srv_inum,
>  	.build_path_to_root = cifs_build_path_to_root,
>  	.echo = CIFSSMBEcho,
> +	.mkdir = CIFSSMBMkDir,
> +	.mkdir_setinfo = cifs_mkdir_setinfo,
>  };
>  
>  struct smb_version_values smb1_values = {

That can be done in a later patch though...

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

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

* Re: [PATCH 04/45] CIFS: Add SMB2 support for mkdir operation
       [not found]     ` <1342626541-29872-5-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
@ 2012-08-01 19:42       ` Jeff Layton
  0 siblings, 0 replies; 74+ messages in thread
From: Jeff Layton @ 2012-08-01 19:42 UTC (permalink / raw)
  To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA, Pavel Shilovsky

On Wed, 18 Jul 2012 19:48:20 +0400
Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:

> From: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> 
> Signed-off-by: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> ---
>  fs/cifs/smb2inode.c |   30 ++++++++++++++++++++++++++++++
>  fs/cifs/smb2ops.c   |    2 ++
>  fs/cifs/smb2proto.h |    6 ++++++
>  3 files changed, 38 insertions(+), 0 deletions(-)
> 
> diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
> index 1ba5c40..e129527 100644
> --- a/fs/cifs/smb2inode.c
> +++ b/fs/cifs/smb2inode.c
> @@ -122,3 +122,33 @@ out:
>  	kfree(smb2_data);
>  	return rc;
>  }
> +
> +int
> +smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
> +	   struct cifs_sb_info *cifs_sb)
> +{
> +	return smb2_open_op_close(xid, tcon, cifs_sb, name,
> +				  FILE_WRITE_ATTRIBUTES, FILE_CREATE, 0,
> +				  CREATE_NOT_FILE, NULL, SMB2_OP_MKDIR);
> +}
> +
> +void
> +smb2_mkdir_setinfo(struct inode *inode, const char *name,
> +		   struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon,
> +		   const unsigned int xid)
> +{
> +	FILE_BASIC_INFO data;
> +	struct cifsInodeInfo *cifs_i;
> +	u32 dosattrs;
> +	int tmprc;
> +
> +	memset(&data, 0, sizeof(data));
> +	cifs_i = CIFS_I(inode);
> +	dosattrs = cifs_i->cifsAttrs | ATTR_READONLY;
> +	data.Attributes = cpu_to_le32(dosattrs);
> +	tmprc = smb2_open_op_close(xid, tcon, cifs_sb, name,
> +				   FILE_WRITE_ATTRIBUTES, FILE_CREATE, 0,
> +				   CREATE_NOT_FILE, &data, SMB2_OP_SET_INFO);
> +	if (tmprc == 0)
> +		cifs_i->cifsAttrs = dosattrs;
> +}
> diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
> index 410cf92..cc74871 100644
> --- a/fs/cifs/smb2ops.c
> +++ b/fs/cifs/smb2ops.c
> @@ -318,6 +318,8 @@ struct smb_version_operations smb21_operations = {
>  	.query_path_info = smb2_query_path_info,
>  	.get_srv_inum = smb2_get_srv_inum,
>  	.build_path_to_root = smb2_build_path_to_root,
> +	.mkdir = smb2_mkdir,
> +	.mkdir_setinfo = smb2_mkdir_setinfo,
>  };
>  
>  struct smb_version_values smb21_values = {
> diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
> index 902bbe2..f992508 100644
> --- a/fs/cifs/smb2proto.h
> +++ b/fs/cifs/smb2proto.h
> @@ -52,6 +52,12 @@ extern int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
>  				struct cifs_sb_info *cifs_sb,
>  				const char *full_path, FILE_ALL_INFO *data,
>  				bool *adjust_tz);
> +extern int smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon,
> +		      const char *name, struct cifs_sb_info *cifs_sb);
> +extern void smb2_mkdir_setinfo(struct inode *inode, const char *full_path,
> +			       struct cifs_sb_info *cifs_sb,
> +			       struct cifs_tcon *tcon, const unsigned int xid);
> +
>  /*
>   * SMB2 Worker functions - most of protocol specific implementation details
>   * are contained within these calls.

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

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

* Re: [PATCH 05/45] CIFS: Move rmdir code to ops struct
       [not found]     ` <1342626541-29872-6-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
@ 2012-08-01 19:45       ` Jeff Layton
  0 siblings, 0 replies; 74+ messages in thread
From: Jeff Layton @ 2012-08-01 19:45 UTC (permalink / raw)
  To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA

On Wed, 18 Jul 2012 19:48:21 +0400
Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:

> Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
> ---
>  fs/cifs/cifsglob.h  |    3 +++
>  fs/cifs/cifsproto.h |    3 +--
>  fs/cifs/cifssmb.c   |   15 ++++++++-------
>  fs/cifs/inode.c     |   15 +++++++++++----
>  fs/cifs/smb1ops.c   |    1 +
>  5 files changed, 24 insertions(+), 13 deletions(-)
> 
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index 1ae7531..a5b4e82 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -253,6 +253,9 @@ struct smb_version_operations {
>  	void (*mkdir_setinfo)(struct inode *, const char *,
>  			      struct cifs_sb_info *, struct cifs_tcon *,
>  			      const unsigned int);
> +	/* remove directory */
> +	int (*rmdir)(const unsigned int, struct cifs_tcon *, const char *,
> +		     struct cifs_sb_info *);
>  };
>  
>  struct smb_version_values {
> diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
> index 7e02362..43784ee 100644
> --- a/fs/cifs/cifsproto.h
> +++ b/fs/cifs/cifsproto.h
> @@ -297,8 +297,7 @@ extern int CIFSSMBUnixSetPathInfo(const unsigned int xid,
>  extern int CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon,
>  			const char *name, struct cifs_sb_info *cifs_sb);
>  extern int CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon,
> -			const char *name, const struct nls_table *nls_codepage,
> -			int remap_special_chars);
> +			const char *name, struct cifs_sb_info *cifs_sb);
>  extern int CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
>  			const char *name, __u16 type,
>  			const struct nls_table *nls_codepage,
> diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
> index d49eedf..9fb21cd 100644
> --- a/fs/cifs/cifssmb.c
> +++ b/fs/cifs/cifssmb.c
> @@ -948,15 +948,15 @@ DelFileRetry:
>  }
>  
>  int
> -CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon,
> -	     const char *dirName, const struct nls_table *nls_codepage,
> -	     int remap)
> +CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
> +	     struct cifs_sb_info *cifs_sb)

This is a very good change. One of the things we've had requested for
quite some time is a "remote_nls=" mount option, where people could set
the codepage that the server uses for non-unicode (ancient) servers
instead of just assuming unicode. To do that though, you need to pass
in a remote codepage to these functions too.

As you go, replacing the remap/nls_codepage combo with a cifs_sb might
make that change more possible in the future.

>  {
>  	DELETE_DIRECTORY_REQ *pSMB = NULL;
>  	DELETE_DIRECTORY_RSP *pSMBr = NULL;
>  	int rc = 0;
>  	int bytes_returned;
>  	int name_len;
> +	int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
>  
>  	cFYI(1, "In CIFSSMBRmDir");
>  RmDirRetry:
> @@ -966,14 +966,15 @@ RmDirRetry:
>  		return rc;
>  
>  	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
> -		name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, dirName,
> -					      PATH_MAX, nls_codepage, remap);
> +		name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
> +					      PATH_MAX, cifs_sb->local_nls,
> +					      remap);
>  		name_len++;	/* trailing null */
>  		name_len *= 2;
>  	} else {		/* BB improve check for buffer overruns BB */
> -		name_len = strnlen(dirName, PATH_MAX);
> +		name_len = strnlen(name, PATH_MAX);
>  		name_len++;	/* trailing null */
> -		strncpy(pSMB->DirName, dirName, name_len);
> +		strncpy(pSMB->DirName, name, name_len);
>  	}
>  
>  	pSMB->BufferFormat = 0x04;
> diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
> index d7e74b1..7354877 100644
> --- a/fs/cifs/inode.c
> +++ b/fs/cifs/inode.c
> @@ -1426,7 +1426,8 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
>  	unsigned int xid;
>  	struct cifs_sb_info *cifs_sb;
>  	struct tcon_link *tlink;
> -	struct cifs_tcon *pTcon;
> +	struct cifs_tcon *tcon;
> +	struct TCP_Server_Info *server;
>  	char *full_path = NULL;
>  	struct cifsInodeInfo *cifsInode;
>  
> @@ -1446,10 +1447,16 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
>  		rc = PTR_ERR(tlink);
>  		goto rmdir_exit;
>  	}
> -	pTcon = tlink_tcon(tlink);
> +	tcon = tlink_tcon(tlink);
> +	server = tcon->ses->server;
> +
> +	if (!server->ops->rmdir) {
> +		rc = -ENOSYS;
> +		cifs_put_tlink(tlink);
> +		goto rmdir_exit;
> +	}
>  
> -	rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls,
> -			  cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
> +	rc = server->ops->rmdir(xid, tcon, full_path, cifs_sb);
>  	cifs_put_tlink(tlink);
>  
>  	if (!rc) {
> diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
> index 861e2df..3129ac7 100644
> --- a/fs/cifs/smb1ops.c
> +++ b/fs/cifs/smb1ops.c
> @@ -643,6 +643,7 @@ struct smb_version_operations smb1_operations = {
>  	.echo = CIFSSMBEcho,
>  	.mkdir = CIFSSMBMkDir,
>  	.mkdir_setinfo = cifs_mkdir_setinfo,
> +	.rmdir = CIFSSMBRmDir,
>  };
>  
>  struct smb_version_values smb1_values = {

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

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

* Re: [PATCH 06/45] CIFS: Add SMB2 support for rmdir
       [not found]     ` <1342626541-29872-7-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
@ 2012-08-01 19:47       ` Jeff Layton
  0 siblings, 0 replies; 74+ messages in thread
From: Jeff Layton @ 2012-08-01 19:47 UTC (permalink / raw)
  To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA

On Wed, 18 Jul 2012 19:48:22 +0400
Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:

> Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
> ---
>  fs/cifs/smb2inode.c |    9 +++++++++
>  fs/cifs/smb2ops.c   |    1 +
>  fs/cifs/smb2proto.h |    2 ++
>  3 files changed, 12 insertions(+), 0 deletions(-)
> 
> diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
> index e129527..2aa5cb0 100644
> --- a/fs/cifs/smb2inode.c
> +++ b/fs/cifs/smb2inode.c
> @@ -152,3 +152,12 @@ smb2_mkdir_setinfo(struct inode *inode, const char *name,
>  	if (tmprc == 0)
>  		cifs_i->cifsAttrs = dosattrs;
>  }
> +
> +int
> +smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
> +	   struct cifs_sb_info *cifs_sb)
> +{
> +	return smb2_open_op_close(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
> +				  0, CREATE_NOT_FILE | CREATE_DELETE_ON_CLOSE,
> +				  NULL, SMB2_OP_DELETE);
> +}
> diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
> index cc74871..826209b 100644
> --- a/fs/cifs/smb2ops.c
> +++ b/fs/cifs/smb2ops.c
> @@ -320,6 +320,7 @@ struct smb_version_operations smb21_operations = {
>  	.build_path_to_root = smb2_build_path_to_root,
>  	.mkdir = smb2_mkdir,
>  	.mkdir_setinfo = smb2_mkdir_setinfo,
> +	.rmdir = smb2_rmdir,
>  };
>  
>  struct smb_version_values smb21_values = {
> diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
> index f992508..bfaa7b1 100644
> --- a/fs/cifs/smb2proto.h
> +++ b/fs/cifs/smb2proto.h
> @@ -57,6 +57,8 @@ extern int smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon,
>  extern void smb2_mkdir_setinfo(struct inode *inode, const char *full_path,
>  			       struct cifs_sb_info *cifs_sb,
>  			       struct cifs_tcon *tcon, const unsigned int xid);
> +extern int smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon,
> +		      const char *name, struct cifs_sb_info *cifs_sb);
>  
>  /*
>   * SMB2 Worker functions - most of protocol specific implementation details

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

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

* Re: [PATCH 00/45] SMB2 base operation support
       [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
                     ` (44 preceding siblings ...)
  2012-07-18 15:49   ` [PATCH 45/45] CIFS: Add statfs support for SMB2 Pavel Shilovsky
@ 2012-08-03 15:14   ` Steve French
  45 siblings, 0 replies; 74+ messages in thread
From: Steve French @ 2012-08-03 15:14 UTC (permalink / raw)
  To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Now that I have also had a chance to rereview the remainder of the
series, and retest these. I merged the last part of Pavel's "smb2
basic" support into cifs-2.6.git for-next (the first part of the
series below is already upstream, as is the earlier smb2 transport
enablement and cifs common code restructuring).  Even though it tests
ok I plan to leave the SMB2 support as CONFIG_BROKEN until after the
testing at the annual Storage Developer Conference (SMB2 Plugfest)
next month, unless I get more test feedback.

Other near term items:
Jeff noted that we need to merge the patch for default security
mechanism upgrade for cifs, and Jeff has a series of 5 socket handling
patches that Pavel found a problem with (that presumably is a bug in
Windows not in the Linux kernel client - but need to investigate
more). In addition for SMB2 there are also three sparse warnings in
Pavel's code that I want to eliminate.

On Wed, Jul 18, 2012 at 10:48 AM, Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:
> This patchset is the second part of big SMB2 merge (after smb2-mount). It adds SMB2 support for
> file and inode operation as well as rewrites existing part of their code to make it use ops
> server struct of protocol specific callbacks.
>
> The patchset is tested by cthon tests: basic and general parts.
>
> Pavel Shilovsky (45):
>   CIFS: Make CAP_* checks protocol independent
>   CIFS: Simpliify cifs_mkdir call
>   CIFS: Separate protocol specific part from mkdir
>   CIFS: Add SMB2 support for mkdir operation
>   CIFS: Move rmdir code to ops struct
>   CIFS: Add SMB2 support for rmdir
>   CIFS: Protect i_nlink from being negative
>   CIFS: Move unlink code to ops struct
>   CIFS: Add SMB2 support for unlink
>   CIFS: Replace netfid with cifs_fid struct in cifsFileInfo
>   CIFS: Move open code to ops struct
>   CIFS: Move close code to ops struct
>   CIFS: Add open/close file support for SMB2
>   CIFS: Move guery file info code to ops struct
>   CIFS: Add SMB2 support for query_file_info
>   CIFS: Move create code use ops struct
>   CIFS: Move reopen code to ops struct
>   CIFS: Make flush code use ops struct
>   CIFS: Add SMB2 support for flush
>   CIFS: Move r/wsize negotiating to ops struct
>   CIFS: Add SMB2 r/wsize negotiating
>   CIFS: Move async read to ops struct
>   CIFS: Add SMB2 support for cifs_iovec_read
>   CIFS: Move async write to ops struct
>   CIFS: Add SMB2 support for cifs_iovec_write
>   CIFS: Move readpage code to ops struct
>   CIFS: Add readpage support for SMB2
>   CIFS: Move writepage to ops struct
>   CIFS: Add writepage support for SMB2
>   CIFS: Enable signing in SMB2
>   CIFS: Move rename to ops struct
>   CIFS: Add SMB2 support for rename operation
>   CIFS: Move hardlink to ops struct
>   CIFS: Add SMB2 support for hardlink operation
>   CIFS: Move set_file_size to ops struct
>   CIFS: Add SMB2 support for set_file_size
>   CIFS: Move set_file_info to ops struct
>   CIFS: Add set_file_info support for SMB2
>   CIFS: Move readdir code to ops struct
>   CIFS: Add readdir support for SMB2
>   CIFS: Process oplocks for SMB2
>   CIFS: Move oplock break to ops struct
>   CIFS: Add oplock break support for SMB2
>   CIFS: Move statfs to ops struct
>   CIFS: Add statfs support for SMB2
>
>  fs/cifs/Kconfig         |    1 +
>  fs/cifs/Makefile        |    2 +-
>  fs/cifs/cifsacl.c       |    2 +-
>  fs/cifs/cifsencrypt.c   |   30 ++-
>  fs/cifs/cifsfs.c        |   31 +--
>  fs/cifs/cifsglob.h      |  241 ++++++++++++-
>  fs/cifs/cifsproto.h     |   96 ++----
>  fs/cifs/cifssmb.c       |  171 ++++-----
>  fs/cifs/connect.c       |  154 +-------
>  fs/cifs/dir.c           |  108 +++---
>  fs/cifs/file.c          |  473 +++++++++++++-----------
>  fs/cifs/inode.c         |  652 ++++++++++++++++----------------
>  fs/cifs/ioctl.c         |   13 +-
>  fs/cifs/link.c          |   80 +++--
>  fs/cifs/misc.c          |    2 +-
>  fs/cifs/netmisc.c       |    3 +-
>  fs/cifs/readdir.c       |  179 +++++----
>  fs/cifs/smb1ops.c       |  351 +++++++++++++++++-
>  fs/cifs/smb2file.c      |  106 ++++++
>  fs/cifs/smb2glob.h      |   14 +
>  fs/cifs/smb2inode.c     |  137 +++++++-
>  fs/cifs/smb2maperror.c  |    3 +-
>  fs/cifs/smb2misc.c      |   86 ++++-
>  fs/cifs/smb2ops.c       |  267 +++++++++++++-
>  fs/cifs/smb2pdu.c       |  957 ++++++++++++++++++++++++++++++++++++++++++++++-
>  fs/cifs/smb2pdu.h       |  178 +++++++++
>  fs/cifs/smb2proto.h     |   71 ++++-
>  fs/cifs/smb2transport.c |  157 ++++++++-
>  fs/cifs/transport.c     |   24 +-
>  29 files changed, 3499 insertions(+), 1090 deletions(-)
>  create mode 100644 fs/cifs/smb2file.c
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html



-- 
Thanks,

Steve

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

* Re: [PATCH 30/45] CIFS: Enable signing in SMB2
       [not found]     ` <1342626541-29872-31-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
@ 2012-08-21  7:35       ` Stefan Metzmacher
  2012-08-21 14:01         ` Pavel Shilovsky
  2012-08-21 14:58         ` Shirish Pargaonkar
  0 siblings, 2 replies; 74+ messages in thread
From: Stefan Metzmacher @ 2012-08-21  7:35 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Hi Pavel,

> Use hmac-sha256 and rather than hmac-md5 that is used for CIFS/SMB.
> 
> Signature field in SMB2 header is 16 bytes instead of 8 bytes.

Sorry for the late reply, I just found a reference to this patch...

To me it seems that this patch doesn't take care of the fact that
the signing key in SMB2/3 belongs to the session and not to the transport
connection.

Does the SMB2 code support multiuser mounts yet?

Why are you using some "BSRSPYL " magic? I only saw that from Windows
clients
using SMB1. (Note: that servers just echo the signature from the
request, if they don't do signing).

metze

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

* Re: [PATCH 30/45] CIFS: Enable signing in SMB2
  2012-08-21  7:35       ` Stefan Metzmacher
@ 2012-08-21 14:01         ` Pavel Shilovsky
  2012-08-21 14:58         ` Shirish Pargaonkar
  1 sibling, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-08-21 14:01 UTC (permalink / raw)
  To: Stefan Metzmacher; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA, Shirish Pargaonkar

2012/8/21 Stefan Metzmacher <metze-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>:
> Hi Pavel,
>
>> Use hmac-sha256 and rather than hmac-md5 that is used for CIFS/SMB.
>>
>> Signature field in SMB2 header is 16 bytes instead of 8 bytes.
>
> Sorry for the late reply, I just found a reference to this patch...

No problem, thank you for your comments.

>
> To me it seems that this patch doesn't take care of the fact that
> the signing key in SMB2/3 belongs to the session and not to the transport
> connection.

Yes, you are right. Thanks to this point. I think we can fix this later.

>
> Does the SMB2 code support multiuser mounts yet?

No, SMB2 code doesn't support Kerberos auth and multiuser mounts yet.

>
> Why are you using some "BSRSPYL " magic? I only saw that from Windows
> clients
> using SMB1. (Note: that servers just echo the signature from the
> request, if they don't do signing).
>

(CC'ing Shirish, as the original author of the patch.)

-- 
Best regards,
Pavel Shilovsky.

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

* Re: [PATCH 30/45] CIFS: Enable signing in SMB2
  2012-08-21  7:35       ` Stefan Metzmacher
  2012-08-21 14:01         ` Pavel Shilovsky
@ 2012-08-21 14:58         ` Shirish Pargaonkar
       [not found]           ` <CADT32e+4DSN=CSCbL+8GoRePknpD3X0HSq1hjVsXf3KHXQcmTw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  1 sibling, 1 reply; 74+ messages in thread
From: Shirish Pargaonkar @ 2012-08-21 14:58 UTC (permalink / raw)
  To: Stefan Metzmacher; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA

On Tue, Aug 21, 2012 at 2:35 AM, Stefan Metzmacher <metze-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:
> Hi Pavel,
>
>> Use hmac-sha256 and rather than hmac-md5 that is used for CIFS/SMB.
>>
>> Signature field in SMB2 header is 16 bytes instead of 8 bytes.
>
> Sorry for the late reply, I just found a reference to this patch...
>
> To me it seems that this patch doesn't take care of the fact that
> the signing key in SMB2/3 belongs to the session and not to the transport
> connection.

metze, where do you see that?  This is the signing key that is used to generate
signature, server->session_key.response.

>
> Does the SMB2 code support multiuser mounts yet?
>
> Why are you using some "BSRSPYL " magic? I only saw that from Windows
> clients
> using SMB1. (Note: that servers just echo the signature from the
> request, if they don't do signing).

IIRC, Jeff Layton added that code to encode BSRSPYL magic (string).
I could be wrong, it has been a while.
But, I do think this is a problem, signature in a smb message is not even
checked till key exchange handshake is session setup is done, right?

>
> metze
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 30/45] CIFS: Enable signing in SMB2
       [not found]           ` <CADT32e+4DSN=CSCbL+8GoRePknpD3X0HSq1hjVsXf3KHXQcmTw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2012-08-22 13:46             ` Stefan (metze) Metzmacher
       [not found]               ` <5034E29E.7030006-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
  0 siblings, 1 reply; 74+ messages in thread
From: Stefan (metze) Metzmacher @ 2012-08-22 13:46 UTC (permalink / raw)
  To: Shirish Pargaonkar; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 1611 bytes --]

Hi Shirish,

> On Tue, Aug 21, 2012 at 2:35 AM, Stefan Metzmacher <metze-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:
>> Hi Pavel,
>>
>>> Use hmac-sha256 and rather than hmac-md5 that is used for CIFS/SMB.
>>>
>>> Signature field in SMB2 header is 16 bytes instead of 8 bytes.
>>
>> Sorry for the late reply, I just found a reference to this patch...
>>
>> To me it seems that this patch doesn't take care of the fact that
>> the signing key in SMB2/3 belongs to the session and not to the transport
>> connection.
> 
> metze, where do you see that?  This is the signing key that is used to generate
> signature, server->session_key.response.

And 'server' is a per connection state not per session...
which is ok for smb1 but not for smb2.

>> Does the SMB2 code support multiuser mounts yet?
>>
>> Why are you using some "BSRSPYL " magic? I only saw that from Windows
>> clients
>> using SMB1. (Note: that servers just echo the signature from the
>> request, if they don't do signing).
> 
> IIRC, Jeff Layton added that code to encode BSRSPYL magic (string).
> I could be wrong, it has been a while.
> But, I do think this is a problem, signature in a smb message is not even
> checked till key exchange handshake is session setup is done, right?

A session setup response with STATUS_SUCCESS is the first signed message.
Before that the server just echos what the client sends.

For SMB1 windows client (and smbclient) send BSRSPYL if they would like to
turn on signing later. But for SMB2 windows and samba send just zeros,
which cifs.ko should also do.

metze


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 262 bytes --]

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

* Re: [PATCH 08/45] CIFS: Move unlink code to ops struct
       [not found]     ` <1342626541-29872-9-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
@ 2012-09-12 19:48       ` Jeff Layton
       [not found]         ` <20120912154804.19b97830-4QP7MXygkU+dMjc06nkz3ljfA9RmPOcC@public.gmane.org>
  0 siblings, 1 reply; 74+ messages in thread
From: Jeff Layton @ 2012-09-12 19:48 UTC (permalink / raw)
  To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA

On Wed, 18 Jul 2012 19:48:24 +0400
Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:

> Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
> ---
>  fs/cifs/cifsglob.h  |    6 ++++++
>  fs/cifs/cifsproto.h |    9 ++++++---
>  fs/cifs/cifssmb.c   |   16 ++++++++--------
>  fs/cifs/inode.c     |   32 +++++++++++++++++++++-----------
>  fs/cifs/smb1ops.c   |    2 ++
>  5 files changed, 43 insertions(+), 22 deletions(-)
> 
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index a5b4e82..bd53d97 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -256,6 +256,12 @@ struct smb_version_operations {
>  	/* remove directory */
>  	int (*rmdir)(const unsigned int, struct cifs_tcon *, const char *,
>  		     struct cifs_sb_info *);
> +	/* unlink file */
> +	int (*unlink)(const unsigned int, struct cifs_tcon *, const char *,
> +		      struct cifs_sb_info *);
> +	/* open, rename and delete file */
> +	int (*rename_pending_delete)(const char *, struct dentry *,
> +				     const unsigned int);
>  };
>  
>  struct smb_version_values {
> diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
> index 43784ee..e9349af 100644
> --- a/fs/cifs/cifsproto.h
> +++ b/fs/cifs/cifsproto.h
> @@ -144,6 +144,11 @@ extern int cifs_get_file_info_unix(struct file *filp);
>  extern int cifs_get_inode_info_unix(struct inode **pinode,
>  			const unsigned char *search_path,
>  			struct super_block *sb, unsigned int xid);
> +extern int cifs_set_file_info(struct inode *inode, struct iattr *attrs,
> +			      unsigned int xid, char *full_path, __u32 dosattr);
> +extern int cifs_rename_pending_delete(const char *full_path,
> +				      struct dentry *dentry,
> +				      const unsigned int xid);
>  extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb,
>  			      struct cifs_fattr *fattr, struct inode *inode,
>  			      const char *path, const __u16 *pfid);
> @@ -303,9 +308,7 @@ extern int CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
>  			const struct nls_table *nls_codepage,
>  			int remap_special_chars);
>  extern int CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon,
> -			const char *name,
> -			const struct nls_table *nls_codepage,
> -			int remap_special_chars);
> +			  const char *name, struct cifs_sb_info *cifs_sb);
>  extern int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
>  			const char *fromName, const char *toName,
>  			const struct nls_table *nls_codepage,
> diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
> index 9fb21cd..395f3e2 100644
> --- a/fs/cifs/cifssmb.c
> +++ b/fs/cifs/cifssmb.c
> @@ -902,15 +902,15 @@ PsxDelete:
>  }
>  
>  int
> -CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon,
> -	       const char *fileName, const struct nls_table *nls_codepage,
> -	       int remap)
> +CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
> +	       struct cifs_sb_info *cifs_sb)
>  {
>  	DELETE_FILE_REQ *pSMB = NULL;
>  	DELETE_FILE_RSP *pSMBr = NULL;
>  	int rc = 0;
>  	int bytes_returned;
>  	int name_len;
> +	int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
>  
>  DelFileRetry:
>  	rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
> @@ -919,15 +919,15 @@ DelFileRetry:
>  		return rc;
>  
>  	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
> -		name_len =
> -		    cifsConvertToUTF16((__le16 *) pSMB->fileName, fileName,
> -				       PATH_MAX, nls_codepage, remap);
> +		name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
> +					      PATH_MAX, cifs_sb->local_nls,
> +					      remap);
>  		name_len++;	/* trailing null */
>  		name_len *= 2;
>  	} else {		/* BB improve check for buffer overruns BB */
> -		name_len = strnlen(fileName, PATH_MAX);
> +		name_len = strnlen(name, PATH_MAX);
>  		name_len++;	/* trailing null */
> -		strncpy(pSMB->fileName, fileName, name_len);
> +		strncpy(pSMB->fileName, name, name_len);
>  	}
>  	pSMB->SearchAttributes =
>  	    cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
> diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
> index 88afb1a..9685eb1 100644
> --- a/fs/cifs/inode.c
> +++ b/fs/cifs/inode.c
> @@ -878,9 +878,9 @@ out:
>  	return inode;
>  }
>  
> -static int
> +int
>  cifs_set_file_info(struct inode *inode, struct iattr *attrs, unsigned int xid,
> -		    char *full_path, __u32 dosattr)
> +		   char *full_path, __u32 dosattr)
>  {
>  	int rc;
>  	int oplock = 0;
> @@ -995,13 +995,13 @@ out:
>  }
>  
>  /*
> - * open the given file (if it isn't already), set the DELETE_ON_CLOSE bit
> + * Open the given file (if it isn't already), set the DELETE_ON_CLOSE bit
>   * and rename it to a random name that hopefully won't conflict with
>   * anything else.
>   */
> -static int
> -cifs_rename_pending_delete(char *full_path, struct dentry *dentry,
> -			   unsigned int xid)
> +int
> +cifs_rename_pending_delete(const char *full_path, struct dentry *dentry,
> +			   const unsigned int xid)
>  {
>  	int oplock = 0;
>  	int rc;
> @@ -1138,6 +1138,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
>  	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
>  	struct tcon_link *tlink;
>  	struct cifs_tcon *tcon;
> +	struct TCP_Server_Info *server;
>  	struct iattr *attrs = NULL;
>  	__u32 dosattr = 0, origattr = 0;
>  
> @@ -1147,6 +1148,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
>  	if (IS_ERR(tlink))
>  		return PTR_ERR(tlink);
>  	tcon = tlink_tcon(tlink);
> +	server = tcon->ses->server;
>  
>  	xid = get_xid();
>  
> @@ -1169,8 +1171,12 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
>  	}
>  
>  retry_std_delete:
> -	rc = CIFSSMBDelFile(xid, tcon, full_path, cifs_sb->local_nls,
> -			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
> +	if (!server->ops->unlink) {
> +		rc = -ENOSYS;
> +		goto psx_del_no_retry;
> +	}
> +
> +	rc = server->ops->unlink(xid, tcon, full_path, cifs_sb);
>  
>  psx_del_no_retry:
>  	if (!rc) {
> @@ -1179,9 +1185,13 @@ psx_del_no_retry:
>  	} else if (rc == -ENOENT) {
>  		d_drop(dentry);
>  	} else if (rc == -ETXTBSY) {
> -		rc = cifs_rename_pending_delete(full_path, dentry, xid);
> -		if (rc == 0)
> -			cifs_drop_nlink(inode);
> +		if (server->ops->rename_pending_delete) {
> +			rc = server->ops->rename_pending_delete(full_path,
> +								dentry, xid);
> +			if (rc == 0)
> +				cifs_drop_nlink(inode);
> +		} else
> +			rc = -ENOSYS;
>  	} else if ((rc == -EACCES) && (dosattr == 0) && inode) {
>  		attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
>  		if (attrs == NULL) {
> diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
> index 3129ac7..725fa61 100644
> --- a/fs/cifs/smb1ops.c
> +++ b/fs/cifs/smb1ops.c
> @@ -644,6 +644,8 @@ struct smb_version_operations smb1_operations = {
>  	.mkdir = CIFSSMBMkDir,
>  	.mkdir_setinfo = cifs_mkdir_setinfo,
>  	.rmdir = CIFSSMBRmDir,
> +	.unlink = CIFSSMBDelFile,
> +	.rename_pending_delete = cifs_rename_pending_delete,
>  };
>  
>  struct smb_version_values smb1_values = {

Hmm...ACK I guess...

I think it might have been better to just make a single "unlink"
function and do the "rename_pending_delete" stuff within that instead
of abstracting that out too. Not a huge deal though...

-- 
Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>

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

* Re: [PATCH 09/45] CIFS: Add SMB2 support for unlink
       [not found]     ` <1342626541-29872-10-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
@ 2012-09-12 19:51       ` Jeff Layton
  0 siblings, 0 replies; 74+ messages in thread
From: Jeff Layton @ 2012-09-12 19:51 UTC (permalink / raw)
  To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA

On Wed, 18 Jul 2012 19:48:25 +0400
Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:

> Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
> ---
>  fs/cifs/smb2inode.c |    9 +++++++++
>  fs/cifs/smb2ops.c   |    1 +
>  fs/cifs/smb2proto.h |    2 ++
>  3 files changed, 12 insertions(+), 0 deletions(-)
> 
> diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
> index 2aa5cb0..02a9bda 100644
> --- a/fs/cifs/smb2inode.c
> +++ b/fs/cifs/smb2inode.c
> @@ -161,3 +161,12 @@ smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
>  				  0, CREATE_NOT_FILE | CREATE_DELETE_ON_CLOSE,
>  				  NULL, SMB2_OP_DELETE);
>  }
> +
> +int
> +smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
> +	    struct cifs_sb_info *cifs_sb)
> +{
> +	return smb2_open_op_close(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
> +				  0, CREATE_DELETE_ON_CLOSE, NULL,
> +				  SMB2_OP_DELETE);
> +}
> diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
> index 826209b..bf9b318 100644
> --- a/fs/cifs/smb2ops.c
> +++ b/fs/cifs/smb2ops.c
> @@ -321,6 +321,7 @@ struct smb_version_operations smb21_operations = {
>  	.mkdir = smb2_mkdir,
>  	.mkdir_setinfo = smb2_mkdir_setinfo,
>  	.rmdir = smb2_rmdir,
> +	.unlink = smb2_unlink,
>  };
>  
>  struct smb_version_values smb21_values = {
> diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
> index bfaa7b1..f4ac727 100644
> --- a/fs/cifs/smb2proto.h
> +++ b/fs/cifs/smb2proto.h
> @@ -59,6 +59,8 @@ extern void smb2_mkdir_setinfo(struct inode *inode, const char *full_path,
>  			       struct cifs_tcon *tcon, const unsigned int xid);
>  extern int smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon,
>  		      const char *name, struct cifs_sb_info *cifs_sb);
> +extern int smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon,
> +		       const char *name, struct cifs_sb_info *cifs_sb);
>  
>  /*
>   * SMB2 Worker functions - most of protocol specific implementation details

So, you're not defining a rename_pending_delete function here. That
means that if the initial unlink attempt happens to get back -ETXTBUSY,
you're now going to return -ENOSYS.

I think maybe it would be best to have cifs_unlink just fall through
and return -ETXTBUSY if there is no rename_pending_delete function.

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

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

* Re: [PATCH 10/45] CIFS: Replace netfid with cifs_fid struct in cifsFileInfo
       [not found]     ` <1342626541-29872-11-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
@ 2012-09-12 19:55       ` Jeff Layton
  0 siblings, 0 replies; 74+ messages in thread
From: Jeff Layton @ 2012-09-12 19:55 UTC (permalink / raw)
  To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA

On Wed, 18 Jul 2012 19:48:26 +0400
Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:

> This is help us to extend the code for future protocols that can use
> another fid mechanism (as SMB2 that has it divided into two parts:
> persistent and violatile).
> 
> Also rename variables and refactor the code around the changes.
> 
> Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
> ---
>  fs/cifs/cifsacl.c  |    2 +-
>  fs/cifs/cifsglob.h |    6 ++-
>  fs/cifs/cifssmb.c  |    4 +-
>  fs/cifs/file.c     |  116 ++++++++++++++++++++++++++--------------------------
>  fs/cifs/inode.c    |   10 ++--
>  fs/cifs/ioctl.c    |   13 ++++--
>  fs/cifs/misc.c     |    2 +-
>  fs/cifs/readdir.c  |   10 ++--
>  fs/cifs/smb1ops.c  |    2 +-
>  9 files changed, 87 insertions(+), 78 deletions(-)
> 
> diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
> index f8c8464..d98a7c3 100644
> --- a/fs/cifs/cifsacl.c
> +++ b/fs/cifs/cifsacl.c
> @@ -1222,7 +1222,7 @@ struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
>  	if (!open_file)
>  		return get_cifs_acl_by_path(cifs_sb, path, pacllen);
>  
> -	pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->netfid, pacllen);
> +	pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->fid.netfid, pacllen);
>  	cifsFileInfo_put(open_file);
>  	return pntsd;
>  }
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index bd53d97..01ee8d2 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -746,6 +746,10 @@ struct cifs_search_info {
>  	bool smallBuf:1; /* so we know which buf_release function to call */
>  };
>  
> +struct cifs_fid {
> +	__u16 netfid;
> +};
> +
>  struct cifsFileInfo {
>  	struct list_head tlist;	/* pointer to next fid owned by tcon */
>  	struct list_head flist;	/* next fid (file instance) for this inode */
> @@ -755,7 +759,7 @@ struct cifsFileInfo {
>  				 */
>  	unsigned int uid;	/* allows finding which FileInfo structure */
>  	__u32 pid;		/* process id who opened file */
> -	__u16 netfid;		/* file id from remote */
> +	struct cifs_fid fid;	/* file id from remote */
>  	/* BB add lock scope info here if needed */ ;
>  	/* lock scope id (0 if none) */
>  	struct dentry *dentry;
> diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
> index 395f3e2..2936875 100644
> --- a/fs/cifs/cifssmb.c
> +++ b/fs/cifs/cifssmb.c
> @@ -1627,7 +1627,7 @@ cifs_async_readv(struct cifs_readdata *rdata)
>  	smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
>  
>  	smb->AndXCommand = 0xFF;	/* none */
> -	smb->Fid = rdata->cfile->netfid;
> +	smb->Fid = rdata->cfile->fid.netfid;
>  	smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
>  	if (wct == 12)
>  		smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
> @@ -2079,7 +2079,7 @@ cifs_async_writev(struct cifs_writedata *wdata)
>  	smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
>  
>  	smb->AndXCommand = 0xFF;	/* none */
> -	smb->Fid = wdata->cfile->netfid;
> +	smb->Fid = wdata->cfile->fid.netfid;
>  	smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
>  	if (wct == 14)
>  		smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
> diff --git a/fs/cifs/file.c b/fs/cifs/file.c
> index 1712794..f542574 100644
> --- a/fs/cifs/file.c
> +++ b/fs/cifs/file.c
> @@ -247,39 +247,39 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file,
>  {
>  	struct dentry *dentry = file->f_path.dentry;
>  	struct inode *inode = dentry->d_inode;
> -	struct cifsInodeInfo *pCifsInode = CIFS_I(inode);
> -	struct cifsFileInfo *pCifsFile;
> -
> -	pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
> -	if (pCifsFile == NULL)
> -		return pCifsFile;
> -
> -	pCifsFile->count = 1;
> -	pCifsFile->netfid = fileHandle;
> -	pCifsFile->pid = current->tgid;
> -	pCifsFile->uid = current_fsuid();
> -	pCifsFile->dentry = dget(dentry);
> -	pCifsFile->f_flags = file->f_flags;
> -	pCifsFile->invalidHandle = false;
> -	pCifsFile->tlink = cifs_get_tlink(tlink);
> -	mutex_init(&pCifsFile->fh_mutex);
> -	INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break);
> -	INIT_LIST_HEAD(&pCifsFile->llist);
> +	struct cifsInodeInfo *cinode = CIFS_I(inode);
> +	struct cifsFileInfo *cfile;
> +
> +	cfile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
> +	if (cfile == NULL)
> +		return cfile;
> +
> +	cfile->count = 1;
> +	cfile->fid.netfid = fileHandle;
> +	cfile->pid = current->tgid;
> +	cfile->uid = current_fsuid();
> +	cfile->dentry = dget(dentry);
> +	cfile->f_flags = file->f_flags;
> +	cfile->invalidHandle = false;
> +	cfile->tlink = cifs_get_tlink(tlink);
> +	mutex_init(&cfile->fh_mutex);
> +	INIT_WORK(&cfile->oplock_break, cifs_oplock_break);
> +	INIT_LIST_HEAD(&cfile->llist);
>  
>  	spin_lock(&cifs_file_list_lock);
> -	list_add(&pCifsFile->tlist, &(tlink_tcon(tlink)->openFileList));
> +	list_add(&cfile->tlist, &(tlink_tcon(tlink)->openFileList));
>  	/* if readable file instance put first in list*/
>  	if (file->f_mode & FMODE_READ)
> -		list_add(&pCifsFile->flist, &pCifsInode->openFileList);
> +		list_add(&cfile->flist, &cinode->openFileList);
>  	else
> -		list_add_tail(&pCifsFile->flist, &pCifsInode->openFileList);
> +		list_add_tail(&cfile->flist, &cinode->openFileList);
>  	spin_unlock(&cifs_file_list_lock);
>  
> -	cifs_set_oplock_level(pCifsInode, oplock);
> -	pCifsInode->can_cache_brlcks = pCifsInode->clientCanCacheAll;
> +	cifs_set_oplock_level(cinode, oplock);
> +	cinode->can_cache_brlcks = cinode->clientCanCacheAll;
>  
> -	file->private_data = pCifsFile;
> -	return pCifsFile;
> +	file->private_data = cfile;
> +	return cfile;
>  }
>  
>  static void cifs_del_lock_waiters(struct cifsLockInfo *lock);
> @@ -327,7 +327,7 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
>  		unsigned int xid;
>  		int rc;
>  		xid = get_xid();
> -		rc = CIFSSMBClose(xid, tcon, cifs_file->netfid);
> +		rc = CIFSSMBClose(xid, tcon, cifs_file->fid.netfid);
>  		free_xid(xid);
>  	}
>  
> @@ -552,7 +552,7 @@ static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
>  	}
>  
>  reopen_success:
> -	pCifsFile->netfid = netfid;
> +	pCifsFile->fid.netfid = netfid;
>  	pCifsFile->invalidHandle = false;
>  	mutex_unlock(&pCifsFile->fh_mutex);
>  	pCifsInode = CIFS_I(inode);
> @@ -600,39 +600,37 @@ int cifs_closedir(struct inode *inode, struct file *file)
>  {
>  	int rc = 0;
>  	unsigned int xid;
> -	struct cifsFileInfo *pCFileStruct = file->private_data;
> -	char *ptmp;
> +	struct cifsFileInfo *cfile = file->private_data;
> +	char *tmp;
>  
>  	cFYI(1, "Closedir inode = 0x%p", inode);
>  
>  	xid = get_xid();
>  
> -	if (pCFileStruct) {
> -		struct cifs_tcon *pTcon = tlink_tcon(pCFileStruct->tlink);
> +	if (cfile) {
> +		struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
>  
>  		cFYI(1, "Freeing private data in close dir");
>  		spin_lock(&cifs_file_list_lock);
> -		if (!pCFileStruct->srch_inf.endOfSearch &&
> -		    !pCFileStruct->invalidHandle) {
> -			pCFileStruct->invalidHandle = true;
> +		if (!cfile->srch_inf.endOfSearch && !cfile->invalidHandle) {
> +			cfile->invalidHandle = true;
>  			spin_unlock(&cifs_file_list_lock);
> -			rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
> -			cFYI(1, "Closing uncompleted readdir with rc %d",
> -				 rc);
> +			rc = CIFSFindClose(xid, tcon, cfile->fid.netfid);
> +			cFYI(1, "Closing uncompleted readdir with rc %d", rc);
>  			/* not much we can do if it fails anyway, ignore rc */
>  			rc = 0;
>  		} else
>  			spin_unlock(&cifs_file_list_lock);
> -		ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
> -		if (ptmp) {
> +		tmp = cfile->srch_inf.ntwrk_buf_start;
> +		if (tmp) {
>  			cFYI(1, "closedir free smb buf in srch struct");
> -			pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
> -			if (pCFileStruct->srch_inf.smallBuf)
> -				cifs_small_buf_release(ptmp);
> +			cfile->srch_inf.ntwrk_buf_start = NULL;
> +			if (cfile->srch_inf.smallBuf)
> +				cifs_small_buf_release(tmp);
>  			else
> -				cifs_buf_release(ptmp);
> +				cifs_buf_release(tmp);
>  		}
> -		cifs_put_tlink(pCFileStruct->tlink);
> +		cifs_put_tlink(cfile->tlink);
>  		kfree(file->private_data);
>  		file->private_data = NULL;
>  	}
> @@ -923,7 +921,8 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
>  			cur->OffsetLow = cpu_to_le32((u32)li->offset);
>  			cur->OffsetHigh = cpu_to_le32((u32)(li->offset>>32));
>  			if (++num == max_num) {
> -				stored_rc = cifs_lockv(xid, tcon, cfile->netfid,
> +				stored_rc = cifs_lockv(xid, tcon,
> +						       cfile->fid.netfid,
>  						       (__u8)li->type, 0, num,
>  						       buf);
>  				if (stored_rc)
> @@ -935,7 +934,7 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
>  		}
>  
>  		if (num) {
> -			stored_rc = cifs_lockv(xid, tcon, cfile->netfid,
> +			stored_rc = cifs_lockv(xid, tcon, cfile->fid.netfid,
>  					       (__u8)types[i], 0, num, buf);
>  			if (stored_rc)
>  				rc = stored_rc;
> @@ -1029,7 +1028,7 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)
>  			type = CIFS_WRLCK;
>  		lck = list_entry(el, struct lock_to_push, llist);
>  		lck->pid = flock->fl_pid;
> -		lck->netfid = cfile->netfid;
> +		lck->netfid = cfile->fid.netfid;
>  		lck->length = length;
>  		lck->type = type;
>  		lck->offset = flock->fl_start;
> @@ -1130,7 +1129,7 @@ static int
>  cifs_mandatory_lock(unsigned int xid, struct cifsFileInfo *cfile, __u64 offset,
>  		    __u64 length, __u32 type, int lock, int unlock, bool wait)
>  {
> -	return CIFSSMBLock(xid, tlink_tcon(cfile->tlink), cfile->netfid,
> +	return CIFSSMBLock(xid, tlink_tcon(cfile->tlink), cfile->fid.netfid,
>  			   current->tgid, length, offset, unlock, lock,
>  			   (__u8)type, wait, 0);
>  }
> @@ -1144,7 +1143,7 @@ cifs_getlk(struct file *file, struct file_lock *flock, __u32 type,
>  	struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data;
>  	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
>  	struct TCP_Server_Info *server = tcon->ses->server;
> -	__u16 netfid = cfile->netfid;
> +	__u16 netfid = cfile->fid.netfid;
>  
>  	if (posix_lck) {
>  		int posix_lock_type;
> @@ -1288,7 +1287,8 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
>  			 */
>  			list_move(&li->llist, &tmp_llist);
>  			if (++num == max_num) {
> -				stored_rc = cifs_lockv(xid, tcon, cfile->netfid,
> +				stored_rc = cifs_lockv(xid, tcon,
> +						       cfile->fid.netfid,
>  						       li->type, num, 0, buf);
>  				if (stored_rc) {
>  					/*
> @@ -1311,7 +1311,7 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
>  				cur++;
>  		}
>  		if (num) {
> -			stored_rc = cifs_lockv(xid, tcon, cfile->netfid,
> +			stored_rc = cifs_lockv(xid, tcon, cfile->fid.netfid,
>  					       types[i], num, 0, buf);
>  			if (stored_rc) {
>  				cifs_move_llist(&tmp_llist, &cfile->llist);
> @@ -1336,7 +1336,7 @@ cifs_setlk(struct file *file,  struct file_lock *flock, __u32 type,
>  	struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data;
>  	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
>  	struct TCP_Server_Info *server = tcon->ses->server;
> -	__u16 netfid = cfile->netfid;
> +	__u16 netfid = cfile->fid.netfid;
>  
>  	if (posix_lck) {
>  		int posix_lock_type;
> @@ -1416,7 +1416,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock)
>  			tcon->ses->server);
>  
>  	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
> -	netfid = cfile->netfid;
> +	netfid = cfile->fid.netfid;
>  	cinode = CIFS_I(file->f_path.dentry->d_inode);
>  
>  	if (cap_unix(tcon->ses) &&
> @@ -1507,7 +1507,7 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, __u32 pid,
>  			/* iov[0] is reserved for smb header */
>  			iov[1].iov_base = (char *)write_data + total_written;
>  			iov[1].iov_len = len;
> -			io_parms.netfid = open_file->netfid;
> +			io_parms.netfid = open_file->fid.netfid;
>  			io_parms.pid = pid;
>  			io_parms.tcon = pTcon;
>  			io_parms.offset = *poffset;
> @@ -2071,7 +2071,7 @@ int cifs_strict_fsync(struct file *file, loff_t start, loff_t end,
>  
>  	tcon = tlink_tcon(smbfile->tlink);
>  	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
> -		rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
> +		rc = CIFSSMBFlush(xid, tcon, smbfile->fid.netfid);
>  
>  	free_xid(xid);
>  	mutex_unlock(&inode->i_mutex);
> @@ -2099,7 +2099,7 @@ int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
>  
>  	tcon = tlink_tcon(smbfile->tlink);
>  	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
> -		rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
> +		rc = CIFSSMBFlush(xid, tcon, smbfile->fid.netfid);
>  
>  	free_xid(xid);
>  	mutex_unlock(&inode->i_mutex);
> @@ -2795,7 +2795,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
>  				if (rc != 0)
>  					break;
>  			}
> -			io_parms.netfid = open_file->netfid;
> +			io_parms.netfid = open_file->fid.netfid;
>  			io_parms.pid = pid;
>  			io_parms.tcon = tcon;
>  			io_parms.offset = *poffset;
> @@ -3369,7 +3369,7 @@ void cifs_oplock_break(struct work_struct *work)
>  	 * disconnected since oplock already released by the server
>  	 */
>  	if (!cfile->oplock_break_cancelled) {
> -		rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid,
> +		rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->fid.netfid,
>  				 current->tgid, 0, 0, 0, 0,
>  				 LOCKING_ANDX_OPLOCK_RELEASE, false,
>  				 cinode->clientCanCacheRead ? 1 : 0);
> diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
> index 9685eb1..1eeb6a0 100644
> --- a/fs/cifs/inode.c
> +++ b/fs/cifs/inode.c
> @@ -298,7 +298,7 @@ int cifs_get_file_info_unix(struct file *filp)
>  	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
>  
>  	xid = get_xid();
> -	rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->netfid, &find_data);
> +	rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->fid.netfid, &find_data);
>  	if (!rc) {
>  		cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb);
>  	} else if (rc == -EREMOTE) {
> @@ -566,7 +566,7 @@ int cifs_get_file_info(struct file *filp)
>  	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
>  
>  	xid = get_xid();
> -	rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data);
> +	rc = CIFSSMBQFileInfo(xid, tcon, cfile->fid.netfid, &find_data);
>  	switch (rc) {
>  	case 0:
>  		cifs_all_info_to_fattr(&fattr, &find_data, cifs_sb, false);
> @@ -932,7 +932,7 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, unsigned int xid,
>  	 */
>  	open_file = find_writable_file(cifsInode, true);
>  	if (open_file) {
> -		netfid = open_file->netfid;
> +		netfid = open_file->fid.netfid;
>  		netpid = open_file->pid;
>  		pTcon = tlink_tcon(open_file->tlink);
>  		goto set_via_filehandle;
> @@ -1887,7 +1887,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
>  	 */
>  	open_file = find_writable_file(cifsInode, true);
>  	if (open_file) {
> -		__u16 nfid = open_file->netfid;
> +		__u16 nfid = open_file->fid.netfid;
>  		__u32 npid = open_file->pid;
>  		pTcon = tlink_tcon(open_file->tlink);
>  		rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, nfid,
> @@ -2061,7 +2061,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
>  	args->device = 0;
>  	open_file = find_writable_file(cifsInode, true);
>  	if (open_file) {
> -		u16 nfid = open_file->netfid;
> +		u16 nfid = open_file->fid.netfid;
>  		u32 npid = open_file->pid;
>  		pTcon = tlink_tcon(open_file->tlink);
>  		rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid);
> diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c
> index ae082a6..5b3481b 100644
> --- a/fs/cifs/ioctl.c
> +++ b/fs/cifs/ioctl.c
> @@ -75,8 +75,9 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
>  			tcon = tlink_tcon(pSMBFile->tlink);
>  			caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
>  			if (CIFS_UNIX_EXTATTR_CAP & caps) {
> -				rc = CIFSGetExtAttr(xid, tcon, pSMBFile->netfid,
> -					&ExtAttrBits, &ExtAttrMask);
> +				rc = CIFSGetExtAttr(xid, tcon,
> +						    pSMBFile->fid.netfid,
> +						    &ExtAttrBits, &ExtAttrMask);
>  				if (rc == 0)
>  					rc = put_user(ExtAttrBits &
>  						FS_FL_USER_VISIBLE,
> @@ -94,8 +95,12 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
>  					rc = -EFAULT;
>  					break;
>  				}
> -				/* rc= CIFSGetExtAttr(xid,tcon,pSMBFile->netfid,
> -					extAttrBits, &ExtAttrMask);*/
> +				/*
> +				 * rc = CIFSGetExtAttr(xid, tcon,
> +				 *		       pSMBFile->fid.netfid,
> +				 *		       extAttrBits,
> +				 *		       &ExtAttrMask);
> +				 */
>  			}
>  			cFYI(1, "set flags not implemented yet");
>  			break;
> diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
> index ce41fee..a921b07 100644
> --- a/fs/cifs/misc.c
> +++ b/fs/cifs/misc.c
> @@ -466,7 +466,7 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
>  			list_for_each(tmp2, &tcon->openFileList) {
>  				netfile = list_entry(tmp2, struct cifsFileInfo,
>  						     tlist);
> -				if (pSMB->Fid != netfile->netfid)
> +				if (pSMB->Fid != netfile->fid.netfid)
>  					continue;
>  
>  				cFYI(1, "file id match, oplock break");
> diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
> index d87f826..9e76e3b 100644
> --- a/fs/cifs/readdir.c
> +++ b/fs/cifs/readdir.c
> @@ -279,7 +279,7 @@ ffirst_retry:
>  		search_flags |= CIFS_SEARCH_BACKUP_SEARCH;
>  
>  	rc = CIFSFindFirst(xid, tcon, full_path, cifs_sb->local_nls,
> -		&cifsFile->netfid, search_flags, &cifsFile->srch_inf,
> +		&cifsFile->fid.netfid, search_flags, &cifsFile->srch_inf,
>  		cifs_sb->mnt_cifs_flags &
>  			CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
>  	if (rc == 0)
> @@ -545,7 +545,7 @@ static int find_cifs_entry(const unsigned int xid, struct cifs_tcon *pTcon,
>  		    !cifsFile->invalidHandle) {
>  			cifsFile->invalidHandle = true;
>  			spin_unlock(&cifs_file_list_lock);
> -			CIFSFindClose(xid, pTcon, cifsFile->netfid);
> +			CIFSFindClose(xid, pTcon, cifsFile->fid.netfid);
>  		} else
>  			spin_unlock(&cifs_file_list_lock);
>  		if (cifsFile->srch_inf.ntwrk_buf_start) {
> @@ -577,8 +577,8 @@ static int find_cifs_entry(const unsigned int xid, struct cifs_tcon *pTcon,
>  	while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) &&
>  	      (rc == 0) && !cifsFile->srch_inf.endOfSearch) {
>  		cFYI(1, "calling findnext2");
> -		rc = CIFSFindNext(xid, pTcon, cifsFile->netfid, search_flags,
> -				  &cifsFile->srch_inf);
> +		rc = CIFSFindNext(xid, pTcon, cifsFile->fid.netfid,
> +				  search_flags, &cifsFile->srch_inf);
>  		/* FindFirst/Next set last_entry to NULL on malformed reply */
>  		if (cifsFile->srch_inf.last_entry)
>  			cifs_save_resume_key(cifsFile->srch_inf.last_entry,
> @@ -781,7 +781,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
>  			}
>  		} /* else {
>  			cifsFile->invalidHandle = true;
> -			CIFSFindClose(xid, pTcon, cifsFile->netfid);
> +			CIFSFindClose(xid, pTcon, cifsFile->fid.netfid);
>  		} */
>  
>  		pTcon = tlink_tcon(cifsFile->tlink);
> diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
> index 725fa61..b170da0 100644
> --- a/fs/cifs/smb1ops.c
> +++ b/fs/cifs/smb1ops.c
> @@ -63,7 +63,7 @@ send_nt_cancel(struct TCP_Server_Info *server, void *buf,
>  static bool
>  cifs_compare_fids(struct cifsFileInfo *ob1, struct cifsFileInfo *ob2)
>  {
> -	return ob1->netfid == ob2->netfid;
> +	return ob1->fid.netfid == ob2->fid.netfid;
>  }
>  
>  static unsigned int

Reviewed-by: Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>

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

* Re: [PATCH 08/45] CIFS: Move unlink code to ops struct
       [not found]         ` <20120912154804.19b97830-4QP7MXygkU+dMjc06nkz3ljfA9RmPOcC@public.gmane.org>
@ 2012-09-12 20:10           ` Jeff Layton
       [not found]             ` <20120912161038.4c32810a-4QP7MXygkU+dMjc06nkz3ljfA9RmPOcC@public.gmane.org>
  0 siblings, 1 reply; 74+ messages in thread
From: Jeff Layton @ 2012-09-12 20:10 UTC (permalink / raw)
  To: Jeff Layton; +Cc: Pavel Shilovsky, linux-cifs-u79uwXL29TY76Z2rM5mHXA

On Wed, 12 Sep 2012 15:48:04 -0400
Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:

> On Wed, 18 Jul 2012 19:48:24 +0400
> Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:
> 
> > Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
> > ---
> >  fs/cifs/cifsglob.h  |    6 ++++++
> >  fs/cifs/cifsproto.h |    9 ++++++---
> >  fs/cifs/cifssmb.c   |   16 ++++++++--------
> >  fs/cifs/inode.c     |   32 +++++++++++++++++++++-----------
> >  fs/cifs/smb1ops.c   |    2 ++
> >  5 files changed, 43 insertions(+), 22 deletions(-)
> > 
> > diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> > index a5b4e82..bd53d97 100644
> > --- a/fs/cifs/cifsglob.h
> > +++ b/fs/cifs/cifsglob.h
> > @@ -256,6 +256,12 @@ struct smb_version_operations {
> >  	/* remove directory */
> >  	int (*rmdir)(const unsigned int, struct cifs_tcon *, const char *,
> >  		     struct cifs_sb_info *);
> > +	/* unlink file */
> > +	int (*unlink)(const unsigned int, struct cifs_tcon *, const char *,
> > +		      struct cifs_sb_info *);
> > +	/* open, rename and delete file */
> > +	int (*rename_pending_delete)(const char *, struct dentry *,
> > +				     const unsigned int);
> >  };
> >  
> >  struct smb_version_values {
> > diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
> > index 43784ee..e9349af 100644
> > --- a/fs/cifs/cifsproto.h
> > +++ b/fs/cifs/cifsproto.h
> > @@ -144,6 +144,11 @@ extern int cifs_get_file_info_unix(struct file *filp);
> >  extern int cifs_get_inode_info_unix(struct inode **pinode,
> >  			const unsigned char *search_path,
> >  			struct super_block *sb, unsigned int xid);
> > +extern int cifs_set_file_info(struct inode *inode, struct iattr *attrs,
> > +			      unsigned int xid, char *full_path, __u32 dosattr);
> > +extern int cifs_rename_pending_delete(const char *full_path,
> > +				      struct dentry *dentry,
> > +				      const unsigned int xid);
> >  extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb,
> >  			      struct cifs_fattr *fattr, struct inode *inode,
> >  			      const char *path, const __u16 *pfid);
> > @@ -303,9 +308,7 @@ extern int CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
> >  			const struct nls_table *nls_codepage,
> >  			int remap_special_chars);
> >  extern int CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon,
> > -			const char *name,
> > -			const struct nls_table *nls_codepage,
> > -			int remap_special_chars);
> > +			  const char *name, struct cifs_sb_info *cifs_sb);
> >  extern int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
> >  			const char *fromName, const char *toName,
> >  			const struct nls_table *nls_codepage,
> > diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
> > index 9fb21cd..395f3e2 100644
> > --- a/fs/cifs/cifssmb.c
> > +++ b/fs/cifs/cifssmb.c
> > @@ -902,15 +902,15 @@ PsxDelete:
> >  }
> >  
> >  int
> > -CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon,
> > -	       const char *fileName, const struct nls_table *nls_codepage,
> > -	       int remap)
> > +CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
> > +	       struct cifs_sb_info *cifs_sb)
> >  {
> >  	DELETE_FILE_REQ *pSMB = NULL;
> >  	DELETE_FILE_RSP *pSMBr = NULL;
> >  	int rc = 0;
> >  	int bytes_returned;
> >  	int name_len;
> > +	int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
> >  
> >  DelFileRetry:
> >  	rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
> > @@ -919,15 +919,15 @@ DelFileRetry:
> >  		return rc;
> >  
> >  	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
> > -		name_len =
> > -		    cifsConvertToUTF16((__le16 *) pSMB->fileName, fileName,
> > -				       PATH_MAX, nls_codepage, remap);
> > +		name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
> > +					      PATH_MAX, cifs_sb->local_nls,
> > +					      remap);
> >  		name_len++;	/* trailing null */
> >  		name_len *= 2;
> >  	} else {		/* BB improve check for buffer overruns BB */
> > -		name_len = strnlen(fileName, PATH_MAX);
> > +		name_len = strnlen(name, PATH_MAX);
> >  		name_len++;	/* trailing null */
> > -		strncpy(pSMB->fileName, fileName, name_len);
> > +		strncpy(pSMB->fileName, name, name_len);
> >  	}
> >  	pSMB->SearchAttributes =
> >  	    cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
> > diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
> > index 88afb1a..9685eb1 100644
> > --- a/fs/cifs/inode.c
> > +++ b/fs/cifs/inode.c
> > @@ -878,9 +878,9 @@ out:
> >  	return inode;
> >  }
> >  
> > -static int
> > +int
> >  cifs_set_file_info(struct inode *inode, struct iattr *attrs, unsigned int xid,
> > -		    char *full_path, __u32 dosattr)
> > +		   char *full_path, __u32 dosattr)
> >  {
> >  	int rc;
> >  	int oplock = 0;
> > @@ -995,13 +995,13 @@ out:
> >  }
> >  
> >  /*
> > - * open the given file (if it isn't already), set the DELETE_ON_CLOSE bit
> > + * Open the given file (if it isn't already), set the DELETE_ON_CLOSE bit
> >   * and rename it to a random name that hopefully won't conflict with
> >   * anything else.
> >   */
> > -static int
> > -cifs_rename_pending_delete(char *full_path, struct dentry *dentry,
> > -			   unsigned int xid)
> > +int
> > +cifs_rename_pending_delete(const char *full_path, struct dentry *dentry,
> > +			   const unsigned int xid)
> >  {
> >  	int oplock = 0;
> >  	int rc;
> > @@ -1138,6 +1138,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
> >  	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
> >  	struct tcon_link *tlink;
> >  	struct cifs_tcon *tcon;
> > +	struct TCP_Server_Info *server;
> >  	struct iattr *attrs = NULL;
> >  	__u32 dosattr = 0, origattr = 0;
> >  
> > @@ -1147,6 +1148,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
> >  	if (IS_ERR(tlink))
> >  		return PTR_ERR(tlink);
> >  	tcon = tlink_tcon(tlink);
> > +	server = tcon->ses->server;
> >  
> >  	xid = get_xid();
> >  
> > @@ -1169,8 +1171,12 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
> >  	}
> >  
> >  retry_std_delete:
> > -	rc = CIFSSMBDelFile(xid, tcon, full_path, cifs_sb->local_nls,
> > -			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
> > +	if (!server->ops->unlink) {
> > +		rc = -ENOSYS;
> > +		goto psx_del_no_retry;
> > +	}
> > +
> > +	rc = server->ops->unlink(xid, tcon, full_path, cifs_sb);
> >  
> >  psx_del_no_retry:
> >  	if (!rc) {
> > @@ -1179,9 +1185,13 @@ psx_del_no_retry:
> >  	} else if (rc == -ENOENT) {
> >  		d_drop(dentry);
> >  	} else if (rc == -ETXTBSY) {
> > -		rc = cifs_rename_pending_delete(full_path, dentry, xid);
> > -		if (rc == 0)
> > -			cifs_drop_nlink(inode);
> > +		if (server->ops->rename_pending_delete) {
> > +			rc = server->ops->rename_pending_delete(full_path,
> > +								dentry, xid);
> > +			if (rc == 0)
> > +				cifs_drop_nlink(inode);
> > +		} else
> > +			rc = -ENOSYS;

In fact, now that I look...

The unlink(2) manpage lists EBUSY as a valid return code, but doesn't
mention ETXTBSY. Perhaps we'd be better off turning that error into
EBUSY instead of returning it as-is to userspace?

In any case, -ENOSYS just because you can't do a sillyrename seems
clearly wrong. Better to return either -EBUSY or -ETXTBUSY there.

> >  	} else if ((rc == -EACCES) && (dosattr == 0) && inode) {
> >  		attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
> >  		if (attrs == NULL) {
> > diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
> > index 3129ac7..725fa61 100644
> > --- a/fs/cifs/smb1ops.c
> > +++ b/fs/cifs/smb1ops.c
> > @@ -644,6 +644,8 @@ struct smb_version_operations smb1_operations = {
> >  	.mkdir = CIFSSMBMkDir,
> >  	.mkdir_setinfo = cifs_mkdir_setinfo,
> >  	.rmdir = CIFSSMBRmDir,
> > +	.unlink = CIFSSMBDelFile,
> > +	.rename_pending_delete = cifs_rename_pending_delete,
> >  };
> >  
> >  struct smb_version_values smb1_values = {
> 
> Hmm...ACK I guess...
> 
> I think it might have been better to just make a single "unlink"
> function and do the "rename_pending_delete" stuff within that instead
> of abstracting that out too. Not a huge deal though...
> 


-- 
Jeff Layton <jlayton-vpEMnDpepFuMZCB2o+C8xQ@public.gmane.org>

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

* Re: [PATCH 11/45] CIFS: Move open code to ops struct
       [not found]     ` <1342626541-29872-12-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
@ 2012-09-12 20:12       ` Jeff Layton
  0 siblings, 0 replies; 74+ messages in thread
From: Jeff Layton @ 2012-09-12 20:12 UTC (permalink / raw)
  To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA

On Wed, 18 Jul 2012 19:48:27 +0400
Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:

> Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
> ---
>  fs/cifs/cifsglob.h  |    7 +++++
>  fs/cifs/cifsproto.h |    7 +++--
>  fs/cifs/dir.c       |   17 +++++++------
>  fs/cifs/file.c      |   63 ++++++++++++++++++++++++--------------------------
>  fs/cifs/smb1ops.c   |   29 +++++++++++++++++++++++
>  5 files changed, 79 insertions(+), 44 deletions(-)
> 
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index 01ee8d2..c4375d8 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -171,6 +171,7 @@ struct cifs_tcon;
>  struct dfs_info3_param;
>  struct cifs_fattr;
>  struct smb_vol;
> +struct cifs_fid;
>  
>  struct smb_version_operations {
>  	int (*send_cancel)(struct TCP_Server_Info *, void *,
> @@ -262,6 +263,12 @@ struct smb_version_operations {
>  	/* open, rename and delete file */
>  	int (*rename_pending_delete)(const char *, struct dentry *,
>  				     const unsigned int);
> +	/* open a file for non-posix mounts */
> +	int (*open)(const unsigned int, struct cifs_tcon *, const char *, int,
> +		    int, int, struct cifs_fid *, __u32 *, FILE_ALL_INFO *,
> +		    struct cifs_sb_info *);
> +	/* set fid protocol-specific info */
> +	void (*set_fid)(struct cifsFileInfo *, struct cifs_fid *, __u32);
>  };
>  
>  struct smb_version_values {
> diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
> index e9349af..80b0e40 100644
> --- a/fs/cifs/cifsproto.h
> +++ b/fs/cifs/cifsproto.h
> @@ -121,9 +121,10 @@ extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time,
>  				      int offset);
>  extern void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock);
>  
> -extern struct cifsFileInfo *cifs_new_fileinfo(__u16 fileHandle,
> -				struct file *file, struct tcon_link *tlink,
> -				__u32 oplock);
> +extern struct cifsFileInfo *cifs_new_fileinfo(struct cifs_fid *fid,
> +					      struct file *file,
> +					      struct tcon_link *tlink,
> +					      __u32 oplock);
>  extern int cifs_posix_open(char *full_path, struct inode **inode,
>  			   struct super_block *sb, int mode,
>  			   unsigned int f_flags, __u32 *oplock, __u16 *netfid,
> diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
> index cbe709a..eebffaf 100644
> --- a/fs/cifs/dir.c
> +++ b/fs/cifs/dir.c
> @@ -384,11 +384,12 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
>  	unsigned int xid;
>  	struct tcon_link *tlink;
>  	struct cifs_tcon *tcon;
> -	__u16 fileHandle;
> +	struct cifs_fid fid;
>  	__u32 oplock;
> -	struct cifsFileInfo *pfile_info;
> +	struct cifsFileInfo *file_info;
>  
> -	/* Posix open is only called (at lookup time) for file create now.  For
> +	/*
> +	 * Posix open is only called (at lookup time) for file create now. For
>  	 * opens (rather than creates), because we do not know if it is a file
>  	 * or directory yet, and current Samba no longer allows us to do posix
>  	 * open on dirs, we could end up wasting an open call on what turns out
> @@ -422,20 +423,20 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
>  	tcon = tlink_tcon(tlink);
>  
>  	rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode,
> -			    &oplock, &fileHandle, opened);
> +			    &oplock, &fid.netfid, opened);
>  
>  	if (rc)
>  		goto out;
>  
>  	rc = finish_open(file, direntry, generic_file_open, opened);
>  	if (rc) {
> -		CIFSSMBClose(xid, tcon, fileHandle);
> +		CIFSSMBClose(xid, tcon, fid.netfid);
>  		goto out;
>  	}
>  
> -	pfile_info = cifs_new_fileinfo(fileHandle, file, tlink, oplock);
> -	if (pfile_info == NULL) {
> -		CIFSSMBClose(xid, tcon, fileHandle);
> +	file_info = cifs_new_fileinfo(&fid, file, tlink, oplock);
> +	if (file_info == NULL) {
> +		CIFSSMBClose(xid, tcon, fid.netfid);
>  		rc = -ENOMEM;
>  	}
>  
> diff --git a/fs/cifs/file.c b/fs/cifs/file.c
> index f542574..3f4b4ba 100644
> --- a/fs/cifs/file.c
> +++ b/fs/cifs/file.c
> @@ -169,16 +169,19 @@ posix_open_ret:
>  
>  static int
>  cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
> -	     struct cifs_tcon *tcon, unsigned int f_flags, __u32 *poplock,
> -	     __u16 *pnetfid, unsigned int xid)
> +	     struct cifs_tcon *tcon, unsigned int f_flags, __u32 *oplock,
> +	     struct cifs_fid *fid, unsigned int xid)
>  {
>  	int rc;
> -	int desiredAccess;
> +	int desired_access;
>  	int disposition;
>  	int create_options = CREATE_NOT_DIR;
>  	FILE_ALL_INFO *buf;
>  
> -	desiredAccess = cifs_convert_flags(f_flags);
> +	if (!tcon->ses->server->ops->open)
> +		return -ENOSYS;
> +
> +	desired_access = cifs_convert_flags(f_flags);
>  
>  /*********************************************************************
>   *  open flag mapping table:
> @@ -215,16 +218,9 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
>  	if (backup_cred(cifs_sb))
>  		create_options |= CREATE_OPEN_BACKUP_INTENT;
>  
> -	if (tcon->ses->capabilities & CAP_NT_SMBS)
> -		rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
> -			 desiredAccess, create_options, pnetfid, poplock, buf,
> -			 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
> -				 & CIFS_MOUNT_MAP_SPECIAL_CHR);
> -	else
> -		rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
> -			desiredAccess, CREATE_NOT_DIR, pnetfid, poplock, buf,
> -			cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
> -				& CIFS_MOUNT_MAP_SPECIAL_CHR);
> +	rc = tcon->ses->server->ops->open(xid, tcon, full_path, disposition,
> +					  desired_access, create_options, fid,
> +					  oplock, buf, cifs_sb);
>  
>  	if (rc)
>  		goto out;
> @@ -234,7 +230,7 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
>  					      xid);
>  	else
>  		rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb,
> -					 xid, pnetfid);
> +					 xid, &fid->netfid);
>  
>  out:
>  	kfree(buf);
> @@ -242,7 +238,7 @@ out:
>  }
>  
>  struct cifsFileInfo *
> -cifs_new_fileinfo(__u16 fileHandle, struct file *file,
> +cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
>  		  struct tcon_link *tlink, __u32 oplock)
>  {
>  	struct dentry *dentry = file->f_path.dentry;
> @@ -255,7 +251,6 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file,
>  		return cfile;
>  
>  	cfile->count = 1;
> -	cfile->fid.netfid = fileHandle;
>  	cfile->pid = current->tgid;
>  	cfile->uid = current_fsuid();
>  	cfile->dentry = dget(dentry);
> @@ -265,6 +260,7 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file,
>  	mutex_init(&cfile->fh_mutex);
>  	INIT_WORK(&cfile->oplock_break, cifs_oplock_break);
>  	INIT_LIST_HEAD(&cfile->llist);
> +	tlink_tcon(tlink)->ses->server->ops->set_fid(cfile, fid, oplock);
>  
>  	spin_lock(&cifs_file_list_lock);
>  	list_add(&cfile->tlist, &(tlink_tcon(tlink)->openFileList));
> @@ -275,9 +271,6 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file,
>  		list_add_tail(&cfile->flist, &cinode->openFileList);
>  	spin_unlock(&cifs_file_list_lock);
>  
> -	cifs_set_oplock_level(cinode, oplock);
> -	cinode->can_cache_brlcks = cinode->clientCanCacheAll;
> -
>  	file->private_data = cfile;
>  	return cfile;
>  }
> @@ -355,10 +348,10 @@ int cifs_open(struct inode *inode, struct file *file)
>  	struct cifs_sb_info *cifs_sb;
>  	struct cifs_tcon *tcon;
>  	struct tcon_link *tlink;
> -	struct cifsFileInfo *pCifsFile = NULL;
> +	struct cifsFileInfo *cfile = NULL;
>  	char *full_path = NULL;
>  	bool posix_open_ok = false;
> -	__u16 netfid;
> +	struct cifs_fid fid;
>  
>  	xid = get_xid();
>  
> @@ -390,7 +383,7 @@ int cifs_open(struct inode *inode, struct file *file)
>  		/* can not refresh inode info since size could be stale */
>  		rc = cifs_posix_open(full_path, &inode, inode->i_sb,
>  				cifs_sb->mnt_file_mode /* ignored */,
> -				file->f_flags, &oplock, &netfid, xid);
> +				file->f_flags, &oplock, &fid.netfid, xid);
>  		if (rc == 0) {
>  			cFYI(1, "posix open succeeded");
>  			posix_open_ok = true;
> @@ -406,20 +399,22 @@ int cifs_open(struct inode *inode, struct file *file)
>  		} else if ((rc != -EIO) && (rc != -EREMOTE) &&
>  			 (rc != -EOPNOTSUPP)) /* path not found or net err */
>  			goto out;
> -		/* else fallthrough to retry open the old way on network i/o
> -		   or DFS errors */
> +		/*
> +		 * Else fallthrough to retry open the old way on network i/o
> +		 * or DFS errors.
> +		 */
>  	}
>  
>  	if (!posix_open_ok) {
>  		rc = cifs_nt_open(full_path, inode, cifs_sb, tcon,
> -				  file->f_flags, &oplock, &netfid, xid);
> +				  file->f_flags, &oplock, &fid, xid);
>  		if (rc)
>  			goto out;
>  	}
>  
> -	pCifsFile = cifs_new_fileinfo(netfid, file, tlink, oplock);
> -	if (pCifsFile == NULL) {
> -		CIFSSMBClose(xid, tcon, netfid);
> +	cfile = cifs_new_fileinfo(&fid, file, tlink, oplock);
> +	if (cfile == NULL) {
> +		CIFSSMBClose(xid, tcon, fid.netfid);
>  		rc = -ENOMEM;
>  		goto out;
>  	}
> @@ -427,8 +422,10 @@ int cifs_open(struct inode *inode, struct file *file)
>  	cifs_fscache_set_inode_cookie(inode, file);
>  
>  	if ((oplock & CIFS_CREATE_ACTION) && !posix_open_ok && tcon->unix_ext) {
> -		/* time to set mode which we can not set earlier due to
> -		   problems creating new read-only files */
> +		/*
> +		 * Time to set mode which we can not set earlier due to
> +		 * problems creating new read-only files.
> +		 */
>  		struct cifs_unix_set_info_args args = {
>  			.mode	= inode->i_mode,
>  			.uid	= NO_CHANGE_64,
> @@ -438,8 +435,8 @@ int cifs_open(struct inode *inode, struct file *file)
>  			.mtime	= NO_CHANGE_64,
>  			.device	= 0,
>  		};
> -		CIFSSMBUnixSetFileInfo(xid, tcon, &args, netfid,
> -					pCifsFile->pid);
> +		CIFSSMBUnixSetFileInfo(xid, tcon, &args, fid.netfid,
> +				       cfile->pid);
>  	}
>  
>  out:
> diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
> index b170da0..907b308 100644
> --- a/fs/cifs/smb1ops.c
> +++ b/fs/cifs/smb1ops.c
> @@ -607,6 +607,33 @@ cifs_mkdir_setinfo(struct inode *inode, const char *full_path,
>  		cifsInode->cifsAttrs = dosattrs;
>  }
>  
> +static int
> +cifs_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
> +	       int disposition, int desired_access, int create_options,
> +	       struct cifs_fid *fid, __u32 *oplock, FILE_ALL_INFO *buf,
> +	       struct cifs_sb_info *cifs_sb)
> +{
> +	if (!(tcon->ses->capabilities & CAP_NT_SMBS))
> +		return SMBLegacyOpen(xid, tcon, path, disposition,
> +				     desired_access, CREATE_NOT_DIR,
> +				     &fid->netfid, oplock, buf,
> +				     cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
> +						& CIFS_MOUNT_MAP_SPECIAL_CHR);
> +	return CIFSSMBOpen(xid, tcon, path, disposition, desired_access,
> +			   create_options, &fid->netfid, oplock, buf,
> +			   cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
> +						CIFS_MOUNT_MAP_SPECIAL_CHR);
> +}
> +
> +static void
> +cifs_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock)
> +{
> +	struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
> +	cfile->fid.netfid = fid->netfid;
> +	cifs_set_oplock_level(cinode, oplock);
> +	cinode->can_cache_brlcks = cinode->clientCanCacheAll;
> +}
> +
>  struct smb_version_operations smb1_operations = {
>  	.send_cancel = send_nt_cancel,
>  	.compare_fids = cifs_compare_fids,
> @@ -646,6 +673,8 @@ struct smb_version_operations smb1_operations = {
>  	.rmdir = CIFSSMBRmDir,
>  	.unlink = CIFSSMBDelFile,
>  	.rename_pending_delete = cifs_rename_pending_delete,
> +	.open = cifs_open_file,
> +	.set_fid = cifs_set_fid,
>  };
>  
>  struct smb_version_values smb1_values = {

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

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

* Re: [PATCH 08/45] CIFS: Move unlink code to ops struct
       [not found]             ` <20120912161038.4c32810a-4QP7MXygkU+dMjc06nkz3ljfA9RmPOcC@public.gmane.org>
@ 2012-09-13  6:04               ` Pavel Shilovsky
       [not found]                 ` <CAKywueTvDNzQQVG0TEvhu2CxEERQc9dxH-VuUwmgOf5d7eeniA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 74+ messages in thread
From: Pavel Shilovsky @ 2012-09-13  6:04 UTC (permalink / raw)
  To: Jeff Layton; +Cc: Jeff Layton, linux-cifs-u79uwXL29TY76Z2rM5mHXA

2012/9/13 Jeff Layton <jlayton-vpEMnDpepFuMZCB2o+C8xQ@public.gmane.org>:
> In fact, now that I look...
>
> The unlink(2) manpage lists EBUSY as a valid return code, but doesn't
> mention ETXTBSY. Perhaps we'd be better off turning that error into
> EBUSY instead of returning it as-is to userspace?

Looks reasonable - nfs code returns -EBUSY too.

> In any case, -ENOSYS just because you can't do a sillyrename seems
> clearly wrong. Better to return either -EBUSY or -ETXTBUSY there.

Ok, will repost this patch.

-- 
Best regards,
Pavel Shilovsky.

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

* [PATCH v2 9/45] CIFS: Move unlink code to ops struct
       [not found]                 ` <CAKywueTvDNzQQVG0TEvhu2CxEERQc9dxH-VuUwmgOf5d7eeniA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2012-09-13  6:12                   ` Pavel Shilovsky
       [not found]                     ` <1347516738-6861-1-git-send-email-pshilovsky-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
  0 siblings, 1 reply; 74+ messages in thread
From: Pavel Shilovsky @ 2012-09-13  6:12 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA; +Cc: Pavel Shilovsky

From: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>

Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
Signed-off-by: Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 fs/cifs/cifsglob.h  |    6 ++++++
 fs/cifs/cifsproto.h |    9 ++++++---
 fs/cifs/cifssmb.c   |   16 ++++++++--------
 fs/cifs/inode.c     |   33 ++++++++++++++++++++++-----------
 fs/cifs/smb1ops.c   |    2 ++
 5 files changed, 44 insertions(+), 22 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 977dc0e..843356f 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -256,6 +256,12 @@ struct smb_version_operations {
 	/* remove directory */
 	int (*rmdir)(const unsigned int, struct cifs_tcon *, const char *,
 		     struct cifs_sb_info *);
+	/* unlink file */
+	int (*unlink)(const unsigned int, struct cifs_tcon *, const char *,
+		      struct cifs_sb_info *);
+	/* open, rename and delete file */
+	int (*rename_pending_delete)(const char *, struct dentry *,
+				     const unsigned int);
 };
 
 struct smb_version_values {
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index f1bbf83..79c0884 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -144,6 +144,11 @@ extern int cifs_get_file_info_unix(struct file *filp);
 extern int cifs_get_inode_info_unix(struct inode **pinode,
 			const unsigned char *search_path,
 			struct super_block *sb, unsigned int xid);
+extern int cifs_set_file_info(struct inode *inode, struct iattr *attrs,
+			      unsigned int xid, char *full_path, __u32 dosattr);
+extern int cifs_rename_pending_delete(const char *full_path,
+				      struct dentry *dentry,
+				      const unsigned int xid);
 extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb,
 			      struct cifs_fattr *fattr, struct inode *inode,
 			      const char *path, const __u16 *pfid);
@@ -303,9 +308,7 @@ extern int CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
 			const struct nls_table *nls_codepage,
 			int remap_special_chars);
 extern int CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon,
-			const char *name,
-			const struct nls_table *nls_codepage,
-			int remap_special_chars);
+			  const char *name, struct cifs_sb_info *cifs_sb);
 extern int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
 			const char *fromName, const char *toName,
 			const struct nls_table *nls_codepage,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index f0cf934..2dddf01 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -902,15 +902,15 @@ PsxDelete:
 }
 
 int
-CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon,
-	       const char *fileName, const struct nls_table *nls_codepage,
-	       int remap)
+CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
+	       struct cifs_sb_info *cifs_sb)
 {
 	DELETE_FILE_REQ *pSMB = NULL;
 	DELETE_FILE_RSP *pSMBr = NULL;
 	int rc = 0;
 	int bytes_returned;
 	int name_len;
+	int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
 
 DelFileRetry:
 	rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
@@ -919,15 +919,15 @@ DelFileRetry:
 		return rc;
 
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
-		name_len =
-		    cifsConvertToUTF16((__le16 *) pSMB->fileName, fileName,
-				       PATH_MAX, nls_codepage, remap);
+		name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
+					      PATH_MAX, cifs_sb->local_nls,
+					      remap);
 		name_len++;	/* trailing null */
 		name_len *= 2;
 	} else {		/* BB improve check for buffer overruns BB */
-		name_len = strnlen(fileName, PATH_MAX);
+		name_len = strnlen(name, PATH_MAX);
 		name_len++;	/* trailing null */
-		strncpy(pSMB->fileName, fileName, name_len);
+		strncpy(pSMB->fileName, name, name_len);
 	}
 	pSMB->SearchAttributes =
 	    cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index cb79c7e..bb39ea4 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -876,9 +876,9 @@ out:
 	return inode;
 }
 
-static int
+int
 cifs_set_file_info(struct inode *inode, struct iattr *attrs, unsigned int xid,
-		    char *full_path, __u32 dosattr)
+		   char *full_path, __u32 dosattr)
 {
 	int rc;
 	int oplock = 0;
@@ -993,13 +993,13 @@ out:
 }
 
 /*
- * open the given file (if it isn't already), set the DELETE_ON_CLOSE bit
+ * Open the given file (if it isn't already), set the DELETE_ON_CLOSE bit
  * and rename it to a random name that hopefully won't conflict with
  * anything else.
  */
-static int
-cifs_rename_pending_delete(char *full_path, struct dentry *dentry,
-			   unsigned int xid)
+int
+cifs_rename_pending_delete(const char *full_path, struct dentry *dentry,
+			   const unsigned int xid)
 {
 	int oplock = 0;
 	int rc;
@@ -1136,6 +1136,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
 	struct tcon_link *tlink;
 	struct cifs_tcon *tcon;
+	struct TCP_Server_Info *server;
 	struct iattr *attrs = NULL;
 	__u32 dosattr = 0, origattr = 0;
 
@@ -1145,6 +1146,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
 	if (IS_ERR(tlink))
 		return PTR_ERR(tlink);
 	tcon = tlink_tcon(tlink);
+	server = tcon->ses->server;
 
 	xid = get_xid();
 
@@ -1167,8 +1169,12 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
 	}
 
 retry_std_delete:
-	rc = CIFSSMBDelFile(xid, tcon, full_path, cifs_sb->local_nls,
-			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+	if (!server->ops->unlink) {
+		rc = -ENOSYS;
+		goto psx_del_no_retry;
+	}
+
+	rc = server->ops->unlink(xid, tcon, full_path, cifs_sb);
 
 psx_del_no_retry:
 	if (!rc) {
@@ -1177,9 +1183,14 @@ psx_del_no_retry:
 	} else if (rc == -ENOENT) {
 		d_drop(dentry);
 	} else if (rc == -ETXTBSY) {
-		rc = cifs_rename_pending_delete(full_path, dentry, xid);
-		if (rc == 0)
-			cifs_drop_nlink(inode);
+		if (server->ops->rename_pending_delete) {
+			rc = server->ops->rename_pending_delete(full_path,
+								dentry, xid);
+			if (rc == 0)
+				cifs_drop_nlink(inode);
+		}
+		if (rc == -ETXTBSY)
+			rc = -EBUSY;
 	} else if ((rc == -EACCES) && (dosattr == 0) && inode) {
 		attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
 		if (attrs == NULL) {
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 3129ac7..725fa61 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -644,6 +644,8 @@ struct smb_version_operations smb1_operations = {
 	.mkdir = CIFSSMBMkDir,
 	.mkdir_setinfo = cifs_mkdir_setinfo,
 	.rmdir = CIFSSMBRmDir,
+	.unlink = CIFSSMBDelFile,
+	.rename_pending_delete = cifs_rename_pending_delete,
 };
 
 struct smb_version_values smb1_values = {
-- 
1.7.1

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

* Re: [PATCH v2 9/45] CIFS: Move unlink code to ops struct
       [not found]                     ` <1347516738-6861-1-git-send-email-pshilovsky-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
@ 2012-09-13 12:07                       ` Jeff Layton
  0 siblings, 0 replies; 74+ messages in thread
From: Jeff Layton @ 2012-09-13 12:07 UTC (permalink / raw)
  To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA, Pavel Shilovsky

On Thu, 13 Sep 2012 10:12:18 +0400
Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:

> From: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
> 
> Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
> Signed-off-by: Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> ---
>  fs/cifs/cifsglob.h  |    6 ++++++
>  fs/cifs/cifsproto.h |    9 ++++++---
>  fs/cifs/cifssmb.c   |   16 ++++++++--------
>  fs/cifs/inode.c     |   33 ++++++++++++++++++++++-----------
>  fs/cifs/smb1ops.c   |    2 ++
>  5 files changed, 44 insertions(+), 22 deletions(-)
> 
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index 977dc0e..843356f 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -256,6 +256,12 @@ struct smb_version_operations {
>  	/* remove directory */
>  	int (*rmdir)(const unsigned int, struct cifs_tcon *, const char *,
>  		     struct cifs_sb_info *);
> +	/* unlink file */
> +	int (*unlink)(const unsigned int, struct cifs_tcon *, const char *,
> +		      struct cifs_sb_info *);
> +	/* open, rename and delete file */
> +	int (*rename_pending_delete)(const char *, struct dentry *,
> +				     const unsigned int);
>  };
>  
>  struct smb_version_values {
> diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
> index f1bbf83..79c0884 100644
> --- a/fs/cifs/cifsproto.h
> +++ b/fs/cifs/cifsproto.h
> @@ -144,6 +144,11 @@ extern int cifs_get_file_info_unix(struct file *filp);
>  extern int cifs_get_inode_info_unix(struct inode **pinode,
>  			const unsigned char *search_path,
>  			struct super_block *sb, unsigned int xid);
> +extern int cifs_set_file_info(struct inode *inode, struct iattr *attrs,
> +			      unsigned int xid, char *full_path, __u32 dosattr);
> +extern int cifs_rename_pending_delete(const char *full_path,
> +				      struct dentry *dentry,
> +				      const unsigned int xid);
>  extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb,
>  			      struct cifs_fattr *fattr, struct inode *inode,
>  			      const char *path, const __u16 *pfid);
> @@ -303,9 +308,7 @@ extern int CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
>  			const struct nls_table *nls_codepage,
>  			int remap_special_chars);
>  extern int CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon,
> -			const char *name,
> -			const struct nls_table *nls_codepage,
> -			int remap_special_chars);
> +			  const char *name, struct cifs_sb_info *cifs_sb);
>  extern int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
>  			const char *fromName, const char *toName,
>  			const struct nls_table *nls_codepage,
> diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
> index f0cf934..2dddf01 100644
> --- a/fs/cifs/cifssmb.c
> +++ b/fs/cifs/cifssmb.c
> @@ -902,15 +902,15 @@ PsxDelete:
>  }
>  
>  int
> -CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon,
> -	       const char *fileName, const struct nls_table *nls_codepage,
> -	       int remap)
> +CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
> +	       struct cifs_sb_info *cifs_sb)
>  {
>  	DELETE_FILE_REQ *pSMB = NULL;
>  	DELETE_FILE_RSP *pSMBr = NULL;
>  	int rc = 0;
>  	int bytes_returned;
>  	int name_len;
> +	int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
>  
>  DelFileRetry:
>  	rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
> @@ -919,15 +919,15 @@ DelFileRetry:
>  		return rc;
>  
>  	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
> -		name_len =
> -		    cifsConvertToUTF16((__le16 *) pSMB->fileName, fileName,
> -				       PATH_MAX, nls_codepage, remap);
> +		name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
> +					      PATH_MAX, cifs_sb->local_nls,
> +					      remap);
>  		name_len++;	/* trailing null */
>  		name_len *= 2;
>  	} else {		/* BB improve check for buffer overruns BB */
> -		name_len = strnlen(fileName, PATH_MAX);
> +		name_len = strnlen(name, PATH_MAX);
>  		name_len++;	/* trailing null */
> -		strncpy(pSMB->fileName, fileName, name_len);
> +		strncpy(pSMB->fileName, name, name_len);
>  	}
>  	pSMB->SearchAttributes =
>  	    cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
> diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
> index cb79c7e..bb39ea4 100644
> --- a/fs/cifs/inode.c
> +++ b/fs/cifs/inode.c
> @@ -876,9 +876,9 @@ out:
>  	return inode;
>  }
>  
> -static int
> +int
>  cifs_set_file_info(struct inode *inode, struct iattr *attrs, unsigned int xid,
> -		    char *full_path, __u32 dosattr)
> +		   char *full_path, __u32 dosattr)
>  {
>  	int rc;
>  	int oplock = 0;
> @@ -993,13 +993,13 @@ out:
>  }
>  
>  /*
> - * open the given file (if it isn't already), set the DELETE_ON_CLOSE bit
> + * Open the given file (if it isn't already), set the DELETE_ON_CLOSE bit
>   * and rename it to a random name that hopefully won't conflict with
>   * anything else.
>   */
> -static int
> -cifs_rename_pending_delete(char *full_path, struct dentry *dentry,
> -			   unsigned int xid)
> +int
> +cifs_rename_pending_delete(const char *full_path, struct dentry *dentry,
> +			   const unsigned int xid)
>  {
>  	int oplock = 0;
>  	int rc;
> @@ -1136,6 +1136,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
>  	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
>  	struct tcon_link *tlink;
>  	struct cifs_tcon *tcon;
> +	struct TCP_Server_Info *server;
>  	struct iattr *attrs = NULL;
>  	__u32 dosattr = 0, origattr = 0;
>  
> @@ -1145,6 +1146,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
>  	if (IS_ERR(tlink))
>  		return PTR_ERR(tlink);
>  	tcon = tlink_tcon(tlink);
> +	server = tcon->ses->server;
>  
>  	xid = get_xid();
>  
> @@ -1167,8 +1169,12 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
>  	}
>  
>  retry_std_delete:
> -	rc = CIFSSMBDelFile(xid, tcon, full_path, cifs_sb->local_nls,
> -			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
> +	if (!server->ops->unlink) {
> +		rc = -ENOSYS;
> +		goto psx_del_no_retry;
> +	}
> +
> +	rc = server->ops->unlink(xid, tcon, full_path, cifs_sb);
>  
>  psx_del_no_retry:
>  	if (!rc) {
> @@ -1177,9 +1183,14 @@ psx_del_no_retry:
>  	} else if (rc == -ENOENT) {
>  		d_drop(dentry);
>  	} else if (rc == -ETXTBSY) {
> -		rc = cifs_rename_pending_delete(full_path, dentry, xid);
> -		if (rc == 0)
> -			cifs_drop_nlink(inode);
> +		if (server->ops->rename_pending_delete) {
> +			rc = server->ops->rename_pending_delete(full_path,
> +								dentry, xid);
> +			if (rc == 0)
> +				cifs_drop_nlink(inode);
> +		}
> +		if (rc == -ETXTBSY)
> +			rc = -EBUSY;
>  	} else if ((rc == -EACCES) && (dosattr == 0) && inode) {
>  		attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
>  		if (attrs == NULL) {
> diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
> index 3129ac7..725fa61 100644
> --- a/fs/cifs/smb1ops.c
> +++ b/fs/cifs/smb1ops.c
> @@ -644,6 +644,8 @@ struct smb_version_operations smb1_operations = {
>  	.mkdir = CIFSSMBMkDir,
>  	.mkdir_setinfo = cifs_mkdir_setinfo,
>  	.rmdir = CIFSSMBRmDir,
> +	.unlink = CIFSSMBDelFile,
> +	.rename_pending_delete = cifs_rename_pending_delete,
>  };
>  
>  struct smb_version_values smb1_values = {

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

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

* Re: [PATCH 12/45] CIFS: Move close code to ops struct
       [not found]     ` <1342626541-29872-13-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
@ 2012-09-13 15:45       ` Jeff Layton
  0 siblings, 0 replies; 74+ messages in thread
From: Jeff Layton @ 2012-09-13 15:45 UTC (permalink / raw)
  To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA

On Wed, 18 Jul 2012 19:48:28 +0400
Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:

> Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
> ---
>  fs/cifs/cifsglob.h |    2 ++
>  fs/cifs/file.c     |   10 +++++++---
>  fs/cifs/smb1ops.c  |    8 ++++++++
>  3 files changed, 17 insertions(+), 3 deletions(-)
> 
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index c4375d8..b3cbce6 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -269,6 +269,8 @@ struct smb_version_operations {
>  		    struct cifs_sb_info *);
>  	/* set fid protocol-specific info */
>  	void (*set_fid)(struct cifsFileInfo *, struct cifs_fid *, __u32);
> +	/* close a file */
> +	int (*close)(const unsigned int, struct cifs_tcon *, struct cifs_fid *);
>  };
>  

nit: maybe ->close and CIFSSMBClose should be a void return? Nothing
actually pays attention to the return code for CIFSSMBClose

>  struct smb_version_values {
> diff --git a/fs/cifs/file.c b/fs/cifs/file.c
> index 3f4b4ba..b18b36a 100644
> --- a/fs/cifs/file.c
> +++ b/fs/cifs/file.c
> @@ -317,10 +317,13 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
>  	cancel_work_sync(&cifs_file->oplock_break);
>  
>  	if (!tcon->need_reconnect && !cifs_file->invalidHandle) {
> +		struct TCP_Server_Info *server = tcon->ses->server;
>  		unsigned int xid;
> -		int rc;
> +		int rc = -ENOSYS;
> +

No need to initialize this at all. In fact, probably best to convert
CIFSSMBClose to void return and get rid of that variable.

>  		xid = get_xid();
> -		rc = CIFSSMBClose(xid, tcon, cifs_file->fid.netfid);
> +		if (server->ops->close)
> +			rc = server->ops->close(xid, tcon, &cifs_file->fid);
>  		free_xid(xid);
>  	}
>  
> @@ -414,7 +417,8 @@ int cifs_open(struct inode *inode, struct file *file)
>  
>  	cfile = cifs_new_fileinfo(&fid, file, tlink, oplock);
>  	if (cfile == NULL) {
> -		CIFSSMBClose(xid, tcon, fid.netfid);
> +		if (tcon->ses->server->ops->close)
> +			tcon->ses->server->ops->close(xid, tcon, &fid);
>  		rc = -ENOMEM;
>  		goto out;
>  	}
> diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
> index 907b308..bb75847 100644
> --- a/fs/cifs/smb1ops.c
> +++ b/fs/cifs/smb1ops.c
> @@ -634,6 +634,13 @@ cifs_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock)
>  	cinode->can_cache_brlcks = cinode->clientCanCacheAll;
>  }
>  
> +static int
> +cifs_close_file(const unsigned int xid, struct cifs_tcon *tcon,
> +		struct cifs_fid *fid)
> +{
> +	return CIFSSMBClose(xid, tcon, fid->netfid);
> +}
> +
>  struct smb_version_operations smb1_operations = {
>  	.send_cancel = send_nt_cancel,
>  	.compare_fids = cifs_compare_fids,
> @@ -675,6 +682,7 @@ struct smb_version_operations smb1_operations = {
>  	.rename_pending_delete = cifs_rename_pending_delete,
>  	.open = cifs_open_file,
>  	.set_fid = cifs_set_fid,
> +	.close = cifs_close_file,
>  };
>  
>  struct smb_version_values smb1_values = {

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

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

* Re: [PATCH 30/45] CIFS: Enable signing in SMB2
       [not found]               ` <5034E29E.7030006-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
@ 2013-07-08  6:15                 ` Shirish Pargaonkar
  0 siblings, 0 replies; 74+ messages in thread
From: Shirish Pargaonkar @ 2013-07-08  6:15 UTC (permalink / raw)
  To: linux-cifs

Any pointers would be really helpful and appreciated...

I am trying to make signing work correctly for smb2
with key exchange key and ntlmv2/ntlmssp with signing.

So as I see, for the first smb session on a tcp session, everything
works fine i.e. session setup and tree connect works.
But for the the second smb session on this tcp session, session setup
succeeds but tree connect fails i.e. signature is incorrect.

If the same second smb session happens to be the first smb session
on a tcp session session setup and tree connect succeeds i.e. signature
is correct but if the first smb session on this tcp session happens to be
the second smb session on this tcp session, session setup succeeds
but tree connect fails i.e. signature is incorrect.

Signature generating algorithm as in ms-smb2 3.1.4.1 is the same
all the time.
It is the session.sessionkey varies.

As I see from ms-nlmp, nonce is the session.session key (exportedsessionkey)
as in 3.1.5.1.2.  Since authentication always succeeds for these
ntlmv2 ntlmssp, encryptedrandomsessionkey must have been correct which means
keyexchangekey must be correct.
So not sure why for the second smb session on this tcp session,
session.sessionkey generates incorrect signature.


So in this case, my question is, if authentication/session_setup for
the second smb session succeeds, how can signing/tree_connect fail?

Regards,

Shirish

On Wed, Aug 22, 2012 at 8:46 AM, Stefan (metze) Metzmacher
<metze-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:
> Hi Shirish,
>
>> On Tue, Aug 21, 2012 at 2:35 AM, Stefan Metzmacher <metze-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:
>>> Hi Pavel,
>>>
>>>> Use hmac-sha256 and rather than hmac-md5 that is used for CIFS/SMB.
>>>>
>>>> Signature field in SMB2 header is 16 bytes instead of 8 bytes.
>>>
>>> Sorry for the late reply, I just found a reference to this patch...
>>>
>>> To me it seems that this patch doesn't take care of the fact that
>>> the signing key in SMB2/3 belongs to the session and not to the transport
>>> connection.
>>
>> metze, where do you see that?  This is the signing key that is used to generate
>> signature, server->session_key.response.
>
> And 'server' is a per connection state not per session...
> which is ok for smb1 but not for smb2.
>
>>> Does the SMB2 code support multiuser mounts yet?
>>>
>>> Why are you using some "BSRSPYL " magic? I only saw that from Windows
>>> clients
>>> using SMB1. (Note: that servers just echo the signature from the
>>> request, if they don't do signing).
>>
>> IIRC, Jeff Layton added that code to encode BSRSPYL magic (string).
>> I could be wrong, it has been a while.
>> But, I do think this is a problem, signature in a smb message is not even
>> checked till key exchange handshake is session setup is done, right?
>
> A session setup response with STATUS_SUCCESS is the first signed message.
> Before that the server just echos what the client sends.
>
> For SMB1 windows client (and smbclient) send BSRSPYL if they would like to
> turn on signing later. But for SMB2 windows and samba send just zeros,
> which cifs.ko should also do.
>
> metze
>

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

end of thread, other threads:[~2013-07-08  6:15 UTC | newest]

Thread overview: 74+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-07-18 15:48 [PATCH 00/45] SMB2 base operation support Pavel Shilovsky
     [not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2012-07-18 15:48   ` [PATCH 01/45] CIFS: Make CAP_* checks protocol independent Pavel Shilovsky
     [not found]     ` <1342626541-29872-2-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2012-07-23 13:55       ` Jeff Layton
     [not found]         ` <CAKywueTxSBkBfp4wZW8Hy71F3dZ1gsthuHcLVO28--a4oEAMjw@mail.gmail.com>
     [not found]           ` <CAKywueTxSBkBfp4wZW8Hy71F3dZ1gsthuHcLVO28--a4oEAMjw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-07-24  6:37             ` Pavel Shilovsky
2012-07-23 20:59       ` Jeff Layton
     [not found]         ` <20120723165947.5fad3d87-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
2012-07-23 21:14           ` Steve French
2012-07-24  6:38           ` Pavel Shilovsky
2012-07-24  7:21       ` [PATCH v2 1/45] " Pavel Shilovsky
     [not found]         ` <1343114502-7908-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2012-07-24 17:44           ` Jeff Layton
2012-07-18 15:48   ` [PATCH 02/45] CIFS: Simpliify cifs_mkdir call Pavel Shilovsky
     [not found]     ` <1342626541-29872-3-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2012-08-01 19:39       ` Jeff Layton
2012-07-18 15:48   ` [PATCH 03/45] CIFS: Separate protocol specific part from mkdir Pavel Shilovsky
     [not found]     ` <1342626541-29872-4-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2012-08-01 19:41       ` Jeff Layton
2012-07-18 15:48   ` [PATCH 04/45] CIFS: Add SMB2 support for mkdir operation Pavel Shilovsky
     [not found]     ` <1342626541-29872-5-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2012-08-01 19:42       ` Jeff Layton
2012-07-18 15:48   ` [PATCH 05/45] CIFS: Move rmdir code to ops struct Pavel Shilovsky
     [not found]     ` <1342626541-29872-6-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2012-08-01 19:45       ` Jeff Layton
2012-07-18 15:48   ` [PATCH 06/45] CIFS: Add SMB2 support for rmdir Pavel Shilovsky
     [not found]     ` <1342626541-29872-7-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2012-08-01 19:47       ` Jeff Layton
2012-07-18 15:48   ` [PATCH 07/45] CIFS: Protect i_nlink from being negative Pavel Shilovsky
     [not found]     ` <1342626541-29872-8-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2012-07-28 11:48       ` Jeff Layton
2012-07-18 15:48   ` [PATCH 08/45] CIFS: Move unlink code to ops struct Pavel Shilovsky
     [not found]     ` <1342626541-29872-9-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2012-09-12 19:48       ` Jeff Layton
     [not found]         ` <20120912154804.19b97830-4QP7MXygkU+dMjc06nkz3ljfA9RmPOcC@public.gmane.org>
2012-09-12 20:10           ` Jeff Layton
     [not found]             ` <20120912161038.4c32810a-4QP7MXygkU+dMjc06nkz3ljfA9RmPOcC@public.gmane.org>
2012-09-13  6:04               ` Pavel Shilovsky
     [not found]                 ` <CAKywueTvDNzQQVG0TEvhu2CxEERQc9dxH-VuUwmgOf5d7eeniA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-09-13  6:12                   ` [PATCH v2 9/45] " Pavel Shilovsky
     [not found]                     ` <1347516738-6861-1-git-send-email-pshilovsky-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-09-13 12:07                       ` Jeff Layton
2012-07-18 15:48   ` [PATCH 09/45] CIFS: Add SMB2 support for unlink Pavel Shilovsky
     [not found]     ` <1342626541-29872-10-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2012-09-12 19:51       ` Jeff Layton
2012-07-18 15:48   ` [PATCH 10/45] CIFS: Replace netfid with cifs_fid struct in cifsFileInfo Pavel Shilovsky
     [not found]     ` <1342626541-29872-11-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2012-09-12 19:55       ` Jeff Layton
2012-07-18 15:48   ` [PATCH 11/45] CIFS: Move open code to ops struct Pavel Shilovsky
     [not found]     ` <1342626541-29872-12-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2012-09-12 20:12       ` Jeff Layton
2012-07-18 15:48   ` [PATCH 12/45] CIFS: Move close " Pavel Shilovsky
     [not found]     ` <1342626541-29872-13-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2012-09-13 15:45       ` Jeff Layton
2012-07-18 15:48   ` [PATCH 13/45] CIFS: Add open/close file support for SMB2 Pavel Shilovsky
2012-07-18 15:48   ` [PATCH 14/45] CIFS: Move guery file info code to ops struct Pavel Shilovsky
2012-07-18 15:48   ` [PATCH 15/45] CIFS: Add SMB2 support for query_file_info Pavel Shilovsky
2012-07-18 15:48   ` [PATCH 16/45] CIFS: Move create code use ops struct Pavel Shilovsky
2012-07-18 15:48   ` [PATCH 17/45] CIFS: Move reopen code to " Pavel Shilovsky
2012-07-18 15:48   ` [PATCH 18/45] CIFS: Make flush code use " Pavel Shilovsky
2012-07-18 15:48   ` [PATCH 19/45] CIFS: Add SMB2 support for flush Pavel Shilovsky
2012-07-18 15:48   ` [PATCH 20/45] CIFS: Move r/wsize negotiating to ops struct Pavel Shilovsky
2012-07-18 15:48   ` [PATCH 21/45] CIFS: Add SMB2 r/wsize negotiating Pavel Shilovsky
2012-07-18 15:48   ` [PATCH 22/45] CIFS: Move async read to ops struct Pavel Shilovsky
2012-07-18 15:48   ` [PATCH 23/45] CIFS: Add SMB2 support for cifs_iovec_read Pavel Shilovsky
2012-07-18 15:48   ` [PATCH 24/45] CIFS: Move async write to ops struct Pavel Shilovsky
2012-07-18 15:48   ` [PATCH 25/45] CIFS: Add SMB2 support for cifs_iovec_write Pavel Shilovsky
2012-07-18 15:48   ` [PATCH 26/45] CIFS: Move readpage code to ops struct Pavel Shilovsky
2012-07-18 15:48   ` [PATCH 27/45] CIFS: Add readpage support for SMB2 Pavel Shilovsky
2012-07-18 15:48   ` [PATCH 28/45] CIFS: Move writepage to ops struct Pavel Shilovsky
2012-07-18 15:48   ` [PATCH 29/45] CIFS: Add writepage support for SMB2 Pavel Shilovsky
2012-07-18 15:48   ` [PATCH 30/45] CIFS: Enable signing in SMB2 Pavel Shilovsky
     [not found]     ` <1342626541-29872-31-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2012-08-21  7:35       ` Stefan Metzmacher
2012-08-21 14:01         ` Pavel Shilovsky
2012-08-21 14:58         ` Shirish Pargaonkar
     [not found]           ` <CADT32e+4DSN=CSCbL+8GoRePknpD3X0HSq1hjVsXf3KHXQcmTw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-08-22 13:46             ` Stefan (metze) Metzmacher
     [not found]               ` <5034E29E.7030006-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2013-07-08  6:15                 ` Shirish Pargaonkar
2012-07-18 15:48   ` [PATCH 31/45] CIFS: Move rename to ops struct Pavel Shilovsky
2012-07-18 15:48   ` [PATCH 32/45] CIFS: Add SMB2 support for rename operation Pavel Shilovsky
2012-07-18 15:48   ` [PATCH 33/45] CIFS: Move hardlink to ops struct Pavel Shilovsky
2012-07-18 15:48   ` [PATCH 34/45] CIFS: Add SMB2 support for hardlink operation Pavel Shilovsky
2012-07-18 15:48   ` [PATCH 35/45] CIFS: Move set_file_size to ops struct Pavel Shilovsky
2012-07-18 15:48   ` [PATCH 36/45] CIFS: Add SMB2 support for set_file_size Pavel Shilovsky
2012-07-18 15:48   ` [PATCH 37/45] CIFS: Move set_file_info to ops struct Pavel Shilovsky
2012-07-18 15:48   ` [PATCH 38/45] CIFS: Add set_file_info support for SMB2 Pavel Shilovsky
2012-07-18 15:48   ` [PATCH 39/45] CIFS: Move readdir code to ops struct Pavel Shilovsky
2012-07-18 15:48   ` [PATCH 40/45] CIFS: Add readdir support for SMB2 Pavel Shilovsky
2012-07-18 15:48   ` [PATCH 41/45] CIFS: Process oplocks " Pavel Shilovsky
2012-07-18 15:48   ` [PATCH 42/45] CIFS: Move oplock break to ops struct Pavel Shilovsky
2012-07-18 15:48   ` [PATCH 43/45] CIFS: Add oplock break support for SMB2 Pavel Shilovsky
2012-07-18 15:49   ` [PATCH 44/45] CIFS: Move statfs to ops struct Pavel Shilovsky
2012-07-18 15:49   ` [PATCH 45/45] CIFS: Add statfs support for SMB2 Pavel Shilovsky
2012-08-03 15:14   ` [PATCH 00/45] SMB2 base operation support Steve French

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.